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

# identify()

> Associate the current browser session with a known user ID and optional attributes for targeting.

## Signature

```typescript theme={null}
window.zenstep.identify(
  userId: string,
  attributes?: UserAttributes
): void

interface UserAttributes {
  [key: string]: string | number | boolean | undefined;
}
```

***

## Parameters

<ParamField path="userId" type="string" required>
  Your application's unique identifier for this user. This is the ID from your own database — a UUID, numeric ID, or any string that uniquely identifies the user.

  **Max length:** 512 characters.

  Do not pass PII (email, name) as the `userId`. Use the `attributes` object for those values if needed for targeting.
</ParamField>

<ParamField path="attributes" type="object">
  Key-value pairs describing the user. Values must be `string`, `number`, or `boolean`.

  Attributes are used in targeting rules — for example, show a flow only to users with `plan: "free"`, or only to `role: "admin"` users.

  **Supported value types:**

  * `string` — `"grow"`, `"admin"`, `"2024-09-01"`
  * `number` — `42`, `3.14`
  * `boolean` — `true`, `false`
  * `undefined` — silently ignored (attribute is not set)
</ParamField>

***

## Examples

### Basic identification

```javascript theme={null}
window.zenstep.identify("user_abc123");
```

### With attributes

```javascript theme={null}
window.zenstep.identify("user_abc123", {
  email: "ada@example.com",
  plan: "grow",
  role: "admin",
  company: "Acme Corp",
  seats: 5,
  trialExpired: false,
  createdAt: "2024-09-01",
});
```

### Re-identification after plan change

Call `identify()` again whenever user attributes change. Zenstep merges the new attributes with the existing identity — it does not replace the full object.

```javascript theme={null}
// User upgrades plan
window.zenstep.identify(currentUser.id, { plan: "scale" });
```

***

## Attribute targeting reference

Once you've called `identify()`, attributes are available in **targeting rules** under **User Attribute** condition type.

| Attribute key  | Example value | Targeting use                          |
| -------------- | ------------- | -------------------------------------- |
| `plan`         | `"free"`      | Show upgrade prompt only to free users |
| `role`         | `"admin"`     | Show admin-only onboarding             |
| `company`      | `"Acme Corp"` | Show enterprise-specific flows         |
| `seats`        | `5`           | Numeric comparison (seats \< 10)       |
| `trialExpired` | `false`       | Boolean match                          |

***

## When to call identify

Call `identify()` as early as possible after the user authenticates — typically on every page load for authenticated sessions, not just on login. This ensures Zenstep always has the latest user state even after a page refresh.

```javascript theme={null}
// On every page load (inside a layout or app shell)
if (currentUser) {
  window.zenstep?.identify(currentUser.id, {
    plan: currentUser.plan,
    role: currentUser.role,
  });
}
```

***

## Anonymous users

Before `identify()` is called, Zenstep tracks the browser session under an auto-generated anonymous ID. Flows with targeting rules requiring user attributes will not show to anonymous users — but flows with no targeting or URL-only targeting will show to everyone.

***

## Privacy notes

* `userId` is hashed using HMAC-SHA256 before being stored in Zenstep's analytics. The raw ID is never stored.
* Attributes are stored in Zenstep only if you explicitly pass them. Do not pass sensitive PII (passwords, payment info, government IDs).
* Zenstep is GDPR-compliant. See the [data deletion API](/rest-api/authentication) to implement user deletion requests.
