Capture ad click IDs so paid traffic is attributable - #8207
Open
gregory-boch-prisma wants to merge 2 commits into
Open
Capture ad click IDs so paid traffic is attributable#8207gregory-boch-prisma wants to merge 2 commits into
gregory-boch-prisma wants to merge 2 commits into
Conversation
Google auto-tagging appends `gclid` and no UTM params at all, but `isAttributionKey` matched only `utm_*` and `ref`. Every paid visit was therefore stored as if it were direct traffic, and `gclid` appeared nowhere in the codebase — so the existing first/last-touch attribution, including the part that forwards it to console.prisma.io, could not see paid acquisition at all. Capture gclid, wbraid, gbraid, msclkid, fbclid, li_fat_id, twclid and ttclid into the existing attribution store. Click IDs are deliberately not rewritten onto internal links — they are opaque and long, and only matter at the console boundary, where syncUtmAttribution now appends them alongside first-touch params. Record paid touches on the PostHog person rather than on a conversion event. A purchase can happen months after the click, far outside any ad platform's window (Google caps offline conversion import at 90 days), so attribution has to live somewhere durable. `first_paid_*` is written with $set_once and never overwritten; organic visitors get no paid properties at all. UtmPersistence emits a `prisma_attribution_change` DOM event rather than calling PostHog directly, so @prisma-docs/ui needs no posthog-js dependency; each app wires it to its own already-initialised client. Coverage is bounded by consent: PostHog here is opt-out by default and only opts in on CookieYes analytics consent, so a visitor who declines produces no data and cannot be attributed. Note also that setPersonProperties creates a person profile under `identified_only`, so paid-touched anonymous visitors now get profiles they otherwise would not — intended, but a billable change scoped to paid traffic. Console-side work (signup/login events, identify, server-side purchase) is specified in ad-creative/analytics-spec-paid-attribution.md and lives in a different repo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Contributor
|
Important Review skippedToo many files! This PR contains 1893 files, which is 1743 over the limit of 150. To get a review, reduce the PR to 150 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to Team to raise the limit. Usage-priced reviews support at most 300 files. ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Essentials Run ID: ⛔ Files ignored due to path filters (434)
📒 Files selected for processing (1893)
You can disable this status message by setting the |
Keeps the `trackSignUp` / `trackLogin` dataLayer helpers in the repo rather than only on one machine. They were written, then reverted unmerged because with the console work deferred there were no call sites, and dead exported code invites accidental use — so the source lives in this file's appendix until §2 of the paid-attribution spec is picked up. The file is marked SUPERSEDED at the top and points at analytics-spec-paid-attribution.md, which covers the same signup/login work plus purchase attribution. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
The problem
Google auto-tagging appends
gclidand no UTM params at all. ButisAttributionKeyinpackages/ui/src/lib/utm.tsmatched onlyutm_*andref, so every paid visit was stored as if it were direct traffic.gclidappeared nowhere in the codebase.That meant the first/last-touch attribution we already have — including the part that forwards it to
console.prisma.io— could not see paid acquisition at all.What this does
Captures click IDs.
gclid,wbraid,gbraid,msclkid,fbclid,li_fat_id,twclid,ttclidnow flow into the existing attribution store.Click IDs are deliberately not rewritten onto internal links — they're opaque and long, and only matter at the console boundary, where
syncUtmAttributionappends them alongside the existing first-touch params.Records paid touches on the PostHog person, not on a conversion event. A purchase can happen months after the click, far outside any ad platform's window — Google caps offline conversion import at 90 days — so attribution has to live somewhere durable.
$set_once(never overwritten)$set(most recent)is_paid_acquired,first_paid_at,first_paid_source,first_paid_campaign,first_paid_medium,first_paid_click_idlast_paid_at,last_paid_source,last_paid_campaign,last_paid_medium,last_paid_click_idOrganic visitors get no paid properties at all.
Keeps
@prisma-docs/uifree ofposthog-js.UtmPersistenceemits aprisma_attribution_changeDOM event; each app wires it to its own already-initialised client, matching the existing CookieYes event pattern.Two things reviewers should weigh
Coverage is bounded by consent. PostHog here is
opt_out_capturing_by_default: trueand only opts in on CookieYes analytics consent. A visitor who declines produces no data and cannot be attributed. This is a ceiling on the whole feature, not a bug.This creates person profiles. The project runs
person_profiles: identified_onlyviadefaults: "2025-11-30".setPersonPropertiescreates a profile where none exists, so paid-touched anonymous visitors now get profiles they otherwise wouldn't. Intended — it's what makes months-later attribution possible — but it is a billable change, scoped to paid traffic only.Verification
No test runner in the repo, so the pure logic was exercised directly against the real source — 15/15, covering:
gclidcaptured from a UTM-less landinggclidnot leaked onto internal linksgclidis carried to console linksapps/sitetypechecks clean.packages/uishows only its 5 pre-existingTS2307s (files copied in without their deps — unchanged by this PR).oxlintclean on all changed files.Not in this PR
Console-side work —
sign_up/loginevents,identify()with a URL fallback, server-sidepurchase— is specified inad-creative/analytics-spec-paid-attribution.mdand lives in a different repo.No GTM changes are needed for any of this.
🤖 Generated with Claude Code