What gets captured
Everything the pixel records on its own, what you have to send yourself, and where each event ends up.
Install the pixel and a lot happens without any further code. This page is the complete list — read it before you start sending custom events, because you may not need to.
Captured automatically
Every event below fires on its own once the script is on the page.
| Event | When it fires | What it carries |
|---|---|---|
| First visit | Once per browser, ever | Landing URL, UTM tags, referrer, ad click ID |
page_view | Every page load, and every SPA route change | Page path, title, referrer, session ID |
page_leave | Leaving or backgrounding a page | Time on page, scroll depth |
click | Links, buttons, and anything with role="button" | Element tag, text, href, whether the link is external |
form_submit | Any form submission | Field names and count — never the values |
identify | An email is typed into a recognisable email field | The email address, stored only as a hash |
Single-page apps work without configuration. The pixel patches the History API, so a client-side
route change fires a page_view the same as a full page load.
page_view, click, form_submit and your own track() calls also carry a session ID (sessions
end after 30 minutes of inactivity) and basic page context: path, title, hostname, screen and
viewport size, language, and timezone. identify and page_leave are deliberately leaner. Every
event carries the visitor's anonymous ID.
What is never captured
- The values typed into forms.
form_submitcarries only field names and a count. The single exception is an email address: the pixel reads a recognisable email field so it can identify the visitor, and sends it to be hashed — see Identify visitors. Nothing else you type is ever read. - Password and hidden fields. Excluded entirely, not even by name.
- IP addresses. The pixel derives a two-letter country code at the edge and stores that. The address itself is never written down.
- Cookies. The pixel sets none. The anonymous ID is a random UUID in the browser's own local storage, scoped to your domain.
Opting an element out
Add data-opinly-no-capture to any element to exclude it and everything inside it from click,
form, and identify capture.
<form data-opinly-no-capture>
<!-- nothing in here is captured -->
</form>Attribution: how a visitor's source is decided
On the first visit the pixel stores the campaign that brought the visitor in — UTM tags,
referrer, and any ad click ID (gclid, fbclid, and nine others).
That stored source is overwritten whenever the visitor arrives on a fresh campaign. If they come back through a new ad, the new campaign wins. A visit with no campaign at all leaves the stored one untouched, so an organic return visit won't wipe the ad that earned them.
Two models are in play, and it's worth knowing which you're reading.
- Events sent from the browser carry that stored source, so they're last-non-direct — the same default GA uses. A returning visitor's purchase is credited to the most recent campaign that referred them.
- Your visitor, campaign and country reports are first-touch. A visitor's own record keeps the campaign from their very first visit and never changes.
- Events sent from your server inherit that visitor record, so they're first-touch too — a server-reported purchase is credited to the campaign that first brought the visitor in.
Sending your own events
Anything not in the table above, you send yourself with
window.opinly.track(). Purchases are the common case:
window.opinly.track('purchase', { value: 49.0, currency: 'USD' }, {
externalEventId: 'order_123',
})externalEventId is a dedup key — send the same order twice and it collapses to one event. It's
also what lets a server-side confirmation of the same order merge with the browser's version.
See Linking server events.
Where events land
Opinly keeps two stores: conversions are kept row by row so you can act on them, and high-volume behaviour is aggregated so your reports stay fast. Here's what goes where.
These events are stored individually and appear in your dashboard immediately:
purchase · refund · sign_up · add_to_cart · generate_lead · form_submit
All of them count as conversions except refund, which is stored for its negative revenue only.
signup and lead are accepted too — they're the original names, kept working permanently. They
are stored exactly as you send them, so pick one spelling and stay with it or your reports will
split across both. Prefer sign_up and generate_lead, which match the
standard events the server-side SDK uses.
form_submit is the one conditional entry. It's stored individually if your conversion goal is
form tracking — or if you haven't picked a goal yet, which is the default. If your goal is
purchases, form submissions are aggregated like page views — see
Conversion goals.
Everything else the pixel captures in the browser — page views, clicks, page leaves, and any custom event name of your own — is aggregated rather than stored row by row. It powers your traffic and sources reports, which refresh hourly, and your pages report, which refreshes daily.
Events you send from your server with track() are the exception: they
are always stored individually, whatever you name them — except the names the pixel already
collects (page_view, click, form_submit, identify and a few others), which the API rejects
with a 400. They're deliberate and low-volume, so they don't need aggregating — but a custom name
still won't count as a conversion.
Two consequences worth knowing:
- Your dashboard's event list will not show page views. That's by design, not a broken install. To confirm the pixel works, look at Visitors.
- A custom event name won't appear as a conversion. Use one of the names above if you want it counted. Conversion goals let you choose which form submissions count — they can't promote a custom event name. See Conversion goals.
refund is stored with its negative value and is not counted as a conversion. Revenue reports show
gross revenue from purchases, so refunds sit alongside them rather than netting off.