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' })

Better still, send it from the server once the account exists, so blocked scripts and double submits don't matter. See server-side examples.

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 a file property):

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

Or for a single link:

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

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.

404 pages#

With the auto module, add this to your 404 template:

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

Then look at the 404 event's path property to find broken links, or use the Not found tab of the Pages panel. 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 ≥ 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)#

Send the variant as a property on every hit, so every metric can be split by variant:

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

with manual mode if the variant isn't known until after load. Then break down any goal by prop:variant. The Experiments report calculates conversion rates per variant and their statistical significance.

Logged-in state or plan#

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

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