Dokumentation
Bläddra i dokumentationen

Event tracking recipes

Copy-paste event tracking for signups, checkout funnels, file downloads, outbound links, 404 pages, scroll milestones, video, A/B tests and user plans.

Visa som Markdown

Signup#

On the page after a successful signup (or in your signup success handler):

js
privatus.track('Signup', { plan: 'free', method: 'email' })

Then create an Event goal named Signup.

Checkout funnel#

js
privatus.track('Checkout started', { items: cart.items.length })
// …
privatus.track('Payment details entered')
// on the confirmation page:
privatus.track('Purchase', { revenue: order.total, currency: order.currency, items: order.items.length })

Build a funnel with the three events as steps. Never send order ids, emails or addresses.

File downloads#

Automatically, with the auto module (File Download events with file and host properties):

html
<script defer src="https://privatusstats.com/js/pa.js" data-site="pa_YOURSITEID" data-modules="engage,auto,vitals,clicks,ask"></script>

Or for a single link:

html
<a href="/files/price-list.pdf" data-privatus-event="Price list download">Price list (PDF)</a>

A File download goal counts the File Download events of the auto module, matched on the file name.

The auto module sends Outbound Link with domain and url. Create an Outbound click goal for a specific domain, e.g. your app's signup page on another domain. It also sends Email Link for mailto: links, Phone Link for tel: links and Form Submit for forms.

404 pages#

The auto module sends a 404 event when the page title contains "404" or "not found". If your title says neither, add this to your 404 template:

html
<meta name="privatus-404" content="true">

Then look at the 404 event's path property in the Events explorer to find broken links. Without auto:

html
<script>
  window.addEventListener('load', function () {
    privatus.track('404', { path: location.pathname });
  });
</script>

Scroll milestones#

The engage module already reports scroll depth for every page. For an event at a specific point (e.g. the end of an article):

js
const end = document.querySelector('#article-end')
new IntersectionObserver((entries, observer) => {
  if (entries.some((e) => e.isIntersecting)) {
    privatus.track('Article finished', { section: 'blog' })
    observer.disconnect()
  }
}).observe(end)

Or create an Engagement goal (scroll depth of at least 75% on /blog/*) with no code.

Video#

HTML5 video:

js
document.querySelectorAll('video').forEach((video) => {
  const name = video.dataset.name || video.currentSrc.split('/').pop()
  video.addEventListener('play', () => privatus.track('Video play', { video: name }), { once: true })
  video.addEventListener('ended', () => privatus.track('Video complete', { video: name }))
})

YouTube embeds need the YouTube IFrame API: listen to onStateChange and track YT.PlayerState.PLAYING and ENDED the same way.

Experiments (A/B tests)#

Privatus Analytics can run the test for you, with no code. If you run tests with your own tool instead, send the variant as a property on every hit:

js
privatus.props({ experiment: 'pricing_2026_09', variant: variant })

with manual mode if the variant isn't known until after load. The report for other tools (Business) takes the property and a goal, assigns each visit to the first variant it saw, and calculates the conversion rate per variant and its statistical significance against the control.

prop:variant breakdowns and filters look at custom events only, so they cover the events sent after privatus.props(), not the pageviews.

Logged-in state or plan#

js
privatus.props({ logged_in: true, plan: 'business' })

Every later pageview and event of the page load carries the properties. Break down or filter custom events by prop:plan.

Never send a user id: it would make visitors identifiable and defeat the cookieless design.