---
title: "Browser SDK troubleshooting"
description: "Match a browser collector symptom to its cause and fix: token errors, consent gating, extension load reasons, CSP, duplicate tags and browser limits."
canonical_url: "https://noxtica.com/docs/sdk/troubleshooting/"
markdown_url: "https://noxtica.com/docs/sdk/troubleshooting/index.md"
last_updated: 2026-10-27
published: 2026-10-27
section: "browser-sdk"
section_title: "Browser SDK"
site: "Noxtica"
language: "en"
source: markdown
---

# Browser SDK troubleshooting

Use this page when the collector does not start, does not collect, or collects less than you expect. Every symptom below comes from an error body, a result code, an event or a console message that the collector produces. Start with the console checks, then find your symptom in the tables.

## What it is

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

The core script fails open. A problem in the collector does not block your page, and most failures show up as a missing event, a `reason` and `code` in a result, a `noxtica:error` event, or an HTTP error on a `/client/*` call. This page maps those signals to causes. Concepts are on [Install and Browser Runtime](https://noxtica.com/docs/browser-runtime/); the full reference is on the other pages of this section.

## Prerequisites

- A browser with DevTools (Console and Network).
- The page that shows the problem, served from the origin registered for the Site Key.
- Your Site Key. It is public. Never post a Server API key (`sk_…`), a session token or a cookie value in a ticket.
- For consent questions, the consent mode of the domain: Backoffice → Integrations & API → Script & Consent → **Consent & extensions**.

## Steps

### 1. Read the loader state

Run this in the console of the affected page:

```javascript
({
	version: window.noxtica && window.noxtica.v,                 // loader version, set by the initial core script
	loader: typeof window.NoxticaCollector,                       // 'object' when a core script ran
	client: typeof window.noxticaClient,                          // 'object' when a data-auto-init tag bound
	consent: window.noxticaClient && window.noxticaClient.getConsent(),
	extensions: window.noxticaClient && window.noxticaClient.getExtensionsState(), // 'not-loaded' | 'attached' | 'built-in'
	lastResult: window.noxticaResult,
	lastError: window.noxticaLastError,                           // { source, message, time }
	logLevel: window.NoxticaCollector && window.NoxticaCollector.getLogLevel(),
});
```

To see more, set the log level to `debug` with `data-log-level="debug"` on the tag and reload. The loader is silent by default. See [Script attributes and client options](https://noxtica.com/docs/sdk/script-attributes/).

### 2. Check the Network tab

Filter by your collector host. A working page shows the core script and `POST /client/token` with status `200`. After consent in a gated mode it also shows the extensions script, engine files and `POST /client/submit`. An error body from the collector carries a `requestId`; keep it for support.

### 3. Check consent and the extensions

Read `getConsent()`: `mode`, `modeResolved` and the four categories. Then call `await window.noxticaClient.loadExtensions()` and read `ok`, `reason` and `code`. The tables below explain each value.

### 4. Check the policy

Open the console on a page with the policy in force and look for violations that name a Noxtica host. See [Content Security Policy, hosts and first-party relay](https://noxtica.com/docs/sdk/csp-and-relay/).

### 5. Collect what support needs

Send: your Site Key, the page URL without query strings, the loader version (`window.noxtica.v`), the output of step 1, the failing request with its status and `requestId`, and the time. Contact your account team or use [Contact](https://noxtica.com/contact/). Platform incidents are listed on `status.noxtica.com`.

### 6. Check the browser

The collector needs WebAssembly and `blob:` workers for its engines. GPU attestation also needs WebGPU: without it the loader logs `WebGPU not available` and skips that step. The Web Locks API is optional; a browser without it falls back to a `localStorage` lock for the cross-tab check. A privacy mode, an extension or a network rule that blocks cross-origin requests, storage, workers or WebAssembly reduces the evidence or stops collection, and the page keeps working.

Headless and automated browsers are scored as bots, and your CDN may challenge them. Do not compare risk scores from headless runs. Test on a lab page, as described in [Release checks, testing and versions](https://noxtica.com/docs/browser-runtime/#release-checks-testing-and-versions).

Noxtica does not publish a verified minimum browser version list in this documentation. Test the browsers and privacy modes your own application supports.

## Verify it works

After a fix, reload the page with a clean profile and check:

- `typeof window.noxticaClient` is `'object'` and `window.noxtica.v` holds a version.
- `POST /client/token` answers `200`.
- `window.noxticaLastError` is `undefined`.
- In a gated mode, `getConsent().modeResolved` is `true`; after consent `getExtensionsState()` is `'attached'`.
- Exactly one `noxtica:collected` event fires for the page.

## Troubleshooting

### The script does not start

| Symptom | Cause | Fix |
| --- | --- | --- |
| `window.noxticaClient` undefined and no `noxtica:*` events | The tag lacks `data-auto-init` or `data-site-key`, or the `src` file name has neither `noxtica-collector` nor `/noxtica.js` | Add the attributes and keep the file name. A tag without a Site Key is skipped silently. |
| `window.NoxticaCollector` undefined | The core script did not load: blocked by CSP or a network rule, a `404`, or an integrity failure | Read the failed request in Network and the console. See the CSP page. |
| Pinned tag blocked with an integrity error | The pin is more than three releases old, or the hash was copied from a document | Copy the tag again from Script & Consent → Snippets, or use the stable tag. |
| `NX001: already loaded (v…), duplicate tag v… ignored.` | A second core or combined tag on the page | Remove it. The initial tag keeps running and its version is `window.noxtica.v`. |
| `window.noxtica(...)` does nothing | `window.noxtica` is a plain object without `q`, or the tag lacks `data-auto-init` | Define the stub as a function or array. |
| `NoxticaCollector: siteKey is required` | `createClient` found no Site Key | Pass `siteKey` or keep `data-site-key` on a collector tag. |
| A relay or proxy path loads the script but nothing binds | The proxied file name lost `noxtica-collector` | Keep the file name when you proxy the script. |

### `POST /client/token` fails

| Status and body | Cause | Fix |
| --- | --- | --- |
| `403` `Origin not allowed` | The request had no `Origin` header, so it did not come from a normal browser page | Test from a real page on the registered origin. |
| `403` `Origin mismatch` | The page origin differs from the origin registered for the Site Key | Use the key of the exact origin. Staging needs its own domain and key. |
| `400` `Missing siteKey` | The request body had no Site Key | Check the tag's `data-site-key` or the `siteKey` option. |
| `401` `Invalid siteKey` | The Site Key is unknown or inactive | Copy the key again from Backoffice → Domains. |
| `403` `Tenant suspended` or `Domain disabled` | The account or the domain is not active | Contact your account team. |
| `429` `Rate limit exceeded`, with `Retry-After` | The tenant and client address hit the token rate limit | Wait for `Retry-After`. |
| `429` `quota_exceeded` with code `COLLECTOR_REQUESTS_QUOTA_EXCEEDED` | The monthly collector request quota is used up, when quota enforcement is enabled | Check usage in Backoffice and see [Usage, quotas and metering](https://noxtica.com/docs/billing/usage-and-quotas/). |
| `413` `Payload too large` or `415` `Content-Type must be application/json` | A custom client or proxy changed the request | Do not rewrite collector requests. |

### Consent and gated modes

| Symptom | Cause | Fix |
| --- | --- | --- |
| `noxtica:collected` has `skipped: 'consent_required'` | A gated mode and `deviceId` not granted | Call `setConsent({ deviceId: 'granted' })` after the visitor agrees. Not an error. |
| `getConsent().mode` is `not_required` on an `api` domain | `modeResolved` is `false`: the saved mode has not arrived | Wait for `noxtica:consent-changed`, or declare `data-consent-mode`. |
| `setConsent` throws `NoxticaCollector.setConsent requires granted, denied, or { analytics, replay, deviceId, behavioral }` | A boolean or another shape | Pass `'granted'` or `'denied'`. |
| `setConsent` throws `unknown consent category` or `… must be granted or denied` | A wrong key or value | Use the four category names with the two strings. |
| Extensions load for visitors who declined | Not required mode with automatic loading, or a legacy script URL | See [Consent modes](https://noxtica.com/docs/sdk/consent/). |
| Two `noxtica:collected` events with different ids | Loader older than 3.8.1 | Update to the current loader; take the id from the server verify call. |
| `fingerprintId` in the browser differs from the server | The core and the extensions mint different ids | Use the id from `POST /v1/protected-actions/verify`. |

### Extensions: `loadExtensions()` results

`loadExtensions()` never rejects. It resolves `{ ok: true, loaded }` or `{ ok: false, reason, code, … }`. A later call retries after a failure.

| `reason` | `code` | Cause | Fix |
| --- | --- | --- | --- |
| `consent_missing` | `consent_required` | You passed `{ requireConsent: true }` in a gated mode and no category is granted | Grant a category before you call it, or drop the option. |
| `consent_missing` | `consent_withdrawn` | A queued `loadExtensions` was dropped because the queued consent denies all four categories (loader 3.8.1 and later) | Call `loadExtensions()` after a grant. |
| `csp_blocked` | `script-src-elem` or `script-src` | An enforced CSP blocked the script | Allow the collector host in that directive. |
| `integrity_mismatch` | `sha384_mismatch` | A pinned file's bytes differ from its hash | Copy the pinned tag again. |
| `network` | `http_<status>`, `fetch_failed` | The file returned an HTTP error or no response | Check the host, the proxy and `connect-src`. |
| `timeout` | `script_timeout` | No load or error event within 20 seconds | Retry. Check the network path. |
| `already_loaded` | `script_present` | A `<script>` for the extensions URL is in the page but nothing registered | Remove your own extensions tag, or fix why it did not run. |
| `unknown` | `build_mismatch` | The extensions come from another build than the core | Load core and extensions from the same collector release. |
| `unknown` | `invalid_extensions`, `handoff_failed`, `not_registered` | The extensions did not register or take over | Reload; report with the `error` text. |
| `unknown` | `script_exception`, `script_error` | The browser rejected a file that is reachable, or the script threw | Check the console. |
| `unknown` | `no_pinned_manifest`, `no_document`, `client_destroyed` | The core has no extensions manifest, there is no document, or the client was destroyed | Use a current core, call from a browser page, create a new client. |
| `unknown` | `legacy_loader` | The typed wrapper normalised a boolean from a loader older than 3.8.0 | Update the loader. |

`error` is human text. Do not parse it. The classification is approximate, because the browser's error event carries no cause.

### Protected actions

| Symptom | Cause | Fix |
| --- | --- | --- |
| `protect()` resolves `error: 'undeclared_protected_action'` | The name is not declared for the domain | Declare it and reload. |
| `protect()` rejects with `NoxticaCollector.protect: invalid protected action name` | The name does not match the action grammar | Use lowercase letters, digits, `-` and `_`, starting with a letter. |
| A form posts without `nox_request_id` | The check exceeded the hold time or the script was blocked | Treat it as no client signal. See [Protected actions](https://noxtica.com/docs/sdk/protected-actions/). |
| Verify returns `409`, `404` or `422` | Replay, expired or foreign id, or an action or domain mismatch | See the status table on the protected-actions page. |

### Responses and signatures

| Symptom | Cause | Fix |
| --- | --- | --- |
| Console warnings `Policy signature verification failed` or `Result signature verification failed`, or errors that mention `Missing policySigned envelope` or `Missing resultSigned envelope` | A response without its signed envelope, or whose signature does not verify. A rule or proxy that rewrites collector responses can cause it. | Stop rewriting collector responses. Keep `signatureMode` at `require`. |
| `noxtica:error` with source `Auto-init failed`, `Auto-check-once failed`, `Auto-collect failed` or `Deferred page check failed` | The automatic step threw; `message` holds the cause, cut to 200 characters | Read `window.noxticaLastError.message`, then match it to a row above. |

### Challenges and blocks

| Symptom | Cause | Fix |
| --- | --- | --- |
| `noxtica:challenge` with `status: 'unsupported'` | The browser cannot run the requested method (`gpu-pow` or `turnstile`) | Informational. The server decides what happens next. |
| A full-page overlay or a redirect | The server issued a block for the visit; `noxtica:block` reports `overlay` or `redirect` | Review the risk decision in Backoffice. The page cannot dismiss the overlay. |

## Related

- [Install and Browser Runtime](https://noxtica.com/docs/browser-runtime/): install, consent and the check list.
- [Script attributes and client options](https://noxtica.com/docs/sdk/script-attributes/): every attribute and option.
- [Client API, events and the command queue](https://noxtica.com/docs/sdk/client-api/): events and result shapes.
- [Consent modes, GPC and Google Consent Mode](https://noxtica.com/docs/sdk/consent/): modes and categories.
- [Content Security Policy, hosts and first-party relay](https://noxtica.com/docs/sdk/csp-and-relay/): policy and relay setup.
- [SDK Changelog](https://noxtica.com/docs/changelog/): behaviour that changed between loader releases.
