Skip to main content

The script tag

That is the complete install. The tag auto-boots on DOMContentLoaded — you do not need to call init(). The key belongs in the page. It is a publishable key, public by construction; what protects it is the origin check, not secrecy.
Never put a secret key (sk_…) in this tag. The widget endpoints reject secret keys, so it would not work — and it would publish your credential to every visitor.
With no key on the tag, the widget logs one warning and does nothing. It never throws into your page.

Where to put it

On every page you want the agent to work on, including the ones it needs to navigate through. The agent can only act on controls that are on screen, so a page without the widget is a page it cannot walk a user into. defer is recommended — the widget never blocks rendering.

Script tag attributes

Everything below is optional.

Configuration

Identity on the tag

If your server renders the page and already knows who the user is, you can put identity straight on the tag instead of calling identify():
Available: data-user-id, data-user-email, data-user-name, data-user-company, data-user-plan, data-user-phone, data-user-created-at. Empty attributes are ignored.
A programmatic identify() call wins over the tag. The tag’s identity is adopted only when identify() has not already recorded one — so an interactive login updates identity correctly without you clearing anything.

Configuring with a global instead

If setting attributes is awkward in your framework, set window.PeeveConfig before the script loads:
Precedence for the key: an explicit init() option, then the script tag attribute, then PeeveConfig.

The npm package

Peeve.init injects the same script tag from the same CDN with the same key. It is idempotent, and it will not add a second tag if one is already on the page — so having both is harmless. The package works with any frontend and has no dependencies. It is SSR-safe: init is a no-op on the server, and identify / reset calls made before the widget finishes loading are queued and flushed when it appears.
There are two names here and they are not the same object. Peeve (capital) is what the npm package exports. window.peeve (lowercase) is the running widget on the page. Both are covered in the JavaScript API.

Verifying the install

1

Check the widget booted

In the browser console, window.peeve should be defined. If it is not, the script did not load or the tag had no key — check for the [peeve] no data-publishable-key… warning.
2

Check the config call

In the network tab, look for the widget’s bootstrap request to api.peeve.ai. A 200 with "ok": true means the key and origin resolved.If enforcement.disabled is true, the workspace is not entitled to serve — check the kill switch, the trial expiry and the subscription.
3

Check it has been mapped

If mapped is false in that response, the widget stays hidden for end users on purpose — a real visitor should never meet an unmapped cursor. Run the baseline capture from the dashboard.

Content Security Policy

If your app sets a CSP, allow:
The widget loads an additional chunk from the same origin as widget.js, which is why cdn.peeve.ai must be in script-src and not only connect-src. API calls go to api.peeve.ai. If you set data-endpoint, add that origin to connect-src instead.