Skip to main content
The Observe data layer is the recommended way to integrate Corbado Observe from your own source code. Your screens carry one data attribute per control, your code pushes a few events into window.CorbadoObserve, a small in-page command queue with the mechanics of an analytics data layer, and network calls and WebAuthn ceremonies are captured automatically in your page. One central module, the mapping, takes the queue over and emits the Observe events for your flows, decisions and subflow steps. No tracking calls are scattered through your components, the whole tracking model lives in one place, and that place can be updated without an app release.
The data layer is web only. On iOS and Android, the native SDKs follow the same split through typed hooks. If you do not want to change your frontend at all, Autocapture is the fully managed option.
Prefer an AI coding agent? The Corbado Observe skill implements the data layer and the mapping for you, including the replay tests.

1. Prerequisites

  • An active project in the Corbado management console. No project yet: Create a new project, project type Observe.
  • Your Project ID and API Base URL from Observe → Settings → General, or from corbado switch --list after pairing the Observe CLI.
  • Your authentication origins registered under Observe → Settings → Origins.

2. How it works

The mapping sees three families of events, dom, network and webApi, and two of them are the capture library’s own objects. That is the same input an Autocapture adapter works from, which is what lets Corbado review, test and correct the tracking model with you without touching your components.

3. Add the stub

Inline it as the first script in <head>, before any application code. Do not put it behind a feature flag or a consent gate. It only records commands in memory, and nothing leaves the page before the mapping runs.
The empty loader URL is the compiled-in case. With script-tag delivery Corbado issues the same stub with your loader URL rendered in.

4. Tag your screens and emit

Every control that offers a decision option gets data-observe-decision-option with the Observe option string. The primary input gets data-observe-input. A screen offer is then a visibility scan. There is no list of options to maintain in code:
Four rules keep the offers right:
  • Emit per presentation, from one place per screen. In a single-page app this is the screen component’s mount, delayed by one microtask. In a multi-page app it is the page load. A framework re-render alone is no new presentation.
  • Re-emit with the same timestamp when a control appears later, such as a passkey button behind a capability check. The mapping discards an unchanged set and replaces the open decision in place when the set changed. If unsure, emit.
  • Emit after the previous screen’s requests settled and before the new screen starts anything, a ceremony or a request. Screens drive the mapping’s state machine.
  • Resolve outcomes explicitly in the handler, for method choices and navigation alike, before the request they start.
Method option strings are fixed by Observe, for example password-login-known-identifier or passkey-login-known-identifier. Navigation options are names you choose, such as back or recovery. The decisions reference lists the strings each method resolves.

5. Capture network and WebAuthn in your page

Requests and ceremonies make up the majority of an integration’s signals and carry its error detail. They are captured automatically. Wire the capture library once, in the first module your bundle evaluates, so that it runs before your first authentication request:
The projectors are your privacy boundary. Without a projector no body is read, and a projector returns only the fields the mapping needs, such as a status, a step name or an error code. Identifiers, passwords, one-time codes and raw bodies never enter the queue. WebAuthn payloads are sanitized by the capture library.
If your organization does not allow patching fetch, your API client can push network events itself, with the same shape. You then decide what the mapping gets to see, and only that reaches the error analytics. Do not run both.

6. Lifecycle commands

Whether recording into the in-page queue before consent is acceptable is your own legal assessment. The queue holds no identity until consent, and your projectors keep identifiers out of network events. See storage and consent. The full contract, the emission rules and the mapping’s tables are in the Corbado Observe skill.

7. The mapping

The mapping is a self-contained module with a fixed layout: a contract file shared with your emitters, a taxonomy file holding the tables that translate your screen names and endpoints into Observe’s flow names, decision names and subflow steps, a coordinator that derives flow starts, finishes and skips from those tables, and one state class per screen. It imports only its contract and @corbado/observe. It does not import your app and does not touch browser APIs. Corbado provides a sample skeleton for your stack, and the agent skill writes it against your journeys. The maintenance split follows from that layout. The markup, the emitters and the capture wiring are your code and evolve with your screens. The mapping is the single place where tracking logic lives, and it can be maintained by you or together with Corbado. If you want Corbado to own the whole thing, including reconciling the tracking after your releases, without any code changes on your side, that is Autocapture. Delivery is a separate choice, made before go-live, and it does not change your app code: Start locally, switch later. A new integration starts compiled in, because no Corbado-hosted bundle exists for your app yet, and the switch does not touch your markup, emitters or capture wiring:
1

Compiled in

Install @corbado/observe and @corbado/autocapture, inline the stub above, import the capture wiring and the mapping module first thing in your app entry, and call CorbadoObserve.init() right after.
2

Script tag

The same mapping module is built as a self-contained bundle and hosted behind a loader. Remove the import and the @corbado/observe dependency, and use the stub Corbado issues with your loader URL. Everything else stays as it is.
Script-tag delivery is set up together with Corbado: we host the bundle, verify a new version by injecting it into your live page in a test browser and replaying recorded journeys, and only then point the loader at it. Talk to us when you approach go-live.

8. Verify

Because the mapping’s input is the stub’s queue, a plain array that now carries screens, outcomes, exchanges and ceremonies alike, tracking logic is testable by replay. Dump window.CorbadoObserve.q for a journey once, store it with the Observe events it must produce, and run it against every mapping change. The skill describes the fixture format. Then walk the real app with debug: true, confirm the emitted series with the Corbado Observe Debugger and check the result against the backend: with the Observe CLI through events-feed, classify and classification-errors, or in the console under Observe → Debugging → Integration with the Process button. See Verify your integration.

9. Next steps

Use with AI agents

Let the skill implement the data layer and the mapping.

Model your journeys

The tables the mapping is built from.

Observe CLI

Pair your project and verify classification from the terminal.

Verify your integration

Confirm events arrive before you ship.