Skip to content

feat(audience): add pixel core class, consent state machine, and session cookie#2830

Merged
bkbooth merged 11 commits into
mainfrom
SDK-50-pixel-core-consent
Apr 8, 2026
Merged

feat(audience): add pixel core class, consent state machine, and session cookie#2830
bkbooth merged 11 commits into
mainfrom
SDK-50-pixel-core-consent

Conversation

@bkbooth
Copy link
Copy Markdown
Contributor

@bkbooth bkbooth commented Apr 7, 2026

Summary

Wires the pixel package to @imtbl/audience-core and lifts shared modules into core:

  • Session management → lifted to core (session.ts): _imtbl_sid cookie with 30-min rolling expiry, getOrCreateSession() returns SessionResult with isNew flag for session lifecycle events
  • Attribution tracking → lifted to core (attribution.ts): UTM params, click IDs, referrer, landing page, sessionStorage caching
  • Consent state machine → lifted to core (consent.ts): Three-level consent (none/anonymous/full) with DNT/GPC detection, queue purge on downgrade to none, userId stripping on downgrade to anonymous, PUT to /v1/audience/tracking-consent via httpSend
  • Generic httpSendTransportOptions now supports method (default POST) and typed ConsentUpdatePayload, so consent uses the shared transport instead of raw fetch
  • Pixel class (pixel.ts): init() creates MessageQueue with storagePrefix isolation, auto-fires PageMessage with attribution context, fires session_start on new sessions and session_end on page unload (with duration), supports identify (full consent only), setConsent, and destroy. Common message fields extracted into buildBase() helper.
  • Version 1.0.0 with build-time injection from package.json via tsup define

Pixel now imports session, attribution, and consent from @imtbl/audience-core — no duplication. The pixel's index.ts only exports pixel-specific code (Pixel class, loader, snippet).

IIFE bundle: 9.05 KB raw (well under 10 KB budget).

Knowingly deferred to follow-up PRs

Test plan

  • pnpm --filter @imtbl/audience-core test — 87/87 passing (11 suites)
  • pnpm --filter @imtbl/pixel test — 26/26 passing (3 suites)
  • pnpm --filter @imtbl/pixel build — IIFE bundle produced (9.05 KB)
  • pnpm --filter @imtbl/pixel lint — clean
  • pnpm --filter @imtbl/pixel typecheck — clean
  • CI passes

🤖 Generated with Claude Code

bkbooth and others added 2 commits April 7, 2026 13:13
…r, and snippet

Add the pixel package scaffold and three self-contained modules that have
no dependency on PR #2824. The package builds to a single IIFE bundle
(dist/imtbl.js) targeting <10KB gzipped (currently 823 bytes).

Modules:
- attribution: UTM params, ad click IDs, referrer, landing page (session-cached)
- loader: command-queue pattern (window.__imtbl) with pre-load replay
- snippet: embeddable <script> tag generator for studio integration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@bkbooth bkbooth requested review from a team as code owners April 7, 2026 04:27
@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented Apr 7, 2026

View your CI Pipeline Execution ↗ for commit 46a42d8

Command Status Duration Result
nx run-many -p @imtbl/sdk,@imtbl/checkout-widge... ✅ Succeeded 3s View ↗

☁️ Nx Cloud last updated this comment at 2026-04-08 00:25:56 UTC

bkbooth and others added 2 commits April 7, 2026 14:38
… reference

Add dclid (Google DV360) and li_fat_id (LinkedIn) to match the
Tracking Pixel Event Reference doc. Also add referral_code parsing
and touchpoint_type derivation (set to 'click' when UTMs or click
IDs are present).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ion cookie

Wire the pixel to audience-core now that PR #2824 has merged:

- Consent state machine: three-level (none/anonymous/full), DNT/GPC detection,
  queue purge on downgrade to none, userId strip on downgrade to anonymous,
  fire-and-forget PUT to /v1/audience/tracking-consent
- Session cookie: _imtbl_sid with 30-min rolling expiry
- Pixel class: init creates MessageQueue with storagePrefix isolation,
  auto-fires PageMessage with attribution context, supports identify at
  full consent, setConsent, and destroy
- Build config: resolves audience-core from source via tsup alias for
  tree-shaken self-contained IIFE bundle (8.04 KB raw / 3.2 KB gzipped)
- Metrics stub: no-op stubs so the pixel bundle doesn't ship internal telemetry

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@bkbooth bkbooth force-pushed the SDK-50-pixel-core-consent branch from e1bc2e5 to 8f6bce0 Compare April 7, 2026 04:39
bkbooth and others added 3 commits April 7, 2026 15:32
Add session lifecycle tracking to the Pixel class:
- Fire session_start track event on new session creation
- Fire session_end track event on pagehide/visibilitychange with duration
- Refactor session module to return SessionResult with isNew flag
- Fix test listener leaking by cleaning up pixel instances in afterEach

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move session management, attribution tracking, and consent state machine
from @imtbl/pixel into @imtbl/audience-core so the web SDK can share them.

- session.ts: use SESSION_COOKIE from core config instead of duplicating
- attribution.ts: UTM params, click IDs, referrer, sessionStorage caching
- consent.ts: three-level state machine with DNT/GPC, queue purge/transform
- Remove pixel re-exports of core modules (no backwards compat needed yet)
- Add SESSION_MAX_AGE constant to core config
- Pixel now imports everything from @imtbl/audience-core

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Read version from package.json in tsup.config.ts and inject it via
esbuild define as PIXEL_VERSION_INJECTED. This stamps every event
payload with the correct libraryVersion automatically — no manual
bumping needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comment thread packages/audience/pixel/src/pixel.ts Outdated
Comment thread packages/audience/pixel/src/pixel.ts Outdated
Comment thread packages/audience/core/src/consent.ts Outdated
Comment thread packages/audience/core/src/consent.ts Outdated
@ImmutableJeffrey ImmutableJeffrey requested a review from a team as a code owner April 7, 2026 08:03
Base automatically changed from SDK-50-pixel-package-scaffold to main April 7, 2026 08:57
bkbooth and others added 2 commits April 8, 2026 09:22
…sent

Resolve conflicts: keep HEAD versions for pixel package config,
re-delete attribution files that were reintroduced from main (#2829),
add packages/audience/sdk from main to pnpm-workspace.yaml.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…load fix

Review feedback from Natalie on PR #2830:

1. Extract buildBase() helper in Pixel class to deduplicate messageId,
   eventTimestamp, anonymousId, surface, and context fields across
   page(), identify(), fireSessionStart(), and fireSessionEnd().

2. Fix consent PUT payload: rename `consentLevel` to `status` and add
   `source` field to match backend OAS. Accept source as a parameter
   to createConsentManager() so pixel passes 'pixel' and web SDK can
   pass 'sdk'.

3. Add comment on direct fetch usage in consent (different method/payload
   than httpSend's BatchPayload POST).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
nattb8
nattb8 previously approved these changes Apr 7, 2026
Add method option to TransportOptions so consent module can use httpSend
instead of raw fetch. Type the consent payload as ConsentUpdatePayload
and widen httpSend to accept both BatchPayload and ConsentUpdatePayload.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@bkbooth bkbooth enabled auto-merge April 8, 2026 00:14
@bkbooth bkbooth added this pull request to the merge queue Apr 8, 2026
Merged via the queue into main with commit 80fcd63 Apr 8, 2026
11 of 12 checks passed
@bkbooth bkbooth deleted the SDK-50-pixel-core-consent branch April 8, 2026 00:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants