---
title: Identifying users
description:
  "The identity object for Feeblo.identify: fields, companies, and custom attributes."
---

A name and email on every piece of feedback makes it actionable. Identify calls attach a
user to everything they do in the widget.

## The identity object

`UserIdentity` takes these fields:

| Field          | Required | Purpose                                                       |
| -------------- | -------- | ------------------------------------------------------------- |
| `id`           | yes      | Your user's ID in your own system                              |
| `email`        | no       | Shown to your team on posts and replies                        |
| `name`         | no       | Display name                                                   |
| `avatar`       | no       | Image URL                                                      |
| `customFields` | no       | Values mapped to the custom attributes you define in Feeblo    |
| `companies`    | no       | Accounts or organizations: `id`, `name`, `avatar`, `customFields` |
| `token`        | no       | Signed JWT that verifies the identity; see [Widget SSO](/developers/widget-sso) |

Calling `identify` without `id` throws an `EmbedError` with code `INVALID_IDENTITY`.

## Identifying in your app

**Vanilla JS**

```ts
Feeblo.identify({
  id: "u_1",
  email: "ada@example.com",
  name: "Ada Lovelace",
});
```

Call it again any time the user's details change. The last call wins.

**React**

Pass the identity as the `user` prop on `FeebloProvider`. Changes call `identify` on the
live widget without remounting anything:

```tsx
<FeebloProvider organizationId="org_123" user={currentUser}>
  <App />
</FeebloProvider>
```

:::warning[Signing out is manual]
In React, setting `user` back to `undefined` does not sign the user out. The SDK has no
clear-identity API, so the last identified user stays active until you mount a different
identity or unmount the provider.
:::

## Custom fields

Custom fields let your team slice feedback by facts you already know about users and
their companies: plan tier, industry, seat count, whatever matters to you.

They are configurable. You define custom attributes for contacts and companies in
Feeblo, then send values under `customFields`, keyed by attribute:

```ts
Feeblo.identify({
  id: "u_1",
  email: "ada@example.com",
  name: "Ada Lovelace",
  // Optional. Keys must match custom attributes you defined in Feeblo.
  customFields: {
    plan: "enterprise", // your "plan" attribute
    role: "admin",      // your "role" attribute
  },
  companies: [
    {
      id: "c_1",
      name: "Acme",
      customFields: {
        industry: "SaaS",     // your company-level "industry" attribute
        seats: 250,
      },
    },
  ],
});
```

Two rules the server applies:

- Values sent under keys with no matching definition are ignored.
- A definition marked **required** must be present in every identify call, or the
  identity fails validation.

## Identity and submissions

Users who have not been identified can still open the widget and submit. Their post
arrives unattributed. When you want posts tied to a verified user, hand out signed
tokens. [Widget SSO](/developers/widget-sso) covers signing and automatic board login.

## Next steps

<CardGroup cols={2}>
  <Card title="Widget SSO" href="/developers/widget-sso">
    Signed JWTs, claims reference, and signing users into your public board.
  </Card>
  <Card title="Configuration" href="/developers/configuration">
    Modes, placement, debug logging, and every init option and provider prop.
  </Card>
</CardGroup>
