OpinlySDK

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.anonId

It 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