Repository navigation
feat(browser): capture the Freebuff bfcid click ID - #5300
Conversation
Adds `bfcid` to the canonical campaign parameter list, so it is captured from the landing page URL and stored as `$initial_bfcid`, the same way `gclid`, `fbclid`, `oppref` and the other ad click IDs already are. Being in PERSONAL_DATA_CAMPAIGN_PARAMS also means URL and property masking covers it. The mirrored list in @posthog/core, which keeps the minimal `$feature_flag_called` payload in sync with the browser SDK, is updated alongside it, as are the fixtures, snapshots and current deployment compatibility goldens that list the full campaign parameter set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Coherence4 spec problems · 0 failing chokepoints · 2 spec gaps · 0 guard failures 44 components, 7 bullets (5 invariants, 2 requirements), 4 problems Spec problems (spec --check)
Chokepoints: none declared. Spec gaps: 2 entrances with outside or unknown trust and no traced control, and 10 more held by the adoption baseline
Close one with |
Node SDK compliance v2Commit: 0530e4e Capture v0 — acceptance✅ 5 passed / ❌ 0 non-passing / Drill-down: run artifacts → Harness exit: 0; report validation exit: 0. All selected cases passed and report validation succeeded. Capture v1 — acceptance✅ 5 passed / ❌ 0 non-passing / Drill-down: run artifacts → Harness exit: 0; report validation exit: 0. All selected cases passed and report validation succeeded. Capture v0 — migration✅ 55 passed / ❌ 1 non-passing / Drill-down: run artifacts → ❌ migration/yaml-parity-v1/remote-flags-v1.feature::Omitted GeoIP settings default to enabled in flag requests — failed_assertionFlags field differs Code: Failed step: migration/yaml-parity-v1/remote-flags-v1.feature:134 the first flags request field "geoip_disable" should equal JSON false Operation: Field: Expected: false Actual value: true Harness exit: 1; report validation exit: 1. Capture v1 — migration✅ 120 passed / ❌ 1 non-passing / Drill-down: run artifacts → ❌ migration/yaml-parity-v1/remote-flags-v1.feature::Omitted GeoIP settings default to enabled in flag requests — failed_assertionFlags field differs Code: Failed step: migration/yaml-parity-v1/remote-flags-v1.feature:134 the first flags request field "geoip_disable" should equal JSON false Operation: Field: Expected: false Actual value: true Harness exit: 1; report validation exit: 1. |
|
Size Change: +372 B (0%) Total Size: 24.1 MB 📦 View Changed
ℹ️ View Unchanged
|
posthog-js Compliance ReportDate: 2026-10-14 18:12:51 UTC ✅ All Tests Passed!26/26 tests passed Capture Tests✅ 26/26 tests passed View Details
|
|
Problem
Freebuff appends a signed click ID,
bfcid, to the landing page URL of an ad click (https://example.com/?bfcid=bfc_1...). PostHog captures every other network's click ID automatically (gclid,fbclid,msclkid,opprefand a dozen more) but not this one, so anyone advertising on Freebuff has to addcustom_campaign_params: ['bfcid']by hand. Even then they get no$initial_bfcidon the person and no masking undermask_personal_data_properties.Changes
bfcidjoinsPERSONAL_DATA_CAMPAIGN_PARAMS, so it is captured from the URL onto events and written to$initial_bfcidon the person, the same wayopprefwas added in feat(browser): capture the OpenAI Ads oppref click ID #5046.mask_personal_data_propertiesredacts it in URLs and properties. Freebuff's docs describe it as an opaque signed identifier, so it belongs on the maskable side.@posthog/corethat minimises the$feature_flag_calledpayload is updated to match, which an existing exhaustive regression test requires.current-*deployment compatibility goldens that enumerate the full campaign parameter set. Thehistorical-*goldens are unchanged because they run published core bytes, which do not knowbfcid.Not in this PR:
bfcidcookie for 30 days. Reading it throughCOOKIE_CAMPAIGN_PARAMS(asli_fat_iddoes) would recover it on later visits without the query param, but that is a separate decision about reading another vendor's cookie, so it is left out like the OpenAI__obrefcookie was.entry_bfcid) and channel-type classification. Those live server-side in the sessions tables and need a ClickHouse migration.Server half: the ingestion, taxonomy and Rust copies of this list are updated in PostHog/posthog#117217.
Reference: Freebuff conversion tracking docs.
Release info Sub-libraries affected
Libraries affected
Checklist
If releasing new changes
pnpm changesetto generate a changeset file🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Agent: Claude Code, Claude Opus 5.5
oppref): same list position, same mirrored list, same changeset shape.bfcidsits right afteroppref.bfcid/$initial_bfcidin sorted key order beside the existingdclidkeys. Per-file insert counts match the existingsccidcounts exactly.vitest run srcforpackages/browser(all tests that loaded passed;entrypoints/module.test.tsandinternal-console-errors.test.tsfailed to load because the local checkout had no fulldistbuild),test:functional, and@posthog/coretest:unit. The deployment compatibility suite (compatibility:test) was not run locally; CI is the check for the editedcurrent-*goldens.