Skip to content

Commit 5f06b06

Browse files
feat(audience): add CDN bundle, demo page, and README
- CDN IIFE entry point (window.ImmutableWebSDK), self-contained bundle - Interactive demo page for end-to-end testing - README with install, API reference, consent, cookies, CDN usage Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2ed1923 commit 5f06b06

4 files changed

Lines changed: 552 additions & 0 deletions

File tree

packages/audience/web/README.md

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# @imtbl/audience-web-sdk
2+
3+
Consent-aware event tracking and identity management for web surfaces. Part of the Immutable Audience platform.
4+
5+
## Install
6+
7+
```bash
8+
npm install @imtbl/audience-web-sdk
9+
```
10+
11+
## Quick Start
12+
13+
```typescript
14+
import { ImmutableWebSDK } from '@imtbl/audience-web-sdk';
15+
16+
const sdk = ImmutableWebSDK.init({
17+
publishableKey: 'pk_imtbl_...',
18+
environment: 'production',
19+
consent: 'anonymous',
20+
});
21+
22+
sdk.track('purchase', { currency: 'USD', value: 9.99, itemId: 'sword_01' });
23+
sdk.page();
24+
```
25+
26+
## Initialisation
27+
28+
```typescript
29+
const sdk = ImmutableWebSDK.init({
30+
publishableKey: 'pk_imtbl_...', // Required — from Immutable Hub
31+
environment: 'production', // 'dev' | 'sandbox' | 'production'
32+
consent: 'none', // 'none' | 'anonymous' | 'full' (default: 'none')
33+
consentSource: 'CookieBannerV2', // Identifies the consent source (default: 'WebSDK')
34+
debug: false, // Log all events to console (default: false)
35+
cookieDomain: '.studio.com', // Cross-subdomain cookie sharing (optional)
36+
flushInterval: 5000, // Queue flush interval in ms (default: 5000)
37+
flushSize: 20, // Queue flush size threshold (default: 20)
38+
});
39+
```
40+
41+
## Consent
42+
43+
The SDK defaults to `none` — no events are collected until consent is explicitly set.
44+
45+
```typescript
46+
sdk.setConsent('anonymous'); // Anonymous tracking (no PII)
47+
sdk.setConsent('full'); // Full tracking (PII via identify)
48+
sdk.setConsent('none'); // Stop tracking, purge queue, clear cookies
49+
```
50+
51+
Consent is:
52+
- **Persisted locally** via `_imtbl_consent` cookie (shared with the pixel)
53+
- **Synced server-side** via `PUT /v1/audience/tracking-consent`
54+
55+
| Level | Behaviour |
56+
|-------|-----------|
57+
| `none` | SDK is inert. No events collected. Queue purged on downgrade. |
58+
| `anonymous` | Events collected with anonymous ID only. `identify()` calls are discarded. |
59+
| `full` | Full collection. `identify()` sends. `userId` included on events. |
60+
61+
**On downgrade to `none`:** queue purged, `imtbl_anon_id` and `_imtbl_sid` cookies cleared.
62+
**On downgrade from `full` to `anonymous`:** identify messages purged, `userId` stripped from queued events.
63+
64+
## Auto-Tracked Events
65+
66+
The SDK automatically fires these events. Studios do not call them.
67+
68+
| Event | When | Properties |
69+
|-------|------|------------|
70+
| `session_start` | SDK init with no active session cookie | `sessionId` |
71+
| `session_end` | `shutdown()` called | `sessionId`, `duration` (seconds) |
72+
73+
## Event Tracking
74+
75+
```typescript
76+
sdk.track('sign_up', { method: 'google' });
77+
sdk.track('purchase', { currency: 'USD', value: 9.99 });
78+
sdk.track('wishlist_add', { gameId: 'game_123', source: 'landing_page' });
79+
sdk.track('beta_key_redeemed', { source: 'influencer' });
80+
```
81+
82+
## Page Tracking
83+
84+
Call `sdk.page()` on route changes. Attribution context (UTMs, click IDs, referrer, landing page) is automatically attached to the first page view.
85+
86+
```typescript
87+
sdk.page();
88+
sdk.page({ section: 'shop', category: 'weapons' });
89+
```
90+
91+
## Identity
92+
93+
```typescript
94+
// Identify a known user (requires full consent)
95+
sdk.identify('user@example.com', 'email');
96+
sdk.identify('76561198012345', 'steam');
97+
sdk.identify('passport_sub_abc', 'passport', {
98+
email: 'user@example.com',
99+
name: 'Player One',
100+
});
101+
102+
// Identify with traits only (anonymous, no userId)
103+
sdk.identify({ source: 'steam', steamId: '76561198012345' });
104+
105+
// Link two identities (same player, different providers)
106+
sdk.alias(
107+
{ uid: '76561198012345', provider: 'steam' },
108+
{ uid: 'user@example.com', provider: 'email' },
109+
);
110+
111+
// Reset on logout (new anonymous ID, clears userId)
112+
sdk.reset();
113+
```
114+
115+
## Queue & Lifecycle
116+
117+
```typescript
118+
await sdk.flush(); // Force flush all queued events
119+
sdk.shutdown(); // Flush remaining events, stop the SDK
120+
```
121+
122+
Events are batched and flushed every 5 seconds or when 20 messages accumulate. On page unload (`visibilitychange` / `pagehide`), remaining events are flushed via `fetch` with `keepalive: true`.
123+
124+
## CDN Usage
125+
126+
For sites without a bundler:
127+
128+
```html
129+
<script src="https://cdn.immutable.com/web-sdk/v1/imtbl-web.js"></script>
130+
<script>
131+
var sdk = window.ImmutableWebSDK.init({
132+
publishableKey: 'pk_imtbl_...',
133+
environment: 'production',
134+
consent: 'anonymous',
135+
});
136+
137+
sdk.track('signup_started');
138+
sdk.identify('user@example.com', 'email');
139+
</script>
140+
```
141+
142+
## Cookies
143+
144+
All cookies are first-party, `SameSite=Lax`, `Secure` on HTTPS, and shared with the pixel:
145+
146+
| Cookie | Lifetime | Purpose |
147+
|--------|----------|---------|
148+
| `imtbl_anon_id` | 2 years | Anonymous device ID |
149+
| `_imtbl_sid` | 30 min (rolling) | Session continuity |
150+
| `_imtbl_consent` | 1 year | Consent state |
151+
152+
## Wire Format
153+
154+
Events are sent to `POST /v1/audience/messages` with the `x-immutable-publishable-key` header. All messages include `surface: 'web'` and follow the backend OpenAPI spec.

0 commit comments

Comments
 (0)