---
title: "Custom events, session tags and request tracing"
description: "Send custom events, tag and identify sessions without sending raw ids, and join a browser request to your backend with W3C trace headers."
canonical_url: "https://noxtica.com/docs/observability/events-and-tracing/"
markdown_url: "https://noxtica.com/docs/observability/events-and-tracing/index.md"
last_updated: 2026-10-27
published: 2026-10-27
section: "observability"
section_title: "Observability"
site: "Noxtica"
language: "en"
source: markdown
---

# Custom events, session tags and request tracing

This page is for a web developer who wants to add context to what Noxtica records: named events from your own code, tags and a hashed identity on a session, and a trace header that links a browser request to your backend. A tenant administrator allow-lists what the domain accepts.

## What it is

Availability depends on your plan, role and the modules enabled for your organisation. Events and tags ride on the behavior analytics and session replay lanes, which run when enabled for your organisation.

| API | Where you call it | What it does |
| --- | --- | --- |
| `track(name, properties)` | `window.noxticaClient` | Sends a custom app event. The domain's allow-list decides what is kept. |
| `noxtica('event', name, value)` | Command queue | Adds a replay timeline marker and sends an app event named `name` with a `value` property. |
| `noxtica('set', key, value)` | Command queue | Tags the session with a key and one or more values. |
| `noxtica('identify', id, { hint })` | Command queue | Links the session to a hashed identity. The raw id never leaves the page. |
| `noxtica('metadata', callback, options)` | Command queue | Hands your code the Noxtica session ids. |
| `noxtica('upgrade', reason)` | Command queue | Asks replay to start now, within the policy. |
| `withRequestSpan(url, callback)` and `spanFetch(url, init)` | `window.noxticaClient` | Add a W3C `traceparent` header to a request to an allow-listed origin. |

