Repository navigation
Conversation
…eline trigger The message history trigger writes one email.link_clicked entry each time a link of clicked_links is first clicked through a token signed by the workspace. Migration v44 installs the new body on existing workspaces; v42 keeps a frozen copy of the body it shipped. Opens and clicks are no longer recorded on messages whose contact was erased.
…sage filter An email.link_clicked trigger can filter on the clicked URL (substring), broadcast and template, read from the timeline entry, and never restarts on a click on an email the automation sent. messages.list takes clicked_url, scoped to a broadcast, to list who clicked a link. The monthly event meter leaves email.link_clicked out.
…ilter against PostgreSQL
…ine, and who clicked each link The trigger form picks email.link_clicked with optional link, broadcast and template filters. The contact timeline shows each link clicked. The broadcast per-link stats open the message log on the emails where that link was clicked, through a clicked_url filter that only exists within a broadcast filter.
…ct what link click comments, docs and tests claim messages.list with clicked_url now uses the jsonb ? operator: PostgreSQL has no estimate for clicked_links -> key IS NOT NULL and walked the created_at index over the whole table for a little-clicked link. The billable index guard EXPLAINs the meter query as it now is, a link clicked before 44 is documented and tested, and the erasure and no-URL subtests go through the real paths.
…tion # Conflicts: # CHANGELOG.md # config/config.go # console/src/i18n/locales/ca.po # console/src/i18n/locales/de.po # console/src/i18n/locales/en.po # console/src/i18n/locales/es.po # console/src/i18n/locales/fr.po # console/src/i18n/locales/it.po # console/src/i18n/locales/ja.po # console/src/i18n/locales/pt-BR.po # web_analytics_sdk/dist/notifuse-analytics.cjs.js # web_analytics_sdk/dist/notifuse-analytics.esm.js # web_analytics_sdk/dist/notifuse-analytics.min.js # web_analytics_sdk/package.json
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## dev #507 +/- ##
==========================================
+ Coverage 88.82% 88.84% +0.02%
==========================================
Files 368 369 +1
Lines 71862 71943 +81
==========================================
+ Hits 63828 63915 +87
+ Misses 5395 5390 -5
+ Partials 2639 2638 -1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…tion # Conflicts: # CHANGELOG.md # config/config.go # web_analytics_sdk/dist/notifuse-analytics.cjs.js # web_analytics_sdk/dist/notifuse-analytics.esm.js # web_analytics_sdk/dist/notifuse-analytics.min.js # web_analytics_sdk/package.json
…tion # Conflicts: # console/src/i18n/locales/ca.po # console/src/i18n/locales/de.po # console/src/i18n/locales/en.po # console/src/i18n/locales/es.po # console/src/i18n/locales/fr.po # console/src/i18n/locales/it.po # console/src/i18n/locales/ja.po # console/src/i18n/locales/pt-BR.po
…tion # Conflicts: # console/src/i18n/locales/ca.po # console/src/i18n/locales/de.po # console/src/i18n/locales/en.po # console/src/i18n/locales/es.po # console/src/i18n/locales/fr.po # console/src/i18n/locales/it.po # console/src/i18n/locales/ja.po # console/src/i18n/locales/pt-BR.po
pierre-b
marked this pull request as ready for review
November 10, 2026 23:06
…e proxy The click routes now judge a link back to the instance against the request's Host and every X-Forwarded-Host entry, so behind a proxy that forwards its upstream name as Host the unsubscribe, notification center and web version links are no longer recorded per link, and no longer start link-click automations.
…nk exclusion Everything merged since 43.0 ships as 44.0. The changelog line now says the instance's own links are left out only when the proxy passes X-Forwarded-Host, and that keys recorded earlier stay.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #498.
What it does
email.link_clicked). It starts the first time a contact clicks each link of an email. Optional filters: the link contains some text (case-insensitive), one broadcast, one template. A click on an email that the automation sent itself never starts it again, soevery_timecannot loop on its own emails.clicked_url(only allowed together withbroadcast_id), whichmessages.listalso accepts.DELETED_EMAIL) are no longer recorded. The link still redirects.How
track_message_history_changes()writes oneemail.link_clickedtimeline entry for eachclicked_linkskey that becomesverified.SetClickedsetsverified: trueonly for clicks through a signed tracking token, so a forged URL starts nothing.email.link_clicked, which details a click that is already counted.clicked_urlfilter uses the jsonb?operator behind an object guard. PostgreSQL has no row estimate for-> key IS NOT NULLand assumes almost every row matches, so for a little-clicked link it scanned the whole table through thecreated_atindex (measured on 1M rows: 99 ms down to 11 ms).Plan:
plans/feat-link-click-automation-plan.md. Docs: Notifuse/docs#29.Tests
./internal/... ./pkg/...green with-race.timeline_link_clicked_test.goandautomation_link_click_trigger_test.godrive the real/r/route with signed and unsigned tokens against PostgreSQL. They cover a link clicked second, the 50-link cap, malformedclicked_links, the real erasure path, a link clicked before 44, the v44 upgrade, the meter, the round trip from per-link stats to the log, and the loop guard.Known, not handled
email.link_clickedwebhook.Host, links to the instance itself (unsubscribe, notification center, "View in browser") are not recognised as such: they are recorded per link, as they already were in per-link stats, and so start an automation with no link filter. The click route doesn't readX-Forwarded-Host, unlike Add a "View in browser" link to broadcast and automation emails #502's/v/route.kindfrom the table for each row of the month: the partial index no longer answers alone (it runs once a day per workspace).messages.listwithclicked_urlis planned like the list's other filters, which can walk thecreated_atindex. This predates the change.TriggerFormConfiginNodeConfigPanel.tsxdoesn't list the three new fields (a type mirror only, no runtime effect).broadcast_idandtemplate_idtrigger filters have no length cap of their own.AutomationCard.tsxhas no test file.npm run lint(--max-warnings 0) already reports 12 warnings on dev in files this PR doesn't touch; CI'snpx eslint .passes.features/automations.mdxlistsemail.sentandemail.deliveredas triggers althoughValidEventKindsexcludes them (also on dev).