Compass Web SDK: Integration Guide
Audience: Front-end and site developers integrating a publisher site with the Compass Web SDK.
The Compass Web SDK β published as @arcxp/compass-sdk and exposed in the
browser as the global ArcCompass β is Arc XPβs first-party, client-side library
for collecting reader interaction events (page views, video progress, clicks,
and more) and posting them to the event collector. These events train the
recommendation models.
It ships as a single bundled JavaScript file for <script> inclusion, and also
as an npm ESM module for build-pipeline consumers (React / Next). The target is
a roughly one-hour integration: paste a snippet, call init() once, resolve
consent, and call track() for each event.
Quickstart
<script> (function (w, d) { w.ArcCompass = w.ArcCompass || { q: [] }; ["init", "setConsent", "setUserId", "track", "trackExposure", "flush"].forEach(function (m) { w.ArcCompass[m] = w.ArcCompass[m] || function () { w.ArcCompass.q.push([m, [].slice.call(arguments)]); }; }); // getUserId returns a value, so it can't ride the queue: until the bundle // attaches there is no identifier yet, so the stub returns null. w.ArcCompass.getUserId = w.ArcCompass.getUserId || function () { return null; }; // observeRecommendations returns a handle: queue the call and return a // deferred handle that wires to the real detector once the bundle loads. w.ArcCompass.observeRecommendations = w.ArcCompass.observeRecommendations || function (options) { var record = { disconnected: false, real: null }; w.ArcCompass.q.push(["observeRecommendations", [options, record]]); return { disconnect: function () { record.disconnected = true; if (record.real) record.real.disconnect(); } }; }; var s = d.createElement("script"); s.async = true; s.src = "https://arc-rec.app-recommend.aws.arc.pub/arc-rec/v1/compass-sdk.iife.min.js"; d.head.appendChild(s); })(window, document);
window.ArcCompass.init({ // Events collector base path for your org. The SDK appends `/events/batch`. domain: "https://<org-id>-config-prod.api.arc-cdn.net/collect-web/v1", apiKey: "<arc-delivery-token>", }); // Single collect-for-personalization gate: pass true once your CMP reports // consent. Nothing is sent or persisted until then. window.ArcCompass.setConsent(true); window.ArcCompass.track("page_view");</script>The rest of this guide walks through each step.
1. Provision a delivery token
Provision a delivery token through the Arc XP Delivery API β see Provisioning tokens through the Delivery API.
The SDK sends this token as the X-API-Key header on every request.
Use a key scoped to the browser events collection (the collect-web API).
That key can post events but cannot reach the content catalog, so it is safe to
embed in page JavaScript.
2. Add the snippet
Place this block in <head>, before any code that calls ArcCompass.*:
<script> (function (w, d) { w.ArcCompass = w.ArcCompass || { q: [] }; ["init", "setConsent", "setUserId", "track", "trackExposure", "flush"].forEach(function (m) { w.ArcCompass[m] = w.ArcCompass[m] || function () { w.ArcCompass.q.push([m, [].slice.call(arguments)]); }; }); // getUserId returns a value, so it can't ride the queue: until the bundle // attaches there is no identifier yet, so the stub returns null. w.ArcCompass.getUserId = w.ArcCompass.getUserId || function () { return null; }; // observeRecommendations returns a handle: queue the call and return a // deferred handle that wires to the real detector once the bundle loads. w.ArcCompass.observeRecommendations = w.ArcCompass.observeRecommendations || function (options) { var record = { disconnected: false, real: null }; w.ArcCompass.q.push(["observeRecommendations", [options, record]]); return { disconnect: function () { record.disconnected = true; if (record.real) record.real.disconnect(); } }; }; var s = d.createElement("script"); s.async = true; s.src = "https://arc-rec.app-recommend.aws.arc.pub/arc-rec/v1/compass-sdk.iife.min.js"; d.head.appendChild(s); })(window, document);</script>The snippet defines a tiny stub on window.ArcCompass so calls made before the
bundle loads queue up and replay in order.
The β¦/arc-rec/v1/β¦ URL is major-pinned, so you receive backwards-compatible
fixes automatically. For production, add Subresource Integrity (integrity +
crossorigin) as shown in Distribution,
which also covers exact-version pinning, the npm (ESM) install, and the
self-host fallback.
3. Initialize the SDK
ArcCompass.init({ domain: "https://<org-id>-config-prod.api.arc-cdn.net/collect-web/v1", apiKey: "<arc-delivery-token>",});domain is the browser events collector base path for your org: the shared
<org-id>-config-prod.api.arc-cdn.net hostname followed by the collect-web/v1
prefix. The SDK appends /events/batch, so events post to
https://<org-id>-config-prod.api.arc-cdn.net/collect-web/v1/events/batch. Arc
provides the exact base URL during onboarding.
4. Resolve consent
Translate whatever your CMP returns into the SDKβs single yes/no gate:
ArcCompass.setConsent(true); // collect-for-personalization grantedEvents that fired before this call are flushed once consent resolves. Nothing is sent or persisted until then. See Consent & Identity for the full state machine.
5. Add the content and site meta tags
Add these tags to each pageβs <head> so the SDK can attribute events to the
right content and Site:
<!-- Required. The content item this page represents; it must match the ID the content was ingested under. --><meta name="arc-compass:item-id" content="ARTICLE-ABC123" />
<!-- Optional. The Site this page belongs to β multi-site tenants only. --><meta name="arc-compass:site-id" content="the-daily" />item-id must be present for automatic page_view capture to fire. You can
override either value for a single event with track(type, { itemId, siteId }).
See Events & Reliability for the full resolution order.
6. Track events
ArcCompass.track("video_progress", { itemId: "VIDEO123", eventValue: 0.75 });page_view is captured automatically on load and on SPA route changes β you do
not need to call track("page_view") yourself unless you disable auto capture
(autoPageView: false). item_id and the optional site_id come from the
meta tags you set above; pass itemId or siteId to track() to override them
for a single event. See Events & Reliability.
7. (Optional) Set a known user ID after login
ArcCompass.setUserId("user-abc-123");// Pass null on logout to revert to the persistent anonymous ID.ArcCompass.setUserId(null);A stable, host-managed ID is what makes personalization work across devices. See Consent & Identity.
Configuration reference
ArcCompass.init(options) accepts the following options. Only domain and
apiKey are required.
| Option | Type | Default | Description |
|---|---|---|---|
domain | string | β (required) | Events collector base path for your org, e.g. https://<org-id>-config-prod.api.arc-cdn.net/collect-web/v1. No trailing slash. The SDK appends /events/batch. |
apiKey | string | β (required) | Arc-provisioned delivery token scoped to the browser events (collect-web) collection. Sent as X-API-Key. |
cookieDomain | string | inferred eTLD+1 (e.g. .host.com) | Cookie Domain attribute for the anonymous-ID cookie. Set explicitly for multi-subdomain sites. |
batch.maxEvents | number | 20 | Flush when the buffer reaches this many events. |
batch.flushIntervalMs | number | 2000 | Flush this many milliseconds after the last flush. |
queue.maxBuffered | number | 500 | Hard cap on in-memory queued events. Oldest are dropped on overflow with a console.warn. |
autoPageView | boolean | true | Fire page_view automatically on load and SPA route changes, reading item_id from the <meta name="arc-compass:item-id"> tag (and the optional site_id from <meta name="arc-compass:site-id">). Set false to call track('page_view', { itemId }) yourself. |
attributionRoot | Element | string | false | document.body | Root under which the SDK scans for host-rendered recommendations carrying the data-arc-compass-* binding β also the click-delegation container, so tagged elements (and elements passed to trackExposure) must live inside it. Accepts an element or a CSS selector (resolved once the DOM is ready). Narrow it to the container that holds recommendations to avoid a page-wide MutationObserver; pass false to disable the scan entirely. A structurally-broken root (invalid selector, or a non-Element value) disables the binding with a console.warn; a valid selector whose container has not mounted yet is deferred and attaches on the next trackExposure. See Recommendation Attribution. |
debug | boolean | false | Log lifecycle and transport diagnostics. |
onError | (e: ArcCompassErrorInfo) => void | β | Called when the SDK abandons a batch (a terminal 4xx/429, or a 5xx/network failure that exhausts retries). Use it to forward otherwise-silent data loss to your observability. Runs in a detached flush context, so it never interrupts the page; anything it throws is swallowed. See Error visibility. |
Error visibility
The SDK is fire-and-forget: track() never throws, and a batch that the
collector rejects (or that never gets through) is dropped rather than surfaced
to the page. To make those drops observable, wire onError to your tooling β it
fires only for terminal transport failures, off the userβs interaction path:
ArcCompass.init({ domain: "https://<org-id>-config-prod.api.arc-cdn.net/collect-web/v1", apiKey: "<collect-web token>", onError: (e) => { // e: { message, reason: "rejected" | "exhausted", status?, droppedEvents, eventTypes, cause? } Sentry.captureException(e.cause ?? new Error(e.message), { extra: e }); // or: datadogRum.addError(e.cause ?? new Error(e.message), e); },});reason: "rejected" is a 4xx/429 the collector refused (fix the payload or
key β retrying wonβt help); reason: "exhausted" means repeated 5xx/network
failures used up the retry budget. status is absent for network/CORS errors
(no response). Per-event issues (an unresolved item_id, a coerced
event_value) are logged only under debug, not through onError.
Cookie domain inference
When cookieDomain is omitted, the SDK falls back to the last two labels of
location.hostname (e.g. www.example.com β .example.com). This is correct
for most single-suffix TLDs but cannot handle multi-segment public suffixes
(e.g. .co.uk, .com.au, GitHub Pages) β set cookieDomain explicitly in
those cases.
Browser support
The SDK assumes baseline support for fetch with keepalive: true,
crypto.randomUUID (with a fallback when absent), visibilitychange, and
localStorage / sessionStorage / cookies.
Tested matrix:
- Chrome / Edge / Chromium β₯ 90
- Safari / WebKit β₯ 14
- Firefox β₯ 88
The SDK is browser-only. The IIFE bundle is safe to include in a
server-rendered page β it no-ops on import when window is undefined.
See also
- Content Recommendations Overview β how this path fits the whole integration, and when to use a forwarder instead.
- Compass Web SDK: Consent & Identity
- Compass Web SDK: Events & Reliability
- Compass Web SDK: Distribution & FAQ
- Content Recommendations Onboarding Checklist