Session Story Sign in
← Back to Developers

JavaScript Tracker

A lightweight script that automatically tracks pageviews, sessions, clicks, scroll depth, and custom events on your website.

Installation

Add the following snippet before the closing </head> tag on every page you want to track.

<script defer
  data-site-id="YOUR_TRACKING_ID"
  data-api-url="https://www.sessionstory.io/api/events"
  src="https://www.sessionstory.io/tracker.min.js"></script>

Replace YOUR_TRACKING_ID with the tracking ID from your site's settings page in the dashboard. The script is lightweight (< 4 KB) and loads asynchronously with defer, so it won't affect page load performance.

Script attributes

Configure the tracker via data-* attributes on the script tag.

AttributeRequiredDescription
data-site-idYesYour site's tracking ID (found in site settings).
data-api-urlNoEvent ingestion endpoint. Defaults to https://www.sessionstory.io/api/events.
data-debugNoSet to "true" to log all events to the browser console.
data-allow-localhostNoSet to "true" to enable tracking on localhost (disabled by default).

Automatic tracking

The tracker automatically captures the following events with no additional code:

Pageviews

Tracked on every page load and SPA navigation. Duplicate pageviews for the same URL within 1 second are automatically throttled.

Clicks

Every click is captured with the element's CSS selector, tag name, visible text, link href, and page coordinates.

Scroll depth

Fires at 25%, 50%, 75%, and 100% scroll milestones. Resets on each page navigation.

Rage clicks

Detected when a user clicks the same area 3+ times within 500ms — a signal of frustration.

Dead clicks

Detected when a click on an interactive element (button, link) produces no DOM change or navigation within 1 second.

Custom events

Track conversions, signups, purchases, or any other action with sessionstory.track().

// Track a simple event
window.sessionstory.track('signup');

// Track with custom data
window.sessionstory.track('purchase', {
  amount: 49.99,
  plan: 'pro',
  currency: 'USD'
});
ArgumentTypeDescription
eventNamestringRequired. Name of the event (e.g. "signup", "purchase").
dataobjectOptional. Arbitrary key-value data attached to the event.

Custom events with numeric data properties can be used for revenue tracking — configure which event and property to use in your site's settings.

User identification

Link anonymous visitors to known users with sessionstory.identify().

// After user logs in
window.sessionstory.identify('user_123', {
  name: 'Jane Doe',
  email: '[email protected]',
  plan: 'pro'
});
ArgumentTypeDescription
userIdstringRequired. Your internal user ID.
traitsobjectOptional. User properties (name, email, plan, etc.).

SPA support

The tracker automatically detects client-side navigations in single-page applications. It patches history.pushState, history.replaceState, and listens for popstate events to track pageviews on route changes.

No additional configuration is needed for React, Vue, Next.js, Nuxt, or any other SPA framework.

UTM & campaign tracking

UTM parameters are automatically captured from the landing page URL and attached to the session. The following parameters are tracked:

  • utm_source
  • utm_medium
  • utm_campaign
  • utm_term
  • utm_content

UTM values are stored in sessionStorage so they persist across SPA navigations but reset when the browser tab is closed.

The landing page referrer is also captured once per session and sent alongside UTM data.

How it works

Visitor & session IDs are stored as first-party cookies (ss_vid for 1 year, ss_sid for 30 minutes rolling). Cookies are scoped to the root domain so they work across subdomains.

Event batching — events are queued in memory and flushed every 5 seconds or when 20 events accumulate, whichever comes first. When the user leaves the page, remaining events are sent via navigator.sendBeacon to avoid data loss.

Bot filtering — the tracker detects headless browsers, automation tools (Selenium, Puppeteer, Playwright), and common bot user agents, and disables tracking automatically.

Iframe protection — the tracker does not run inside iframes to prevent duplicate tracking from embedded content.