Who is this for? Web developers building web games, marketing sites, or SPAs who need explicit event tracking, user identity, or SPA support. Works with any framework (React, Next.js, Svelte, vanilla JS).
page() on each route change, and in-game moments like progressions, purchases, and sign-ups are triggered by your code. All events flow to the same pipeline as the Unity SDK and REST API.
What You Need
- An Immutable Hub account with a project (get started here)
- A publishable key from your project settings (API keys guide)
Installation
- npm
- yarn
- pnpm
- CDN
Quick Start
1
Initialize the SDK
- npm
- CDN
2
Set consent
The SDK uses a three-tier consent model (At
'none', 'anonymous', 'full'). The SDK does not provide a consent UI. Build your own cookie banner or privacy prompt, then call setConsent with the appropriate level when the user responds.'anonymous', page views and events are tracked but identify() and alias() calls are dropped. At 'full', all methods are available. See the Data Dictionary for what is collected at each level.3
Track page views
Call
page() on each route change. The first call in each session includes attribution parameters.4
Track events
Log player actions with
track(). The SDK ships with predefined events for common player actions (purchases, sign-ups, progression, wishlist actions, and more) that give you typed properties and autocomplete. You can also pass any custom event string.- npm
- CDN
5
Identify users
Identifies the player by associating their userId with their activity and traits. Call at login or account connection. Requires
'full' consent.- npm
- CDN
6
Clean up on exit
Flushes the queue and shuts down the SDK.
Complete Example
- npm
- CDN
Auto-Capture
The SDK captures form submissions, outbound link clicks, and scroll depth by default. Internal link clicks and button clicks are off by default, since they can be noisy on interactive pages. Turn them on where the extra signal is useful, such as measuring whether players open a#trailer modal or click a call-to-action.
Use the autocapture option to control what’s collected:
forms, clicks, and scroll to false to disable auto-capture entirely and rely only on your manual page() and track() calls.
See form_submitted and scroll_depth for exact property shapes. link_clicked shares its schema with the predefined event of the same name: a manual track('link_clicked', ...) call for a link auto-capture can’t see looks identical on the wire.
Verify the Integration
Initialize withdebug: true to see SDK activity in the browser console:
- Console: Look for log entries showing
pageand anytrack()calls - Network tab: Look for POST requests to
https://api.immutable.com. Events flush every 5 seconds or when 20 events accumulate
Remove
debug: true before deploying to production.Content Security Policy
If your site enforces a Content-Security-Policy header, add the event endpoint so the SDK can deliver events:If you install the SDK as a package dependency (npm/yarn/pnpm), only
connect-src is required. The CDN directive is only needed for the <script>-tag installation.nonce attribute to your inline <script> tag. The nonce covers the inline code only. The CDN-loaded script is authorized by the script-src directive above.
API Reference
Audience.init(config)
Audience.init(config)
Creates and returns an
Audience instance. Call once when your app loads to set up tracking.setConsent(level)
setConsent(level)
Controls what the SDK is allowed to collect. Call when the user accepts or changes their cookie preferences. Takes effect immediately, no page reload needed. See the Data Dictionary for consent levels and downgrade behavior.
canTrack(level)
canTrack(level)
Checks whether a consent level allows tracking. Returns
true when level is 'anonymous' or 'full'. Use before calling track() or page() when you need to guard behavior based on the current consent level, for example when conditionally showing a tracking-dependent UI element.canIdentify(level)
canIdentify(level)
Checks whether a consent level allows player identification. Returns
true when level is 'full'. Use before calling identify() or alias() when you need to guard identity-dependent logic, for example to only prompt a player to link accounts when consent allows it.page(properties?)
page(properties?)
Records a page view. Call on every route change to track which pages players visit and in what order. The first call in each session includes attribution parameters.
Requires:
'anonymous' or 'full' consent. Calls at 'none' are silently dropped.track(event, properties?)
track(event, properties?)
Records a player action. Call when a player does something you want to measure, such as a purchase, sign-up, level completion, or any custom action. Predefined events give you typed properties with autocomplete.
Requires:
'anonymous' or 'full' consent. Calls at 'none' are silently dropped.identify(id, identityType, traits?)
identify(id, identityType, traits?)
Associates the player’s userId with their activity and traits. Call at login or account connection.Identity types:
Requires:
'full' consent.alias(from, to)
alias(from, to)
Links two account IDs that belong to the same player. Call when a player connects a second account with a different provider, for example a player previously identified via Steam who later links a Passport account.
Requires:
'full' consent.deleteData(userId?)
deleteData(userId?)
Requests erasure of all event data for a player. Call when a player submits a data deletion request (e.g. GDPR right-to-erasure). The backend resolves all linked identities via stored alias mappings and queues an erasure event for async processing.
When
userId is omitted and no anonymous ID has been created yet (fresh install with no prior tracking), the call is a no-op — there is no record to erase.Failures are surfaced via config.onError with code 'DATA_DELETE_FAILED'. The returned promise always resolves.getAnonymousId()
getAnonymousId()
Returns the anonymous ID for the current browser session. Useful for debugging, passing the ID to a third-party tool, or carrying it across a browser redirect. See Cross-Browser Tracking.
reset()
reset()
Wipes the current player’s identity and starts a fresh anonymous session. Call when a player logs out so the next player on the same device isn’t mixed up. Reset does not change the consent level, so studios using an explicit consent prompt should also call
setConsent('none') at logout if the next player should start unconsented.flush()
flush()
Sends all queued events to the server immediately. Call when you need events delivered right now instead of waiting for the next automatic flush. Returns a
Promise that resolves when the batch is sent.shutdown()
shutdown()
Sends any remaining events and shuts down the SDK. Call when the app unmounts or the page is about to unload.
Cross-Browser Tracking
When a player moves between domains or browser contexts, the SDK mints a fresh anonymous ID in the new context and their prior session history is disconnected. To carry the anonymous ID across, append it to the URL:imtbl_aid automatically on init, adopts it as the anonymous ID for that session, and removes the parameter from the URL. No extra code is needed on the landing page.
If the player logs in after the redirect, call identify() as normal. The anonymous session is linked to their account.
This works for any redirect where you control the destination URL. It does not apply when the OS or browser handles navigation directly (for example, a Share sheet or a bookmark), since there is no opportunity to append parameters before the URL is opened.
Event Delivery
- Events are batched and flushed every 5 seconds or when 20 events accumulate (configurable via
flushIntervalandflushSize) - On page unload (navigate away, close tab), the queue flushes remaining events so they are not lost
FAQ
What happens if I call track() before consent is set?
What happens if I call track() before consent is set?
The call is a no-op. No events are queued or sent. Once you call
setConsent('anonymous') or higher, subsequent calls will be tracked.What browsers are supported?
What browsers are supported?
Chrome 80+, Firefox 78+, Safari 14+, Edge 80+.
How do I handle a GDPR erasure request?
How do I handle a GDPR erasure request?
Call If the player has no known user ID (they were only tracked anonymously), call For server-side erasure (e.g. triggered from a backend request), see Deleting User Data in the REST API docs.
deleteData() with the player’s user ID. This sends a deletion request to the backend, which resolves all linked identities and queues an erasure event for async processing.deleteData() with no argument — the SDK uses the device’s persistent anonymous ID automatically.After the deletion request is sent, call reset() to clear the local identity and generate a fresh anonymous ID so the next session is not linked to the erased player:Next Steps
Attribution
How tracking data powers player attribution and Hub reports
Data Dictionary
Full reference of event schemas and consent levels
Unity SDK
In-game tracking for Unity desktop builds
REST API
Send events from your backend or game server
Conversion Postbacks
Send attributed conversions back to ad networks to improve campaign optimisation
API Keys
Manage your publishable and secret keys