SDK 2 installation and reference
This guide describes SDK 2.0 event capture and SDK 2.1 replay. For SDK 1.x, use the legacy reference.
Install
Section titled “Install”Release channels at the 2026-10-04 recovery checkpoint:
| Channel | Availability |
|---|---|
npm @siteqwality/rum | 1.0.7. SDK 1.1 and 2.x are not published on npm at this checkpoint. |
CDN /rum/v1/ | SDK 1.1 reported live. |
CDN /rum/v2/ | SDK 2.0 reported live; this moving alias does not yet provide replay 2.1. |
| SDK 2.1 | Candidate only, not deployed. Its fixed-header transport and backend CORS fix must be released together before the canary. |
Use the application’s public applicationId and clientToken. Do not use an account API key in a browser. Do not use npm install @siteqwality/rum@2 for this recovery checkpoint: no 2.x package is available there yet. The existing npm package is not interchangeable with the CDN SDK2 bundle.
The initialization example below applies to a reviewed SDK2 package build once available. For the currently reported CDN2.0 channel, use the CDN snippet and retain the legacy replay host in CSP. Replay behavior later in this guide is explicitly labeled 2.1 and describes the candidate, not the live alias.
import { SiteQwalityRUM } from '@siteqwality/rum';
SiteQwalityRUM.init({ applicationId: 'YOUR_APPLICATION_ID', clientToken: 'YOUR_CLIENT_TOKEN', service: 'web', env: 'production', version: '1.4.2', // Your application release, not the SDK version. trackingConsent: 'pending', // Grant through your consent manager when appropriate.});
// Run this when the visitor grants consent.// SiteQwalityRUM.setTrackingConsent('granted');Call init before mounting your app. It starts collection synchronously and returns a promise that settles after config loads or fails, with a 3-second config timeout. You do not need to await it. A second init is ignored; public methods do not throw.
CDN snippet
Section titled “CDN snippet”This snippet loads the moving 2.x CDN alias, reported to contain SDK 2.0 at this checkpoint. It does not select the undeployed SDK 2.1 candidate. Before the alias advances to 2.1, complete the replay rollout prerequisites. Authorize the inline bootstrap using your site’s CSP nonce or hash; see CSP and endpoint configuration.
<script> (function(w,d,s,u){var r=w.SiteQwalityRUM=w.SiteQwalityRUM||{_q:[]};if(r._q&&!r._h){ ['init','setUser','clearUser','setGlobalAttribute','removeGlobalAttribute', 'addError','addAction','setView','setTrackingConsent','optOut','optIn', 'isOptedOut','startReplay','stopReplay','getSessionUrl','getStatus'].forEach(function(m){ r[m]=function(){r._q.push([m,arguments])}}); r._h=function(e){r._q.push(['_e',[e]])};w.addEventListener('error',r._h); w.addEventListener('unhandledrejection',r._h); var e=d.createElement(s);e.async=1;e.src=u;(d.head||d.documentElement).appendChild(e)} })(window,document,'script','https://cdn.siteqwality.com/rum/v2/sdk.min.js');
SiteQwalityRUM.init({ applicationId: 'YOUR_APPLICATION_ID', clientToken: 'YOUR_CLIENT_TOKEN', trackingConsent: 'pending' });</script>The stub queues all 16 public methods and early errors. It runs init first when the bundle arrives. A queued getter has no synchronous return value; call getStatus, getSessionUrl and isOptedOut after the real SDK loads when you need their results.
/rum/v2/sdk.min.js is the moving 2.x alias. Immutable releases use /rum/v<version>/sdk.min.js. Keep the matching recorder-<version>.min.js and gzip-<version>.min.js beside the core when self-hosting SDK 2.1. The gzip fallback loads only when native compression is unavailable. The /rum/v1/ alias stays on 1.x.
Endpoints and config
Section titled “Endpoints and config”| Purpose | SDK 2 endpoint | Authentication |
|---|---|---|
| Events | POST https://in.siteqwality.com/v2/batch | Authorization: Bearer <clientToken> |
| Identity check, when enabled | POST https://in.siteqwality.com/v2/identity | Same header |
| Config | GET https://cdn.siteqwality.com/rum/config/v2/<applicationId>.json | No token, cookies or custom headers |
| Replay, SDK 2.1 | POST https://in-replay.siteqwality.com/v2/segments | Bearer header and x-sq-replay-index |
| Replay, SDK 2.0 | POST https://replay.siteqwality.com/v1/segments | Bearer header |
ingestBase, replayBase and configBase override those host bases for a first-party proxy. Do not include the endpoint path in the base. apiBase was removed in 2.0. Preserve authentication as a header; never put a client token in the URL. See the proxy requirements.
Config is cached under _sq_cfg_<applicationId> in localStorage when consent is granted. A tab becoming visible refreshes a config older than five minutes. Until config arrives, the SDK uses the cached config or safe defaults: Observe sample rate 1, no Analyze or Replay rules, Balanced privacy, masked inputs and GPC honored. A failed refresh keeps the previous config. Set pending consent in init when required, because the remote config may arrive after initial collection.
Init options
Section titled “Init options”| Option | Default | Effect |
|---|---|---|
applicationId, clientToken | Required | The application’s public credentials. |
service, env, version | None | Sent in batch context; version identifies your application release. |
trackingConsent | granted, unless cached config requires consent | pending, granted or not-granted. Pass explicitly for consent-gated sites. |
persistence | cookie | Session persistence: cookie, localStorage or memory. |
cookieDomain | Current host | Share a session across your subdomains. |
hashRouting | false | Treat hash routes as page views. |
routeName(path) | None | Return a route label such as /users/:id. |
allowedQueryParams, deniedQueryParams | None | URL minimization exceptions; built-in sensitive names remain denied. |
ignoreErrors, denyUrls | None | String or RegExp lists for error messages and top-frame URLs. |
beforeSend(event, kind) | None | Synchronous hook for error, view, action, custom, network and console events. |
ingestBase, replayBase, configBase | Hosts above | First-party proxy bases. |
recorderUrl | Next to the CDN core | Override the CDN recorder URL; keep its gzip fallback beside it. |
debug | false | Log config, recording decisions and transport outcomes. |
Public methods
Section titled “Public methods”| Method | Behavior |
|---|---|
setUser({id, email, name, traits}), clearUser() | Set or clear identity for subsequent batches. Traits accept up to 20 string labels; email capture follows application privacy settings. |
setGlobalAttribute(key, value), removeGlobalAttribute(key) | Attach string labels to batch context, including measures. Up to 50 keys and 4 KB total. |
addError(error, context) | Capture any value through the error filters. context['sq.fingerprint'] sets a custom fingerprint. |
addAction(name, context) | Record an Observe custom event, even without an Analyze rule match. |
setView(name) | Name the current view’s route. |
setTrackingConsent(consent) | Change consent for this page. |
optOut(), optIn(), isOptedOut() | Persist or read browser opt-out. These work before init. |
startReplay({force}), stopReplay() | Start or stop replay. force: true bypasses sampling, not consent, privacy or quota. |
getSessionUrl({atCurrentTime}) | Get an internal session link, optionally with ?at=<epoch ms>. Viewers still need account access. |
getStatus() | Inspect SDK version, session/window IDs, consent, sampling, recording state, config revision and drop counters. |
With npm, other calls before init are ignored. Treat context, traits and global attributes as stored data; use non-personal labels such as { feature: 'checkout' }.
beforeSend may return false or null to drop an event, an object to replace it, or nothing to retain in-place edits. Views cannot be dropped. The SDK limits edits to existing fields of the same type, preserves event identity and timing, and sanitizes modified values again. A thrown hook keeps the original event. SDK 2 error fields include message, stack and error_type; replace SDK 1 hooks that expect error_message or error_stack.
Capture and billing
Section titled “Capture and billing”With the Phase 1 intake deployed, accepted errors count toward Observe sessions, on both /v2/batch and the compatibility /v1/errors endpoint. An error alone does not make the session Analyze. Filtered browser noise does not claim usage. A recording rule triggered by that error can still activate Analyze or Replay and incur those session counts when data is accepted.
| Tier | Capture and usage |
|---|---|
| Observe | Views, vitals, accepted errors, failed requests, frustration signals and custom events for sampled sessions. Default Observe sampling is 100%; privacy, filtering, quotas and budgets still apply. |
| Analyze | Accepted detail such as actions, successful requests, resources, console and long animation frames after a rule match. A memory buffer holds up to 60 seconds or 500 detail events before activation. |
| Replay | A Replay rule also enables Analyze. The first accepted replay segment counts the session toward Replay; retries do not add a new replay session. An unmatched memory buffer alone is not a billed replay. |
Free monthly allowances are 1,000 Observe sessions, 100 Analyze sessions and 100 Replay sessions. Paid packs increase those allowances; replay is priced per recorded session, not per stored MB. Before the Phase 1 intake deployment, the legacy error handler counted real errors as Analyze. This billing change is a server deployment gate, not merely an SDK version check.
Replay 2.1 transport
Section titled “Replay 2.1 transport”The fixed endpoint is POST /v2/segments, with no segment-specific query string. Index fields move to the x-sq-replay-index header as a URL-encoded query-string value, for example:
Authorization: Bearer <clientToken>x-sq-replay-index: s=<session-uuid>&w=<window-uuid>&p=<page-load-uuid>&q=0&ft=<first-epoch-ms><=<last-epoch-ms>&n=<event-count>&fs=1&v=<sdk-version>s, w, p, q, ft, lt and n identify the stream, sequence and event range. Optional fs=1 marks a full snapshot, fin=1 a best-effort final segment, and r the URL-encoded rule ID. Sequence numbers start at zero per session/page-load stream and continue across recorder restarts within that stream. Every tab records its own window.
Send exactly one index header, at most 2,048 bytes. Do not combine it with URL query parameters. Intake retains the query-only form for older clients, but rejects ambiguous input.
The body is a JSON array of rrweb events. Gzip uses Content-Type: application/octet-stream; uncompressed fallback uses application/json. The intake detects gzip from the body. No client If-None-Match header is needed; deduplication uses a conditional write in storage.
Segments normally close at 20 seconds or about 2.5 MB of serialized JSON, and on tab hide. The first full snapshot is sent promptly. A snapshot larger than 4 MB after stylesheet references stops recording for that page load (too_large). These are SDK segmentation thresholds, not intake limits: intake allows at most 2 MB on the wire and 16 MB inflated.
Requests are sent in order, one at a time. Network errors, 408, ordinary 429 responses and 5xx retry with backoff; Retry-After holds sends, including unload. The coordinated 2.1 release distinguishes two explicit response reasons: a 403 with reason: "not_enabled" stops replay for the page load while Observe and Analyze continue, without retrying through legacy replay, and a 429 with reason: "session_cap" stops replay for that session. Other 401 or 403 responses and an exhausted request budget stop delivery. Other 4xx responses drop a segment. A missing snapshot also drops dependent segments and requests a fresh snapshot. Identical retry bodies are deduplicated by intake.
At page close, the SDK attempts a keepalive tail using already-compressed bytes or JSON within the shared 60 KB keepalive budget. Delivery and the final marker are best-effort. Inspect getStatus().dropped, including replay_tail_dropped and replay_segments_dropped, rather than assuming every closing event arrived.
Replay buffer and privacy
Section titled “Replay buffer and privacy”SDK 2.1 can download the recorder before a rule matches, but only when a sampled-in Replay rule could still match the session’s device, release and environment, and recording is permitted. It keeps the current and previous full-snapshot intervals in memory, with snapshots about 60 seconds apart and a 5 MB buffer target. A match sends retained segments oldest first, then streams new recording.
This can include roughly 60 to 120 seconds before a later error. It does not guarantee a minute of history: a fresh page, delayed config or consent, a pause, memory pressure or a large snapshot may leave less. Nothing from an unmatched replay buffer is uploaded or persisted. It is discarded on page close, stop, consent withdrawal, opt-out, GPC restrictions or a do-not-record decision. SDK 1.x and 2.0 do not have this pre-trigger replay buffer.
| Privacy mode | Behavior in SDK 2.1 |
|---|---|
| Strict | Masks page text except configured unmask selectors, masks inputs and blocks media. Block selectors always win. |
| Balanced | Masks inputs; page text is visible with configured PII patterns scrubbed. Default patterns cover emails, card-like numbers and long digit runs. |
| Relaxed | Masks inputs; ordinary page text is visible and default text PII patterns are empty. |
| Legacy Custom | Uses stored masking flags. Review them explicitly; legacy applications can have input masking disabled. |
Password, email and telephone inputs remain masked; hidden inputs are excluded. Credit-card autocomplete fields cannot be exposed through legacy input-unmasking. URLs in page metadata, DOM attributes and CSS are minimized. No canvas recording or iframe document content is captured by this recorder. Stylesheet references can avoid resending acknowledged CSS; images and fonts still depend on their asset URLs.
Recording pauses while hidden, after five minutes without input, or on never-record URLs, and resumes with a full snapshot when permitted. Pointer, scroll and media sampling plus mutation throttling mean replay does not preserve every intermediate DOM state. Heavy mutation bursts can leave marked gaps and require a fresh snapshot.
Consent and browser signals
Section titled “Consent and browser signals”pending: telemetry waits in a bounded memory queue of up to 200 events; no telemetry uploads or persistent session state. Replay recording does not start. The public config may still be fetched.granted: the held telemetry can be flushed, session persistence follows the configured mode, and eligible replay recording can start.not-granted: discard queued data, stop replay and clear session/config state. Previously uploaded data is not deleted by this method.optOut(): stop sending and remember the preference in_sq_optout;optIn()permits collection again subject to consent and config.- Honored GPC: no Analyze, replay, anonymous visitor ID or supplied user identity; Observe can continue using a cookieless session in sessionStorage (or memory when storage is unavailable). This is not a promise of zero requests or zero technical identifiers.
Do not infer a Privacy Center UI, deletion workflow, error alerting, source-map CLI, analytics segmentation or canvas support from the SDK methods and config fields. Those require their separate product rollouts.
Migration checklist
Section titled “Migration checklist”- Confirm the intake, config CDN, replay pipeline and application rollout prerequisites.
- Update CSP before switching bundles. Retain legacy hosts while old SDKs still run.
- Replace
apiBaseand SDK 1-onlybeforeSendfields. Update the CDN stub’s method list. - Choose consent explicitly and review the stored privacy config before testing a replay.
- Verify the config GET, event POST and replay preflight in browser Network tools. A successful config GET alone does not prove ingestion or playback.
- Check
getStatus()and a real session in the dashboard, including an accepted replay and its playback, before expanding traffic.
SDK 2 shares sessions across tabs by default through _sq_s; _sq_w identifies a window. Sessions expire after 15 minutes of inactivity or four hours total. The SDK adopts an existing SDK 1.1 session and rule decision on first load where available.