OpinlySDK

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.

EventWhen it firesWhat it carries
First visitOnce per browser, everLanding URL, UTM tags, referrer, ad click ID
page_viewEvery page load, and every SPA route changePage path, title, referrer, session ID
page_leaveLeaving or backgrounding a pageTime on page, scroll depth
clickLinks, buttons, and anything with role="button"Element tag, text, href, whether the link is external
form_submitAny form submissionField names and count — never the values
identifyAn email is typed into a recognisable email fieldThe 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_submit carries 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:

  1. 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.
  2. 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.