The command queue also takes `pause`, `resume`, `stop`, `start` and `consent`. The queue is documented in [Client API, events and the command queue](https://noxtica.com/docs/sdk/client-api/).

Three limits shape everything on this page:

- Events and tags are not delivered when the visitor has not consented to the `analytics` category (events) or `replay` category (tags and the replay timeline) in a consent-gated mode.
- A visitor who sends Do Not Track or Global Privacy Control is excluded when the domain policy is Honor.
- Nothing here bypasses consent, sampling or the replay minimum duration.

## Prerequisites

- **Scripts.** The core and extensions scripts load on the page. The tracker, replay and session API run from the extensions. See [Install & Browser Runtime](https://noxtica.com/docs/browser-runtime/).
- **Events.** The domain's **Tracker** switch and its **App events** switch are on, and the domain has an allow-list. The Admin role changes them.
- **Tags and the timeline.** Replay is armed for the domain. See [Session replay: setup, masking and playback](https://noxtica.com/docs/observability/session-replay/).
- **Tracing.** The domain lists the exact origins that may receive a trace header. The Admin role and a fresh step-up verification change the list.
- **Consent.** Your banner grants the categories the features need. See [Consent modes, GPC and Google Consent Mode](https://noxtica.com/docs/sdk/consent/).

## Steps

### 1. Define the command queue before the core script

```html
<script>
  window.noxtica = window.noxtica || function () {
    (window.noxtica.q = window.noxtica.q || []).push(arguments);
  };
</script>
```

The core replays queued calls in order once it starts, then replaces the stub with a live function. An unknown command name logs a warning and does nothing. A failing call reports through the `noxtica:error` event and never throws into your code.

### 2. Allow-list events and properties

Backoffice → Administration → Domains → open the domain → **Configuration** → **Tracker policy**. Switch on the domain's **Tracker** and **App events**. The **Tracker** switch is also in the **Tracker** column of the Domains list.

Backoffice → Web Analytics & Privacy → **Tracking Allowlists** → **Tracker app-event allowlists**.

1. Pick the domain.
2. Choose **Restrict to an allowlist** under **Event name allowlist** and add names such as `checkout_completed`.
3. Do the same under **Property key allowlist** for keys such as `plan`.
4. Select **Save allowlists** and complete the step-up verification.

How the lists act:

| Mode | Behaviour |
| --- | --- |
| **Accept all (legacy default)** | Every name and property is accepted. Domains created before the allow-list existed start here. |
| **Restrict to an allowlist** | An event whose name is not listed is dropped on the server, and the rest of the batch is unaffected. A property key that is not listed is stripped, and the event is kept. |
| **Deny-all** | An empty restricted list. Every event is dropped. A newly created domain starts here. |

Each list holds up to 200 entries of up to 128 characters. A save over the limit is rejected, never truncated. The data of one event is limited to 1 KB.

### 3. Send events

```js
// A custom event with properties. Throws a TypeError for an invalid shape.
window.noxticaClient.track('checkout_completed', { plan: 'pro' });

// A timeline marker plus an app event named 'coupon_applied'.
noxtica('event', 'coupon_applied', 'SPRING');
```

- `track` needs a non-empty string name and a plain object for `properties`.
- `noxtica('event', name, value)` takes a name up to 128 characters. The value is a string (cut at 256 characters), a finite number or a boolean. The event reaches the app-event lane as `track(name, { value })`, so list `value` in the property allow-list to keep it.
- The browser buffers up to 50 events and flushes about every 10 seconds.
- Timeline markers appear in the recording while the recorder is active.

### 4. Tag sessions

Allow the keys before you set tags. Backoffice → Web Analytics & Privacy → **Capture Policies** → **Session replay policy** → **Session tag keys (allow-list)**: up to 32 keys. An empty list turns tags off for the domain.

```js
noxtica('set', 'plan', 'pro');
noxtica('set', 'cohort', ['north', 'eu']);
```

| Rule | Limit |
| --- | --- |
| Key pattern | `A-Z a-z 0-9 _ . : -`, 1 to 64 characters |
| Value | A string, number or boolean, up to 255 characters |
| Values per key | Up to 128 distinct values |
| Keys per session | Up to 32 |

A call replaces the values of that key. An empty list removes the key. An invalid key throws a `TypeError`. A key that is not on the allow-list is dropped. Tags are free text. The server redacts values that look like email addresses or long digit runs, and you should not put personal data in a tag. Tags are attached to the recorded session and need an active recorder.

### 5. Identify a session without sending the raw id

```js
noxtica('identify', 'user-8841', { hint: 'us' });
noxtica('identify', null); // clear the identity
```

The browser sends the SHA-256 of the trimmed id (lowercase hex) and a 2-character hint, such as `us***`. The id may be up to 256 characters. If the browser has no WebCrypto, which is the case on an insecure page, the call does nothing and the raw id is still never sent.

This is the session identity. It is separate from the account id that links a device to a verdict, which you set with `window.noxticaClient.setAccountId(id)`. See [Client API, events and the command queue](https://noxtica.com/docs/sdk/client-api/).

### 6. Read the Noxtica session ids

```js
noxtica('metadata', function (meta) {
  // meta.sessionId, meta.replaySessionId (null until a recording starts),
  // meta.pageId, meta.consent
  myLogger.setContext({ noxticaReplay: meta.replaySessionId });
}, { wait: true, recall: true });
```

`wait` defers the call until a replay session id exists. `recall` calls it again whenever the id changes.

### 7. Start replay now, within the policy

```js
const result = noxtica('upgrade', 'support-chat-opened');
```

The call returns `started`, `already_recording`, `pending_consent` or `refused`. The reason uses the tag-key pattern. It never grants consent, never overrides Do Not Track or sampling, and the minimum duration still applies.

### 8. Allow-list trace origins

Backoffice → Web Analytics & Privacy → **Tracking Allowlists** → **RUM trace controls** → **Trace-origin allowlist**. Add an exact origin: `https://host` with an optional port, with no path and no wildcard. An IP address is rejected, except loopback addresses for local development. The list holds up to 20 origins. Select **Save trace controls**.

### 9. Trace a request

```js
const client = window.noxticaClient;

// Option A: you control the request.
await client.withRequestSpan('https://api.example.com/orders', async ({ headers, span }) => {
  const res = await fetch('https://api.example.com/orders', { headers });
  span.end(res.ok ? 'ok' : 'error');
});

// Option B: let Noxtica issue the request.
const { followed, response, span } = await client.spanFetch('https://api.example.com/orders');
```

- For an allow-listed origin, `headers.traceparent` is set (`tracestate` may be present). For any other origin the callback still runs with empty headers and a no-op span, and the request is not blocked.
- There is no global fetch or XHR patch. You opt in per call.
- The ids are fresh W3C ids. No Noxtica session, tenant or user id enters the header.
- A span ends as `ok` when your callback finishes. A throwing callback ends it as `error` and the error is rethrown. An async callback is awaited for up to 5 seconds.
- `spanFetch` never follows a redirect. On a 3xx it returns `followed: false` and an opaque response. Start a new call for the redirect target.

Your backend continues the trace by reading the `traceparent` header. If it exports OpenTelemetry data to Noxtica, see [APM and the ingestion service (OTLP)](https://noxtica.com/docs/observability/apm-and-ingest/).

### 10. Tag releases

Pass `release` and `buildId` when you create the client. See [Browser errors, console logs and source maps](https://noxtica.com/docs/observability/errors-and-source-maps/).

## Verify it works

1. In Backoffice → Session Insights → Behavior Analytics → Overview, the **App events** feature shows counts after a visit.
2. In a replay of the session, the timeline shows your `event` markers, and the session shows your tags.
3. In the browser network panel, a request to an allow-listed origin carries a `traceparent` header. A request to another origin carries none.
4. `noxtica('metadata', console.log)` prints `sessionId`, `pageId` and `consent`.

## Troubleshooting

| Symptom | Cause | Fix |
| --- | --- | --- |
| An event never appears | Its name is not on the allow-list, **App events** or **Tracker** is off, the visitor has not consented to `analytics`, or Do Not Track or Global Privacy Control is honored. | Check steps 2 and 3, and the consent state. |
| An event arrives without a property | The property key is not on the allow-list. | Add the key. For `noxtica('event', ...)` add `value`. |
| `track` throws a `TypeError` | The name is empty or `properties` is not a plain object. | Pass a non-empty string and an object. |
| A queued call logs `noxtica:error` | The key, value or reason failed validation. | Match the patterns in the table. |
| A tag is missing | The key is not in **Session tag keys (allow-list)**, the list is empty, or no recorder is active. | Add the key, and arm replay. |
| `identify` does nothing | The id is blank or over 256 characters, or the page has no WebCrypto. | Use a secure page and a valid id. |
| No `traceparent` header | The origin is not allow-listed. The request still runs without a header. | Add the exact origin in step 8. |
| `upgrade` returns `pending_consent` or `refused` | Consent has not been decided, or the recorder cannot start. | Grant the `replay` category. See the replay page. |

## Related

- [Client API, events and the command queue](https://noxtica.com/docs/sdk/client-api/) — the full client surface.
- [Session replay: setup, masking and playback](https://noxtica.com/docs/observability/session-replay/) — tags and markers show up in recordings.
- [Behavior analytics: heatmaps, journeys and funnels](https://noxtica.com/docs/observability/behavior-analytics/) — funnels are built from your app events.
- [APM and the ingestion service (OTLP)](https://noxtica.com/docs/observability/apm-and-ingest/) — backend traces.
- [Single-page apps, frameworks and tag managers](https://noxtica.com/docs/sdk/single-page-apps/) — call these APIs from a framework.
