Bản dịch này được tạo bằng máy và đang chờ xem xét.Chuyển sang tiếng Anh
Trên trang này

SDK Changelog

Release notes for the browser collector SDK, the core and extensions scripts served from your collector host. Each entry says what changed, who is affected and what to do. The newest release is first, and the version number is the one the collector reports: window.noxtica.v on a page that runs 3.7.0 or later.

Only one release needs a code change on your side: 3.8.0, tagged Breaking below. Every other release is additive or a fix, so a page that adopts none of the new surface keeps working. Releases before 3.5.2 are not listed. Install steps, consent modes, events and the command queue are described on Install and Browser Runtime.

The stable collector URLs serve the latest build. A hashed build you pinned with Subresource Integrity keeps serving for the last few releases, so to take a release, copy the new pinned tag from Backoffice → Integrations & API → Script & Consent → Snippets. The version number names a release, not the exact bytes: when a fix ships without a version bump, the hashed file name and its integrity value identify the build.

A client-side fingerprintId is a hint

The core (minimal) and extensions (full) runtimes legitimately mint different ids for one browser. A fingerprintId that arrives in noxtica:collected or noxtica:cache-hit is therefore a hint for your page, not an identity. The only authoritative id is the one returned to your backend by POST /v1/protected-actions/verify. Release 3.8.1 fixes a race so that one page load produces one page check and one submit; before it, the race could produce two noxtica:collected events with different ids. For the server-side step see Backend Integration.

Compatibility with @noxtica/sdk

@noxtica/sdk is the typed wrapper around the collector script. It does not contain the collector: the script always comes from your collector host, so the pair that runs on a page is one collector release (this page) and one wrapper release. The Developers page states what is currently published.

Collector release@noxtica/sdkNotes
3.8.10.3.0 (targets this release)0.3.0 needs a collector core of 3.8.0 or newer.
3.8.00.3.0 (minimum supported core)loadExtensions() resolves a result object (Breaking).
3.7.x, 3.6.x, 3.5.20.2.x0.2.x types loadExtensions() as a boolean and passes the loader’s value through. On a 3.8.0 or newer core it still resolves the object at run time, which is always truthy: use .ok, or move to 0.3.0.

Against a core older than 3.8.0, 0.3.0 turns the boolean into the 3.8.0 result shape: { ok: true, loaded: [] } for true and { ok: false, reason: 'unknown', code: 'legacy_loader' } for false. The session members (@noxtica/sdk/session, from 3.7.0) throw on a core older than 3.7.0, as track() does on a build that predates it. The wrapper has its own release notes for typings and framework helpers; this page covers the collector.

SDK 3.8.1 (2026-10-24)

Fixes and consent-handling changes; nothing is removed or renamed.

Fixed

  • One page check is one submit. With consent delivered at noxtica:ready, loadExtensions() called at the same point and a token response slower than the extensions script, a page check could run twice: two submits, two runtimes and two noxtica:collected events with different fingerprintId values. A page-check call that is still waiting for the token now joins the runtime when it attached in the meantime. One page load produces one submit.
    • Who: pages that grant consent and call loadExtensions() early, with data-auto-check-once or checkOnce(); most visible on cold devices where the token round trip is slower than loading the extensions script.
    • Do: nothing. Remove any de-duplication you added around noxtica:collected, and take the authoritative id from your server-side verify call.
  • No second skipped event. Replaying an already-settled, skipped page check no longer dispatches a second noxtica:collected with skipped: 'consent_required'. Only a real result is announced.
  • One token per page session across the core to extensions hand-off. On the documented install (the core with auto-loaded extensions) the extensions runtime could mint its own token a few seconds after the core’s. A payload the core had collected, sealed under the first token, was then submitted under the second token and the server answered 400 Unable to process request. The core now hands its token to the runtime, which adopts it when it has more than 30 seconds of life left; later rotations mint normally.
    • Who: pages on the documented install that call collect() then submit() (or checkOnce()) with the extensions loaded, on a domain with KHAN armed or a guarded RUM policy.
    • Do: nothing. No configuration or server change. Re-copy a pinned tag to get the build.

