---
title: "Client API, events and the command queue"
description: "The page globals, the methods of window.noxticaClient, every noxtica:* event, the window.noxtica command queue and the checkOnce result, as the loader implements them."
canonical_url: "https://noxtica.com/docs/sdk/client-api/"
markdown_url: "https://noxtica.com/docs/sdk/client-api/index.md"
last_updated: 2026-10-27
published: 2026-10-27
section: "browser-sdk"
section_title: "Browser SDK"
site: "Noxtica"
language: "en"
source: markdown
---

# Client API, events and the command queue

This page is the reference for what the core script puts on your page: the globals, the client methods, the events on `document`, and the `window.noxtica(...)` command queue. Use it when you wire a consent banner, react to a step-up challenge, or queue calls before the script has loaded.

## What it is

Availability: Evaluation access. Availability depends on your plan, role and the modules enabled for your organisation.

A core tag with `data-auto-init` builds one client for the page. The client, the events and the command queue exist on tags that carry `data-auto-init`. A client you create with `NoxticaCollector.createClient()` returns its results through promises and does not fire `noxtica:ready`. See [Script attributes and client options](https://noxtica.com/docs/sdk/script-attributes/).

Until the extensions script attaches, the core runs a reduced lane. When the extensions attach, every public method of the client delegates to the extensions runtime; the core keeps `loadExtensions`, `getExtensionsState` and `destroy`. Loading the extensions never grants consent; see [Consent modes](https://noxtica.com/docs/sdk/consent/).

## Prerequisites

- The core tag with `data-site-key` and `data-auto-init`, as generated by Backoffice → Integrations & API → Script & Consent → Snippets.
- Your listeners registered before the core tag runs. Put them in an inline script in `<head>` above the tag. An event that already fired is not replayed.
- Your own consent flow, if the domain uses the `api` mode: your page calls `setConsent`. See [Consent modes](https://noxtica.com/docs/sdk/consent/).

## Steps

### 1. Read the page globals

| Global | What it holds |
| --- | --- |
| `window.NoxticaCollector` | The loader object: `VERSION`, `SCHEMA_VERSION`, `SDK_VERSIONS`, `createClient(options)`, `autoDiscoverSiteKey()`, `setApiUrl(url)`, `setIngestUrl(url)`, `setLogLevel(level)`, `getLogLevel()`, and on the core script `BUNDLE` (`'core'`), `registerExtensions(ext)` and a static `loadExtensions()`. `setApiUrl` and `setIngestUrl` take effect for clients created afterwards and reject a URL that is not `https` (localhost excepted). Other members of the object are diagnostics, not part of the supported surface. |
| `window.noxticaClient` | The client of the `data-auto-init` tag. Properties `siteKey`, `apiUrl` and `ingestUrl`. |
| `window.noxtica` | The command function (step 4). `window.noxtica.v` holds the loader version once a core or combined script has claimed the page. |
| `window.noxticaResult` | The last result announced with `noxtica:collected`. |
| `window.noxticaLastError` | The last error the loader reported: `{ source, message, time }`. The message is cut to 200 characters. |

### 2. Call the client methods

**Page check and state**

| Method | Returns | Notes |
| --- | --- | --- |
| `checkOnce(options)` | Promise of a result (step 5) | Cache-aware page check. Options are in [Script attributes and client options](https://noxtica.com/docs/sdk/script-attributes/). In a gated consent mode without a `deviceId` grant it resolves a `skipped` result and runs again when the grant arrives. |
| `collectAndSubmit()` | Promise of a result | Collects and submits on every call, without the cache. |
| `collect()`, `submit(payload)`, `visit(deviceId, meta)` | Promises | Building blocks of the two methods above. Prefer `checkOnce`. |
| `getToken()` | Promise of the session token string, or `null` | Fetches or refreshes the token without submitting. |
| `getPolicy()` | Object or `null` | The policy delivered with the session token. |
| `getStoredState()`, `clearStoredState()` | State object or `null`; nothing | Read or delete the cached device state that `checkOnce` uses. |
| `getEffectiveTtlSeconds(options)` | Number | The cache window in seconds that a call with these options would use. |

**Lifecycle**

| Method | Effect |
| --- | --- |
| `pause()`, `resume()` | `pause` holds replay flushing, mutation processing and tracker and RUM uploads without ending anything; `resume` drains what was held. |
| `stop()`, `start()` | `stop` tears the lanes down but keeps consent state and device storage; `start` re-arms them. |
| `destroy()` | Stops timers and lanes and makes this client inert. Create a new client to continue. |

**Consent and extensions**

| Method | Effect |
| --- | --- |
| `setConsent(update)` | `update` is `{ analytics, replay, deviceId, behavioral }` with values `'granted'` or `'denied'`, or the legacy string `'granted'` / `'denied'`, which sets the `analytics` category. Any other shape throws a `TypeError`. |
| `getConsent()` | `{ mode, modeResolved, analytics, replay, deviceId, behavioral, privacySignal }`. |
| `enableGoogleConsentMode()` | Turns on the Google Consent Mode v2 bridge. |
| `setReplayConsent(boolean)` | Legacy switch for the `replay` category. |
| `getReplayConsentState()` | `UNINITIALIZED`, `DISABLED`, `AWAITING_CONSENT`, `DENIED` or `POLICY_READY`. |
| `getReplayRecorderState()` | `idle`, `loading`, `active`, `stopped` or `error`. |
| `loadExtensions(options)` | Promise of `{ ok: true, loaded }` or `{ ok: false, reason, code, … }`. Never rejects. See [Loading extensions and its result](https://noxtica.com/docs/browser-runtime/#loading-extensions-and-its-result). |
| `getExtensionsState()` | `'not-loaded'`, `'attached'`, or `'built-in'` on the legacy combined script. |

**Protected actions, identity and events**

| Method | Effect |
| --- | --- |
| `protect(name, { timeoutMs })` | Runs the protected-action check and resolves the result with a `requestId`. See [Protected actions](https://noxtica.com/docs/sdk/protected-actions/). |
| `setAccountId(id)` | Links the device to your own account id on the next submit. Non-string, empty and values over 256 characters are ignored. Use an opaque id. |
| `identify(id, { hint })` | Session identity: Noxtica receives a hash of the id and a two-character hint. Not the same as `setAccountId`. The typed wrapper calls this `identifySession()` and uses `identify()` for the account id. |
| `setTag(key, value)`, `event(name, value)`, `getMetadata(callback, options)`, `upgrade(reason)` | Session tags, timeline markers, the ids that join Noxtica data to yours, and starting replay with a reason. Limits and consent rules are on [Custom events, session tags and request tracing](https://noxtica.com/docs/observability/events-and-tracing/). `upgrade` returns `started`, `already_recording`, `pending_consent` or `refused`. |
| `track(name, properties)` | Custom application event. Names and properties that the domain allow-list does not list are dropped. |
| `withRequestSpan(url, callback)`, `spanFetch(url, init)` | W3C trace context for one request, for origins on the domain's trace allow-list. |
| `loadReplayPlugins()`, `loadReplayAssist()`, `debug({ uploads })` | Replay add-ons and the upload debug switch. See [Session replay](https://noxtica.com/docs/observability/session-replay/). |

The client object has more members, such as tracker and token-refresh controls. They are internal and not supported.

### 3. Listen to events

All events are dispatched on `document` with a `CustomEvent`. Register the listeners in `<head>` before the core tag:

```html
<script>
	document.addEventListener('noxtica:collected', (event) => {
		if (event.detail.skipped === 'consent_required') return; // not an error
		// Hand event.detail.fingerprintId to your backend as a hint, not as an identity.
	});
	document.addEventListener('noxtica:error', (event) => {
		console.warn('Noxtica reported', event.detail.source, event.detail.message);
	});
	document.addEventListener('noxtica:challenge', (event) => {
		// event.detail: { status: 'started' | 'solved' | 'failed' | 'unsupported', method: 'gpu-pow' | 'turnstile' }
	});
	document.addEventListener('noxtica:block', (event) => {
		// event.detail: { status: 'blocked' | 'redirected' | 'failed', mode: 'overlay' | 'redirect' }
	});
</script>
```

| Event | `event.detail` | When |
| --- | --- | --- |
| `noxtica:ready` | `{ client }` | The `data-auto-init` tag created the client and ran the command queue. The automatic check has not started. Fires once per tag. |
| `noxtica:collected` | The check result, or `{ success: false, skipped: 'consent_required', fromCache: false, consentMode }` | After the automatic check, a check that waited for consent, and a queued `checkOnce`. Also sets `window.noxticaResult`. |
| `noxtica:cache-hit` | The same result with `fromCache: true` | Right after `noxtica:collected` when the cache answered. |
| `noxtica:consent-changed` | The `getConsent()` snapshot | A consent category really changed, or the signed mode differs from the page's declaration once the token arrives. |
| `noxtica:extensions-loaded` | `{ message: 'attached', ok: true, loaded }` | The extensions took over the client. |
| `noxtica:extensions-failed` | `{ message: 'not-loaded', ok: false, reason, code, … }` | A load attempt failed, or a queued `loadExtensions` was dropped because every category is denied. |
| `noxtica:error` | `{ source, message, time }` | The loader reported a failure. Known sources include `Auto-init failed`, `Auto-check-once failed`, `Auto-collect failed`, `Deferred page check failed` and `noxtica("<command>") failed`. Also stored in `window.noxticaLastError`. |
| `noxtica:challenge` | `{ status, method }` | The server asked the browser for a step-up challenge. `status` is `started`, `solved`, `failed` or `unsupported`; `method` is `gpu-pow` or `turnstile`. Advisory: the server decides. |
| `noxtica:block` | `{ status, mode }` | The page enforced a server block. `status` is `blocked`, `redirected` or `failed`; `mode` is `overlay` or `redirect`. Advisory. |
| `noxtica:protected` | `{ action, requestId, success, source, reason, timedOut? }` | A protected-action check for a form or control settled. Dispatched on that element; it bubbles. `source` is `warm`, `click` or `submit`. |
| `noxtica:debug-upload` | The captured upload | Fires with `data-debug-upload` or `debug({ uploads })` and in no other case. |

`noxtica:challenge` and `noxtica:block` fire when the server issues a challenge or a block for the visit, and not otherwise. Whether your domain can issue them depends on your configuration. The page acts on a block directive when the signed result verifies and carries the same block id, so a forged directive does nothing.

With `createClient` options `onChallenge` and `onBlock` you get the same details through callbacks. A callback that throws never breaks collection.

`noxtica:extensions-*` details were strings before SDK 3.8.0. Read `detail.message` for the old value.

### 4. Queue calls before the script loads

The command queue follows the gtag pattern. Define the stub above the core tag, then call it:

```html
<script>
	window.noxtica = window.noxtica || function () { (window.noxtica.q = window.noxtica.q || []).push(arguments); };
	noxtica('consent', 'gcm');
	noxtica('set', 'plan', 'pro');
</script>
<script
	src="https://collect.noxtica.com/collector/noxtica-collector-core.js"
	data-site-key="pk_prod_your_site_key_here"
	data-auto-init
	data-auto-check-once
	async
></script>
```

An array assigned to `window.noxtica` also works as a stub. The core replays the queued calls in order against the initial client it creates, then replaces the stub with a live function. Later calls, and a stub reference you kept, run at once and return the method's result.

| Command | Arguments | Runs |
| --- | --- | --- |
| `setConsent` | update object, or `'granted'` / `'denied'` | `client.setConsent` |
| `consent` | `'gcm'`, or an update object | `enableGoogleConsentMode()` or `setConsent` |
| `loadExtensions` | options | `client.loadExtensions` |
| `protect` | name, options | `client.protect` |
| `checkOnce` | options | `client.checkOnce`; the result is announced with `noxtica:collected` |
| `set` | key, value or list of values | `client.setTag` |
| `identify` | id, `{ hint }` | `client.identify` (session identity) |
| `event` | name, value | `client.event` |
| `metadata` | callback, `{ wait, recall }` | `client.getMetadata` |
| `upgrade` | reason | `client.upgrade` |
| `pause`, `resume`, `stop`, `start` | none | the lifecycle methods |

These are the 14 commands. Behaviour to rely on:

- An unknown command logs a warning and does nothing. A command that fails reports `noxtica:error` and never throws.
- Queued `setConsent` and `consent` updates are folded into one update, applied where the earliest of them stood (a later key wins), so you get one `noxtica:consent-changed`. A queued `loadExtensions` is dropped when the folded state denies all four categories. This applies to loader 3.8.1 and later; earlier loaders replayed every call in order.
- If `window.noxtica` is a plain object without a `q` array, the loader leaves it untouched and the commands are unavailable.
- Deciding consent in a `noxtica:ready` handler is more robust than queuing it. See [Events and timing](https://noxtica.com/docs/browser-runtime/#events-and-timing).

### 5. Read the `checkOnce` result

| Field | Present when | Meaning |
| --- | --- | --- |
| `success` | always | `true` when the check or the cache hit succeeded. |
| `fingerprintId` | success | Device id as the browser sees it. A hint: the core and the extensions runtimes can mint different ids for one browser. The authoritative id is the one from [the server-side verify call](https://noxtica.com/docs/sdk/protected-actions/). |
| `fromCache` | always | `true` when the cache answered. |
| `cachedResult` | cache hit | `{ score, risk_level, confidence, flags }` from the last check, or `null` when the cookie is the sole storage that survived. |
| `daysSinceSubmit`, `nextSubmitIn` | cache hit | Days since the last submit and days left in the window. |
| `visitRecorded` | `recordVisit: false` | `false`. |
| `acquiredFromAnotherTab` | another tab ran the check | `true`. A cross-tab lock keeps tabs from submitting twice; it times out after 30 seconds. |
| `forceRefreshed` | `forceRefresh: true` | `true`. |
| `skipped`, `consentMode` | gated mode without a `deviceId` grant | `skipped: 'consent_required'`; no `fingerprintId`. |

A numeric `score`, `risk_level` and `confidence` may be absent when the server withholds them. Treat a missing score as unknown, never as zero.

## Verify it works

Open the console on a page that has the tag and consent decided:

```javascript
window.noxticaClient.getConsent();        // { mode, modeResolved, analytics, replay, deviceId, behavioral, privacySignal }
window.noxticaClient.getExtensionsState(); // 'not-loaded' before the extensions attach, 'attached' after
window.noxticaResult;                      // the last result announced with noxtica:collected
window.noxtica.v;                          // the loader version
await window.noxticaClient.getToken();     // a token string once /client/token succeeded
```

Add a temporary listener for each event in step 3 and reload. A healthy consented page logs `noxtica:ready`, then `noxtica:consent-changed` and `noxtica:extensions-loaded` after your consent call, then `noxtica:collected`.

## Troubleshooting

| Symptom | Cause | Fix |
| --- | --- | --- |
| A listener never fires | It was registered after the event, or the tag lacks `data-auto-init` | Move the listener into `<head>` above the tag. For a late page, read `window.noxticaClient` and `window.noxticaResult` directly. |
| `window.noxtica(...)` does nothing | `window.noxtica` is a plain object, or the tag lacks `data-auto-init` | Define the stub as a function or an array, and keep `data-auto-init`. |
| `setConsent` throws `NoxticaCollector.setConsent requires granted, denied, or { analytics, replay, deviceId, behavioral }` | The argument is `true`, `false` or another shape | Pass the strings `'granted'` or `'denied'`. |
| `setConsent` throws `unknown consent category` | A key other than `analytics`, `replay`, `deviceId`, `behavioral` | Remove the key. |
| `noxtica:collected` carries `skipped: 'consent_required'` | The domain is in a gated mode and `deviceId` is not granted | Call `setConsent({ deviceId: 'granted' })` after the visitor agrees. The check then runs again on the same page. |
| `protect()` resolves `error: 'undeclared_protected_action'` | The action name is not declared for the domain | Declare it in Script & Consent → Protected actions. |
| `identify()` did not link my account | `identify` is the hashed session identity | Use `setAccountId(id)`. |
| Two `noxtica:collected` events with different ids | A loader older than 3.8.1 | See [SDK Changelog](https://noxtica.com/docs/changelog/). Take the id from the server-side verify call. |

## Related

- [Script attributes and client options](https://noxtica.com/docs/sdk/script-attributes/): the options that configure the client.
- [Consent modes, GPC and Google Consent Mode](https://noxtica.com/docs/sdk/consent/): categories, precedence and the Google bridge.
- [Protected actions](https://noxtica.com/docs/sdk/protected-actions/): `protect()`, `noxtica:protected` and the server check.
- [Install and Browser Runtime](https://noxtica.com/docs/browser-runtime/): events and timing, extension load reasons.
- [Custom events, session tags and request tracing](https://noxtica.com/docs/observability/events-and-tracing/): the session API in depth.
- [Browser SDK troubleshooting](https://noxtica.com/docs/sdk/troubleshooting/): symptoms across the SDK.
