Skip to main content
FirstFlow trusts the identity you give it your own auth verifies who the user is. The user you pass to the provider sets the subject for frequency caps, resume, and persisted rows, and its traits drive targeting and branching.

Identified users

id
string
required
Your stable user identifier. Becomes the user_id on persisted runs and the key for once_per_user caps and resume.
traits
Record<string, unknown>
Arbitrary values for audience targeting and branch conditions, addressed as traits.<key> in when clauses.

Anonymous visitors

Omit user (or pass no id) and the runtime mints a stable per-browser anonymous id, persisted in localStorage, so caps and resume work before sign-in.
  • The id survives reloads a returning visitor keeps one identity.
  • Anonymous users carry traits.anonymous === true. Target them with when: { "traits.anonymous": true }, or exclude them.
  • Read or reuse it directly:

Targeting with traits

Traits flow into when conditions on triggers and step branches:
To use a server-classified intent inside a flow, pass it as a trait (traits.intent) and branch on it. See the server classifier.

Linking to the server SDK

The runtime persists experiences by user.id only it has no conversation id and no backend channel. To tie a person’s experiences to their LLM activity, pass the same user.id to FirstflowProvider and to your server-side calls. The conversation id (called sessionId on the server) is separate: your own chat code owns it and passes it to the server SDK to group a transcript. The provider is not involved.