# User attributes

> How StepsKit user attributes work: any data-user-* attribute is supported, used for tour targeting. Pass at minimum data-user-id for frequency capping and visitor identification.

*Source: https://stepskit.com/docs/concepts/user-attributes*

User attributes are key/value pairs describing the current visitor. You
use them in the dashboard to target tours — for example: only show this
tour to users on the Free plan, or only to admins, or only to people in
a specific company.

## What you can pass

Anything. StepsKit doesn't have a fixed schema. Any `data-user-<key>`
attribute on the script tag becomes a `key` in the attribute object, and
any key you pass to `setUserAttributes` is queryable in targeting rules.

Common ones we recommend:

| Key       | Why                                                            |
| --------- | -------------------------------------------------------------- |
| `id`      | Required for "show once" rules — uniquely identifies a visitor |
| `email`   | Lets you target individuals during testing                     |
| `plan`    | Common for upgrade tours                                       |
| `name`    | Useful for personalization inside tour copy                    |
| `company` | Useful for B2B targeting                                       |
| `role`    | Lets you target admins vs viewers                              |

But you can pass `data-user-signup-date`, `data-user-team-size`, or
anything else your product needs to target on.

## Two ways to set them

### Via the script tag (server-rendered, snippet install only)

Render attributes into the script tag when you serve the page.

```html
<script
  src="https://cdn.stepskit.com/stepskit.latest.js"
  data-api-key="YOUR_API_KEY"
  data-user-id="user_123"
  data-user-plan="pro"
  async
></script>
```

Keys are kebab-case in HTML and camelCase in the resulting object:
`data-user-team-size="42"` becomes `{ teamSize: "42" }`.

### Via setUserAttributes (client-side, any install)

For SPAs and any case where attributes change after page load. With the
[npm package](/docs/install.md) you import the API; on a snippet install
the same methods live on `window.stepskit`.

```ts
import stepskit from "stepskit";

await stepskit.setUserAttributes(
  {
    id: user.id,
    plan: user.plan,
    teamSize: user.team_size,
  },
  { autoRefresh: true },
);
```

`setUserAttributes` is a merge: keys you don't pass keep their previous
values. Call `setUserAttributes({}, { autoRefresh: true })` if you only
need to trigger a refresh.

## Types and values

Attribute values can be strings, numbers, or booleans. Anything else
will be coerced to a string. Targeting rules can match exact values, do
case-insensitive string comparisons, and check membership.

## What if I don't set any attributes?

The tour still loads, but it's treated as an anonymous visitor. Tours
that target specific users won't fire, and "show once" rules degrade to
a session-scoped check. For meaningful targeting and frequency capping,
pass at least `id`. See
[Visitor identification](/docs/concepts/visitor-identification.md).

This is the most common way a StepsKit install ends up half-working: the
embed is live, every health check is green, and nothing is targeted. If
you're using an AI coding agent, the
[install prompt](/docs/ai-agents/install-prompt.md) wires attributes for you
from whatever your user object already carries.