Changed

  • The pre-init command queue is coalesced. When the core replays window.noxtica.q, every setConsent or consent update folds into one update (a later key wins) applied at the position of the first one, so you get one noxtica:consent-changed. A queued loadExtensions is dropped when the folded state denies all four categories: it answers noxtica:extensions-failed with { ok: false, reason: 'consent_missing', code: 'consent_withdrawn' }. Invalid entries and consent gcm run unchanged. A later live noxtica('loadExtensions') is an explicit call and still loads.
    • Who: pages that queue several consent updates before the core loads, or queue loadExtensions ahead of a consent banner.
    • Do: expect one noxtica:consent-changed for the whole queue. Prefer deciding consent in a noxtica:ready handler over queuing it.
  • The signed consent mode is announced, and getConsent() says whether it is known. noxtica:consent-changed now also fires when the mode signed for your domain differs from the page’s declaration at token time (for example an untagged page on a domain set to API mode: not_required becomes api). getConsent() and the event detail carry modeResolved, which is false until the token applied the signed mode. Auto-loading extensions (data-extensions="auto") fails closed: before the mode is known it needs an explicit grant, and it never runs when every category is denied. A manual loadExtensions() is unchanged.
    • Who: pages that rely on auto-load without declaring a consent mode on the tag, and code that compares getConsent().mode with the tag’s declaration.
    • Do: declare the mode on the tag (data-consent-mode) or grant consent explicitly, and gate your own logic on modeResolved rather than on mode alone.
  • The device cookie is minimal. nox_fp_<siteKey> now carries only the state schema version, the device id and the time of the last submit, which is what recovery of the device id and its cache lifetime need. The last result (risk score, level, confidence, flags) stays in localStorage and IndexedDB. A cache hit recovered from the cookie alone returns cachedResult: null.
    • Who: sites that describe cookie contents in a cookie notice, and code that reads cachedResult after the cookie was the only surviving storage.
    • Do: update the notice wording, and treat cachedResult: null as a prompt to check again.

SDK 3.8.0 (2026-10-12), Breaking

loadExtensions() resolves a result object instead of a boolean. An object is always truthy, so if (await client.loadExtensions()) and === true no longer test success.

Changed

  • loadExtensions() never rejects and resolves a result. This covers client.loadExtensions(options), the static NoxticaCollector.loadExtensions() and noxtica('loadExtensions', options). Success is { ok: true, loaded: string[] }, where loaded is the extensions script URL the core injected ([] on the combined bundle, or when a tag you added yourself attached the runtime); later calls resolve the same shape without a second fetch. Failure is { ok: false, reason, code, url?, status?, error? }: reason is a closed set, code is the finer machine-readable cause, url is the attempted file, status the HTTP status when one was seen and error human text that you should not parse.
  • The extensions events carry the result. noxtica:extensions-loaded and noxtica:extensions-failed now have detail of { message: 'attached' | 'not-loaded', ...result }. In 3.6.0 and 3.7.0 the detail was that string; read it from detail.message. Only a real load attempt dispatches noxtica:extensions-failed.
  • loadExtensions({ requireConsent: true }) refuses to fetch in a gated mode (API or cookie) while no category is granted and answers { ok: false, reason: 'consent_missing', code: 'consent_required' }. The plain call needs no consent, as before.
reasonMeaning
consent_missingOnly with requireConsent: true, or when a queued call was dropped because every category is denied (3.8.1). Nothing is fetched.
csp_blockedAn enforced Content-Security-Policy violation blocked the script URL. code is the effective directive (script-src-elem or script-src).
integrity_mismatchThe browser rejected the pinned file and its hash differs from the pin (code: sha384_mismatch).
networkThe file could not be fetched (code: http_<status> or fetch_failed).
timeoutNo load or error event within 20 seconds (code: script_timeout). The next call retries.
already_loadedA script tag for the URL is already in the page but nothing registered (code: script_present). Nothing is injected.
unknownEverything else, for example a build mismatch or a hand-off error.

The reason is best effort: the browser’s error event carries no cause, so a failed script costs one extra diagnostic request for the same file. A Content-Security-Policy whose connect-src also blocks that request reads as network.

  • Who: code that tests the return value, or that reads the detail of the extensions events as a string.
  • Do: test result.ok, log result.reason and result.code when it is false, and read the old string from detail.message. With @noxtica/sdk, move to 0.3.0 for the matching types.

SDK 3.7.0 (2026-10-09)

