Pixel reference
The window.opinly API, script tag attributes, package exports, and browser storage.
window.opinly
Available once the script loads. Four members, that's the whole surface.
| Member | Signature | |
|---|---|---|
anonId | string | The visitor's anonymous ID. Your join key for server-side events. |
track | (event, properties?, opts?) => void | Record an event. |
identify | ({ email, userId? }) => void | Link this visitor to a person. Ignored without email. |
page | () => void | Fire a page_view manually. |
track
window.opinly.track('purchase', { value: 49.0, currency: 'USD' }, {
externalEventId: 'order_123',
})| Argument | ||
|---|---|---|
event | string | The event name. See where events land for which names become conversions. |
properties | object | Any data to attach. On purchase and refund, value + currency become revenue; on any other event value stays a plain property. |
opts.externalEventId | string | Dedup key. Two calls with the same ID become one event — so retries are safe, and a server-side call with the same ID merges rather than duplicating. |
identify
window.opinly.identify({ email: 'user@example.com', userId: 'usr_123' })The first identify wins; a later one with a different email won't overwrite it. See Identify visitors.
opinly:ready
The pixel fires an opinly:ready event on window once it's live. You rarely need it — the
framework packages queue calls made before load and flush them for you — but it's there if
you're working with the raw script tag.
It fires once, synchronously, the moment the pixel is live, and does not replay for listeners
added later. Since the snippet loads async, a listener you register afterwards would never run —
so check first, then subscribe:
function onReady() {
window.opinly.identify({ email: currentUser.email })
}
if (window.opinly) onReady()
else window.addEventListener('opinly:ready', onReady, { once: true })Script tag attributes
<script async src="https://static.opinly.ai/p.js" data-key="pk-your-key"></script>| Attribute | ||
|---|---|---|
data-key | required | Your publishable pk- key. Without it the script does nothing at all — silently. |
data-api-host | optional | Where to send events. Defaults to the origin the script was served from, which is correct unless you're proxying. |
data-opinly-no-capture
Put it on any element to exclude that element and its descendants from click, form, and identify capture.
<form data-opinly-no-capture>...</form>Package exports
The import path differs by framework — check this table rather than guessing.
| Package | Import from | Exports |
|---|---|---|
@opinly/next | @opinly/next/pixel | OpinlyPixel, useOpinly |
@opinly/react | @opinly/react/pixel | OpinlyPixel, useOpinly |
@opinly/vue | @opinly/vue | OpinlyPixel, useOpinly |
@opinly/nuxt | @opinly/nuxt | useOpinlyPixel, useOpinly |
@opinly/svelte | @opinly/svelte | OpinlyPixel, getOpinlyPixel |
@opinly/sveltekit | @opinly/sveltekit | OpinlyPixel, getOpinlyPixel |
@opinly/shared | @opinly/shared/pixel | loadOpinlyPixel, getOpinlyPixel |
All of them take the same two options:
| Option | ||
|---|---|---|
writeKey | required | Your publishable pk- key. |
host | required | https://static.opinly.ai |
useOpinly() — or getOpinlyPixel() in Svelte and SvelteKit, which don't ship a hook — returns a
handle with the same three methods as window.opinly: track, identify and page. They're
queued, so they're safe to call before the pixel has loaded and safe during SSR (they no-op until
there's a browser). The anonymous ID is the one difference: the handle exposes it as a
getAnonId() method, not an anonId property.
Browser storage
The pixel sets no cookies. Everything lives in the browser's own storage, on your domain.
| Key | Where | What |
|---|---|---|
_opinly_anon | Local storage | The anonymous visitor ID |
_opinly_utm | Local storage | The campaign that last referred this visitor |
_opinly_first_visit_sent | Local storage | Marks the first visit as recorded |
opinly_identified_email | Local storage | Stops the same email being identified twice |
_opinly_session | Session storage | The current session; ends after 30 minutes idle |
If storage is unavailable — private browsing, or a locked-down browser — the pixel degrades quietly rather than throwing. The visitor is counted, but each visit looks new.