Loading workspace insights... Statistics interval
7 days30 daysLatest CI Pipeline Executions
3e2929ec Added gift dimension to the web analytics tracker on gift reads (#28853)
ref
https://linear.app/ghost/issue/BER-3746/integrate-gift-link-usage-tracking-with-analytics
Stacked on #28824 (the `?gift=` reader path). **Producer** slice of
moving gift-link usage tracking off the DB counter and onto the existing
web-analytics pipeline (Tinybird), so gift numbers are measured the same
way as every other page view.
### What this does
Attaches a single new dimension — `gift_link` (the gift-link token) — to
the `page_hit` payload on a verified gift read, so downstream analytics
can:
- segment "gift traffic" in the normal reports, and
- count usage per individual link.
### How
- The reader path (`entry/gift-links.ts`, `setGiftTemplateFlag`) flags a
verified gift render with a single internal `_giftLink` token — the
token itself, not a boolean — set on `res.locals` so it merges onto the
render context root. One flag, not two: it also drives the reader toast.
- This renames the internal flag (`_gift` → `_giftLink`, to match the
`gift_link` dimension) and moves it off the `@data` frame onto
`res.locals`, so both consumers read it from the render root like
`post_uuid`/`member`. Touches `ghost_foot` and the reader’s `gift-links`
controller as well as `ghost_head`.
- `ghost_head`'s tracker reads it as `dataRoot._giftLink` and emits
`tb_gift_link`, via the existing `ghost_head` → `ghost-stats` courier
path that already carries `post_uuid`, `member_status`, etc.
`ghost_foot` reads the same root flag for the toast.
- Always emitted, but **empty** (`tb_gift_link=""`) on a normal read;
only a verified gift render carries the token. The empty-vs-token
distinction (not an `"undefined"` sentinel) is what lets the downstream
`gift_link != ''` filter decide what counts as gift traffic.
Gated on `labs.giftLinks`.
### This PR is producer-only
The two consumers are separate PRs so each can be reviewed
independently:
- **Proxy** (TryGhost/TrafficAnalytics) — thread `gift_link` through the
page-hit transforms, else it's dropped before Tinybird.
- **Data files** (Tinybird datafiles in this repo) — `_mv_hits` column,
`gift_link` segment param, and a per-link endpoint.
Until the proxy lands, `gift_link` is sent but dropped — no behaviour
change.
### Out of scope
The pre-existing `?gift=` token leak into `ghost-stats`' `location.href`
(noted in #28824) is unchanged here. The token is sent deliberately as
`gift_link` regardless; the `href` field is inert in reports.
### Test
- `ghost-head.test.js` (unit): `tb_gift_link` carries the token when
`_giftLink` is set, empty otherwise.
- `e2e-frontend/gift-links.test.ts` (integration): drives the real
reader path with web analytics enabled and asserts the rendered tracker
— a verified token reaches `tb_gift_link`, while a forged token, a token
for another post, and a normal read all render an empty `tb_gift_link`.
Proves an unverified token never enters analytics.