> ## Documentation Index
> Fetch the complete documentation index at: https://docs.corbado.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Send User References to Corbado Observe

> Attach your authentication system's user reference to an Observe flow with the SDK.

User references connect Observe flows to the user IDs your authentication system supplies. This page explains how to send those references from the SDK.

For the meaning of a user link, failed attempts across devices and identifier search, start with [Users and identifiers](/corbado-observe/overview/users-and-identifiers).

<Frame>
  <iframe className="w-full aspect-video rounded-xl" src="https://www.youtube.com/embed/1mQBtnjtNLw" title="Debug any Passkey User in Seconds | Corbado Observe" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen />
</Frame>

## 1. Why user mapping matters

Adding user information to events helps you:

* Group multiple flows (for example login retries and recovery) under the same user
* Analyze authentication behavior in a per-user view
* Connect anonymous pre-login events with known users as soon as identity is available

User references are strongly recommended because they power reliable per-user analysis in **Corbado Observe**.

## 2. User reference model

**Corbado Observe** supports these user reference fields:

* `userId`: Your stable internal user ID
* `identifier`: Deprecated. A flow-level user-facing reference that existing integrations can keep sending; new code captures identifiers on the provide-identifier step instead
* `crossEnvironmentTransactionID`: Optional correlation ID for cross-device or email-link flows

Prefer your stable `userId` for user enrichment. Capture submitted emails, phone numbers and usernames separately on the [provide-identifier step](/corbado-observe/tracking/subflows#3-1-provide-identifier) so each submission remains searchable, including typos, changes and failures.

You can send a stable hash as `userId`. User lookup and connecting journeys to the same user still work; matching exports to your own records requires the same hashing configuration or a mapping. Alternatively, send the clear user ID and let a [data policy](/corbado-observe/security/privacy#3-data-policies) hash it later. Keep hashing secrets in your backend, outside browser scripts and mobile apps.

User reference fields are limited to `userId`, `identifier` and `crossEnvironmentTransactionID`.

## 3. Send user references from the SDK

Call `setUser()` on the tracker as soon as the identity is known, while the flow is open. The SDK records it as a `flow_enriched` event on that flow, and the classifier attaches it to the flow and to every attempt inside it. Call it before `flowFinished()`. One call per identity observation is enough; the latest reference per flow wins.

Choose the point at which your authentication system supplies the reference:

* **When the host confirms the user:** Send the `userId` with the login result, before finishing the flow.
* **When an enrollment flow starts:** The user is already logged in, so the reference is known at `flowStarted()`.
* **When the host resolves an account before authentication:** An early user reference can identify the account being targeted. Its presence alone does not establish who made the attempt or prove ownership of a submitted identifier.

Failed attempts remain searchable through their captured identifier submissions even without a confirmed user. Later user enrichment retains those submissions. A qualified identifier-to-user link is a separate relationship; see [the evidence rule](/corbado-observe/overview/users-and-identifiers#3-from-a-submission-to-a-user-link).

Passing `userId` or `identifier` inside `flowFinished()`, `flowAutoFinished()`, `conversion()` or the `userReference` step option still works and is deprecated. Use `setUser()` in new code.

For SDK installation and setup, see [Integrate custom events](/corbado-observe/get-started/custom-events).

<Tabs>
  <Tab title="NPM">
    ```typescript theme={null}
    import { init, getTracker } from "@corbado/observe";

    init({
      projectId: "<ProjectID>",
      apiBaseUrl: "<APIBaseURL>",
    });

    getTracker().flowStarted({ flowName: "login" });
    // ... your authentication system confirms the login
    getTracker().setUser({ userId: "usr_12345" });
    getTracker().flowFinished({ flowName: "login" });
    ```
  </Tab>

  <Tab title="CDN">
    ```html theme={null}
    <script>
      Corbado.init({
        projectId: "<ProjectID>",
        apiBaseUrl: "<APIBaseURL>",
      });

      Corbado.get().flowStarted({ flowName: "login" });
      // ... your authentication system confirms the login
      Corbado.get().setUser({ userId: "usr_12345" });
      Corbado.get().flowFinished({ flowName: "login" });
    </script>
    ```
  </Tab>
</Tabs>

### 3.1 Identity learned after the flow finishes

Keep the handle returned by `flowStarted()` or `flowFinished()` when identity arrives asynchronously after completion. `handle.enrich()` targets that journey, including after a session change, while the tracker remains alive. Calling `setUser()` after completion targets the currently open flow and cannot enrich the finished one.

```typescript theme={null}
const tracker = getTracker()!;
const journey = tracker.flowStarted({ flowName: "login" });
// Your authentication completes.
tracker.flowFinished({ flowName: "login" });
// Once the host supplies the identity for this journey:
await journey.enrich({ userId: "usr_12345" });
```

The promise confirms tracking and enqueueing, not server delivery. This targets the named journey; it does not identify unrelated later flows or prove ownership of an identifier.

## 4. Best practices

* Prefer your immutable internal user ID for `userId`, in clear text or as a stable hash according to your policy
* Capture identifiers per submission for debugging and support workflows
* Send the same user reference consistently across all relevant auth events
* Do not use tags for identity mapping; use tags for segmentation

## 5. Next steps

* Continue with [Tags](/corbado-observe/tracking/tags) to add optional segmentation metadata.
* Continue with [Flows](/corbado-observe/tracking/flows) to model complete user journeys.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.