# Install StepsKit with a script tag

> Add StepsKit to any site with a single JavaScript snippet. Identify users with stepskit.identify() to enable tour targeting and frequency capping.

*Source: https://stepskit.com/docs/install/js*

For server-rendered apps, CMSes, tag managers, or any site where you can edit
the markup, the simplest install is one `<script>` snippet.

Building with a bundler? Use the [npm package](/docs/install.md) instead —
it's typed, and there's no snippet to keep in sync. This guide is for sites
with no build step.

## Add the script tag

Place this just before the closing `</body>` tag on every page where you
want tours to be available:

```html
<script>
  (function () {
    var stepskit = window.stepskit = window.stepskit || {};
    stepskit._q = stepskit._q || [];

    // Queue API calls made before the SDK finishes loading.
    var methods = ['identify', 'setUserAttributes', 'track', 'refresh', 'playTour', 'stopTour', 'dismissAnnouncement', 'on', 'off', 'destroy', 'validateEnvironment'];
    methods.forEach(function (method) {
      stepskit[method] = stepskit[method] || function () {
        stepskit._q.push([method].concat([].slice.call(arguments)));
      };
    });

    // Load the StepsKit SDK asynchronously.
    var script = document.createElement('script');
    script.async = true;
    script.src = 'https://cdn.stepskit.com/stepskit.latest.js';
    script.setAttribute('data-api-key', 'YOUR_API_KEY');

    var first = document.getElementsByTagName('script')[0];
    first.parentNode.insertBefore(script, first);
  })();
</script>
```

StepsKit initializes itself once the script loads — no extra wiring
needed.

## Identify the user

Once you have the current user, call `stepskit.identify()` to pass
their details for tour targeting:

```html
<script>
  stepskit.identify({
    id: "user_123",
    email: "user@example.com",
    plan: "pro",
    company: "Acme Inc",
  });
</script>
```

`id` is the one to always pass if you can —
[frequency capping](/docs/concepts/frequency-capping.md) and
[visitor identification](/docs/concepts/visitor-identification.md) both rely
on it.

For static, server-rendered installs you can also pass user details via
`data-user-*` attributes on a plain script tag — StepsKit reads any
`data-user-<key>` attribute and exposes it for targeting:

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

## Anonymous visitors

If you don't have a user object yet (marketing site, signed-out screens),
just leave the `data-user-*` attributes off and skip the `identify`
call. Tours that don't require a specific user will still play, and
"show once" rules degrade gracefully.

## Updating user data after page load

If the user logs in or upgrades plan after the script has loaded, call
`window.stepskit.setUserAttributes()` from JavaScript. See the
[JavaScript API reference](/docs/api.md#setuserattributes).

### Attribute limits

StepsKit validates every attribute you pass via `data-user-*` or
`stepskit.identify()`. The rules below match what the dashboard's
targeting editor enforces. Violations are logged as `console.warn` and
the offending key is dropped — the rest of your payload still goes
through. Check `stepskit.validateEnvironment().warnings` to see the
accumulated drops.

| Limit | Value | Notes |
| --- | --- | --- |
| Attribute name format | `^[a-zA-Z_][a-zA-Z0-9_]*$` | Use snake_case or camelCase. No hyphens, spaces, or leading digits. |
| Attribute name length | 50 chars max | |
| Attribute value type | string, number, or boolean | Nested objects and arrays are dropped. |
| Attribute value length | 500 chars max (strings) | |
| Attributes per call | 20 max | Extras are dropped. |
| Reserved names | `id` (used as visitor identifier), `user_id`, `project_id`, `tour_id`, `step_id`, `session_id`, `created_at`, `updated_at`, `deleted_at` | `id` is allowed and special-cased; the others are blocked. |