Additive. A page that uses none of it behaves as 3.6.0, except that the first core or combined bundle publishes window.noxtica.v (creating the command-queue stub when the page defined none) and getConsent() and noxtica:consent-changed details carry privacySignal.

Added

  • Session API. setTag (replaces a key’s values), hashed identify (the raw id is never stored or sent), event, getMetadata, upgrade, and a byte-capped pre-roll for conditional recording. Queue commands: set, identify, event, metadata, upgrade.

  • Session lifecycle. pause(), resume(), stop() and start() on the client and as queue commands. All are idempotent.

  • Google Consent Mode v2 bridge. data-consent-mode="gcm", createClient({ consentMode: 'gcm' }), client.enableGoogleConsentMode() or noxtica('consent', 'gcm') make the collector follow analytics_storage.

  • GPC and DNT on the tracker and console lanes. With the default signed policy (honor), a visitor who sends Global Privacy Control or Do Not Track gets neither the tracker nor console-log capture. getConsent().privacySignal reports 'gpc', 'dnt' or null, as a local flag that is never sent. The documented_override policy runs both lanes.

  • Duplicate-tag guard (NX001). The first core or combined bundle on a page claims it and sets window.noxtica.v. A second one logs NX001 and is refused, so no second client is created.

  • Who: everyone gets window.noxtica.v and privacySignal; the rest is opt-in. Pages with two collector tags (a hand-pasted tag plus a tag-manager copy) now see the NX001 warning and only the first one runs.

  • Do: remove the extra tag if you see NX001. If your tracker lane must also run for visitors who send GPC or DNT, review the domain policy before you upgrade.

SDK 3.6.0 (2026-10-08)

Additive. A page that uses none of it behaves as 3.5.2; the visible differences are that window.noxtica is installed as a function by auto-init and noxtica:ready is dispatched.

Added

  • noxtica:ready on document (detail: { client }), dispatched once per auto-init tag after the queue ran and before the automatic page check starts. A page without data-auto-init gets neither the event nor the queue.

  • The window.noxtica command queue (the gtag pattern): define window.noxtica = window.noxtica || function () { (window.noxtica.q = window.noxtica.q || []).push(arguments); } before the core loads. The core replays the queue in order against the first client it creates, then makes window.noxtica(...) live. Commands: setConsent, loadExtensions, protect, checkOnce. Unknown commands log a warning, and failures go to noxtica:error instead of throwing.

  • noxtica:consent-changed (detail is the getConsent() snapshot), dispatched only when a consent category really changes.

  • noxtica:extensions-loaded and noxtica:extensions-failed, dispatched by the core (never by the combined or extensions bundles). The detail was the string 'attached' or 'not-loaded'; since 3.8.0 it is the result object.

  • Same-page re-collect is evented. In API or cookie mode, a page check skipped for consent (noxtica:collected with skipped: 'consent_required') runs again with its original options when deviceId is granted later on the same page, and announces noxtica:collected (and noxtica:cache-hit when the cache answers it).

  • Who: pages that want to react to readiness, consent or extension loading without polling, and consent banners that load after the collector.

  • Do: adopt noxtica:ready and the queue when convenient.

SDK 3.5.2 (2026-10-05)

Additive; completes 3.5.1 of the same day.

Changed

  • The legacy URLs serve the core. /collector/noxtica-collector.js (3.5.1) and /collector/noxtica.js (3.5.2) return the same bytes, content type, CORS headers and cache class as /collector/noxtica-collector-core.js. A core evaluated from a legacy URL defaults extensions to 'auto': the extensions load immediately in consent mode not_required, and on the first category grant in API or cookie mode. An explicit extensions option or data-extensions value still wins (any value other than auto opts out), and the core URL itself keeps the manual default.

  • Pinned combined builds keep working. The combined bundle is still built, and its hashed file keeps serving the combined bytes for existing integrity pins. asset-manifest.json adds servedAs and deprecated entries for the legacy and combined files.

  • Who: pages that still load a legacy URL. Before the extensions attach, extension-lane client methods (track, tracker and replay setters) run the core’s reduced lane and are not replayed after the hand-off; maskTextFn and maskInputFn apply only once the extensions runtime owns the client.

  • Do: nothing is required. Move to the core tag plus extensions when convenient, as described on Install and Browser Runtime.