Identify visitors
Turn an anonymous ID into a known person, and carry that identity through to your backend.
Every visitor starts anonymous. Identifying them is what connects a browsing session to a real customer — and what lets an order placed on your server find the ad click that earned it.
How identification works
The moment someone lands on your site, the pixel gives them an anonymous ID and stores it in their browser. Every event they fire carries it. At this point Opinly knows a visitor came from a Google ad and read three pages, but not who they are.
When they identify themselves, that anonymous ID is linked to a hash of their email. Their earlier activity doesn't need to be moved or rewritten — it was already tied to the anonymous ID, and the ID is now tied to a person. The whole history joins up at once.
The address travels to Opinly over HTTPS and is stored only as a SHA-256 hash — the address itself is never written to disk. The hash is deterministic and unsalted, which is precisely what lets a later server-side purchase match an earlier visit. That makes it pseudonymised rather than anonymous: treat it as personal data in your own compliance work.
Anonymous visitors
You get the anonymous ID for free — there's nothing to call. Read it any time:
window.opinly.anonIdIt lives in the browser's local storage and persists across visits and sessions on that browser.
Identified on the frontend
Most identification happens on its own. When a visitor types an email into a recognisable email field, the pixel identifies them with it — no code required. That covers newsletter signups, checkout, contact forms, and gated downloads.
"Recognisable" means the field is type="email", has an autocomplete containing email, or has
email somewhere in its name, id, placeholder, aria-label or label. A perfectly valid address
typed into <input type="text" name="username"> is never captured — if you rely on auto-identify,
check your fields are marked up.
The pixel is careful about which emails it treats as the visitor's own. It skips:
- Emails on your own domain (a staff address typed into your own contact form, say).
- Fields whose name suggests someone else —
friend,recipient,refer,gift,share,colleague. - Hidden, disabled, and read-only fields.
- Anything inside
data-opinly-no-capture.
To identify explicitly — after a login, for instance — call it yourself:
window.opinly.identify({ email: 'user@example.com' })
// optionally attach your own user ID
window.opinly.identify({ email: 'user@example.com', userId: 'usr_123' })email is required; the call is ignored without one.
The first identify wins. Once a visitor is linked to an email, a later identify() with a
different email won't overwrite it. This is deliberate — it protects first-touch attribution on
shared devices and stops a support address entered later from hijacking the visitor. If you
need a genuinely different person, that's a different browser or a cleared store.
Identify only works for a visitor Opinly has already seen. If you call it before any page view
has been recorded, there's no visitor to attach it to and the call does nothing. In practice the
pixel loads first, so this only bites if you call identify() on a page the script isn't on.
Carried to the backend
This is the part that matters, and the part most analytics setups get wrong.
Your server knows things the browser never will — that a payment settled, that a subscription renewed, that a trial converted. But your server has no idea which browser visit those belong to. It has an order and a customer; it doesn't have an anonymous ID.
So you pass it one. Read the ID in the browser and send it to your backend along with whatever request you're already making:
// in the browser, at checkout
await fetch('/api/checkout', {
method: 'POST',
body: JSON.stringify({
cart,
anonId: window.opinly.anonId,
}),
})Then include it when you record the event server-side:
import { createOpinlyClient } from '@opinly/backend'
const opinly = createOpinlyClient()
await opinly.track('purchase', { value: 49.0, currency: 'USD' }, {
externalEventId: order.id,
anonId: req.body.anonId, // ← the browser's ID
email: order.email,
})The event now lands on the same visitor as the ad click that started everything.
Send at least one of anonId or email on every server-side call. With neither, the event
is still recorded, but it has nothing to attach to and will show up as "direct" — real revenue,
no attribution.
Linking server events covers the full picture, including what happens when you can only supply an email.
What changes a visitor's anonymous ID
The ID is stable, but not permanent. A visitor gets a new one — and looks like a new person — when:
- They clear their browser storage.
- They switch browser, device, or profile.
- They browse in a private/incognito window (the ID lasts only for that window).
- Safari's tracking prevention expires script-written storage, which it does after 7 days of not visiting your site.
This is why email matters. An email hash follows a person across all of the above; an anonymous ID doesn't.
Next steps
- Linking server events — the full attribution contract.
- What gets captured — everything the pixel records on its own.