analytics: report referrer and traffic source in both analytics versions - #348
Open
MO-Thibault wants to merge 1 commit into
Open
MO-Thibault wants to merge 1 commit into
MO-Thibault wants to merge 1 commit into
Conversation
Adds two fields to the auction payload built by lib/addons/prebid/analytics.ts and lib/addons/prototypes/analytics.js: - referrer: the referring hostname only, never the full referring URL, which can carry query strings with personal data. - trafficSource: direct, internal, paid, campaign, email, organic_search, social or referral, derived from the referrer plus the campaign and click-id parameters on the landing URL. Both are first-touch per tab. document.referrer becomes the site's own hostname after the first internal click, so the first non-internal result is cached in sessionStorage under optableTrafficSource and reused for the rest of the session. Without that, every auction after the first pageview would report internal. The logic lives in lib/core/traffic-source.ts for the typed path and is inlined in the prototype file, which is self-contained and imports no modules. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
mosherBT
requested changes
Sep 21, 2026
| // self-contained and pulls in no modules. | ||
| const TRAFFIC_SOURCE_KEY = "optableTrafficSource"; | ||
| const SEARCH_SITES = ["google", "bing", "yahoo", "duckduckgo", "ecosia", "baidu", "yandex", "qwant", "startpage"]; | ||
| const SOCIAL_SITES = [ |
Contributor
There was a problem hiding this comment.
why duplicated? Can't we use the logic in one place traffic-source.ts?
| @@ -0,0 +1,105 @@ | |||
| const TRAFFIC_SOURCE_KEY = "optableTrafficSource"; | |||
Contributor
There was a problem hiding this comment.
Add test suite for this file
| const referrer = referrerHost(); | ||
| const properties: TrafficSourceProperties = { referrer, trafficSource: classify(referrer) }; | ||
|
|
||
| if (properties.trafficSource !== "internal") { |
Contributor
There was a problem hiding this comment.
Should this blokc on direct too?
| if (medium === "email") return "email"; | ||
| if (params.has("utm_source")) return "campaign"; | ||
| if (!host) return "direct"; | ||
| if (host === window.location.hostname) return "internal"; |
Contributor
There was a problem hiding this comment.
Prefer this I think. Host exact match will lead to a lot of referal false positives
if (siteName(host) === siteName(window.location.hostname)) return "internal";
| if (medium === "email") return "email"; | ||
| if (params.has("utm_source")) return "campaign"; | ||
| if (!host) return "direct"; | ||
| if (host === window.location.hostname) return "internal"; |
Contributor
There was a problem hiding this comment.
Flagged by claude I think relevant. We do utm check before internal so internal referal will get marked as campaign. Should move internal check to top
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.
Summary
Adds two fields to the auction payload built by both analytics implementations, so we can tell where a session's traffic came from alongside the bid data we already collect.
referrer— the referring hostname only.trafficSource— one ofdirect,internal,paid,campaign,email,organic_search,social,referral.Touched in both places:
lib/core/traffic-source.tsgetTrafficSource()returns{ referrer, trafficSource }lib/addons/prebid/analytics.tswitnessDatalib/addons/prototypes/analytics.jslib/addons/prebid/analytics.mdMotivation and design notes
Three decisions worth a reviewer's attention:
First-touch per tab.
document.referrerbecomes the site's own hostname after the first internal click. Classifying on every event would reportinternalfor every auction past the first pageview, which is useless. The first non-internal result is cached insessionStorageunderoptableTrafficSourceand reused for the rest of the session.Hostname, not full URL. Only the referring hostname is reported. Full referring URLs can carry query strings with personal data. This also costs nothing in practice, since browsers default to
strict-origin-when-cross-originand usually only give us the origin anyway.Named
trafficSource, notsource. The same payload already carriesoptableSources, meaning Optable data sources. Two fields calledsourceandoptableSourcesin one payload would be read as related when they are not.The logic is duplicated rather than shared between the two files:
lib/addons/prototypes/analytics.jsis self-contained and imports no modules, so it gets an inlined copy with a comment pointing back atlib/core/traffic-source.ts.Known limits
siteName()approximates the registrable domain with a short list of two-part suffixes rather than the public suffix list. Good enough to separategoogle.co.ukfromco, not exact.Referrer-Policy: no-referrerproduce an empty referrer, so some real social traffic lands indirectunless the link carries a click id. Expected, not a bug, but it matters when reading the numbers.traffic-source.ts. It is exercised at 57% through the analytics path. Severallib/coremodules ship without tests, but the classification rules are the kind of thing worth pinning down if reviewers want it.Test plan
pnpm build-lib(tsc) clean.pnpm exec jest— 469 tests across 28 suites pass, including the 82 existing prebid analytics tests.pnpm exec prettier --checkclean on all four files.🤖 Generated with Claude Code