Tracking Snippet

The Agent Analytics tracking snippet is a lightweight, privacy-first JavaScript library that automatically captures pageviews, engagement metrics, and custom events. At under 2KB minified, it requires zero dependencies and works seamlessly with modern frameworks and single-page applications.

Installation

Add the tracking snippet to your website by including the script tag in your HTML. The snippet can be installed in various ways depending on your tech stack.

Basic HTML Installation

Add this script tag to your HTML, ideally in the <head> section or just before </body>:

html
<script
  async
  defer
  data-site-id="your-site-id-here"
  src="https://api.statscontext.com/tracker.js"
></script>

The async or defer attribute ensures the tracking script loads without blocking page rendering. The data-site-id attribute is required and must match the site ID from your Agent Analytics dashboard.

React / Next.js Installation

For React applications, use the Next.js Script component to load the tracker with optimal performance:

app/layout.tsx
import Script from "next/script";export default function RootLayout({ children }) {  return (    <html lang="en">      <body>        {children}        <Script          src="https://api.statscontext.com/tracker.js"          data-site-id="your-site-id-here"          strategy="afterInteractive"        />      </body>    </html>  );}

The strategy="afterInteractive" setting loads the tracker after the page becomes interactive, ensuring optimal performance without delaying user interactions.

WordPress Installation

For WordPress sites, add the tracking snippet to your theme's footer or use a plugin like "Insert Headers and Footers":

footer.php
<!-- Add before </body> tag -->
<script
  async
  defer
  data-site-id="your-site-id-here"
  src="https://api.statscontext.com/tracker.js"
></script>
<?php wp_footer(); ?>

Static HTML Sites

For static HTML websites, add the script tag before the closing </body> tag on every page:

html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>My Website</title>
</head>
<body>
  <!-- Your content -->

  <script
    async
    defer
    data-site-id="your-site-id-here"
    src="https://api.statscontext.com/tracker.js"
  ></script>
</body>
</html>

Getting Your Site ID

To find your unique site ID:

  1. Log in to your Agent Analytics dashboard
  2. Navigate to the Sites page
  3. Copy the site ID for your domain
  4. Replace your-site-id-here in the tracking snippet

How It Works

The tracking snippet follows a simple initialization and event flow designed for maximum reliability and minimal performance impact.

Initialization Flow

When the tracking script loads, it automatically performs these steps:

  1. Extract Site ID: Reads the data-site-id attribute from the script tag
  2. Check Do Not Track: Respects browser DNT settings by checking navigator.doNotTrack
  3. Configure API Endpoint: Derives the API base URL from the script source
  4. Initialize State: Sets up tracking state including page view ID and heartbeat timer
  5. Register Event Listeners: Hooks into browser navigation and visibility events
  6. Track Initial Pageview: Automatically sends the first pageview event

If the site ID is missing or Do Not Track is enabled, the tracker exits silently without any network activity or errors. This ensures tracking never breaks your website.

Automatic Pageview Tracking

The tracker automatically captures pageviews on initial page load without requiring any manual code. Each pageview captures:

  • URL: Full URL from window.location.href
  • Referrer: Previous page URL from document.referrer
  • Page Title: Document title from document.title
  • UTM Parameters: Campaign tracking parameters (source, medium, campaign, term, content)

The server responds with a page_view_id that the tracker uses for subsequent heartbeat events and SPA navigation tracking.

Heartbeat Mechanism

After each pageview, the tracker starts a heartbeat timer that sends engagement data every 5 seconds while the page is active:

Heartbeat Payload
{
  "type": "heartbeat",
  "site_id": "your-site-id",
  "page_view_id": "pv_abc123",
  "duration_ms": 15000
}

Heartbeats serve multiple purposes:

  • Accurate Time Tracking: Measures actual time spent on page, not just page load
  • Engagement Metrics: Distinguishes between quick bounces and engaged visits
  • Session Duration: Updates session duration in real-time

The heartbeat timer stops on page navigation or when the tab becomes hidden, and a final heartbeat is sent on visibilitychange events.

SPA Navigation Support

The tracker automatically detects single-page application (SPA) navigation by intercepting:

  • history.pushState(): Programmatic navigation (e.g., React Router)
  • history.replaceState(): URL replacement without navigation
  • popstate event: Browser back/forward button clicks

When a navigation is detected, the tracker automatically:

  1. Sends a final heartbeat for the current page
  2. Stops the current heartbeat timer
  3. Sends a navigation event linking to the previous page
  4. Starts a new heartbeat timer for the new page

This ensures accurate page tracking in React, Vue, Angular, and other SPA frameworks without requiring manual tracking code.

Custom Events

Beyond automatic pageview tracking, the tracker exposes a global API for tracking custom application events through window.aa.track().

API Reference

typescript
window.aa.track(  name: string,              // Event name (required, max 255 chars)  properties?: Record<string, any>  // Optional metadata object): void

Basic Usage

Track a simple event without properties:

javascript
// Track newsletter signupwindow.aa.track('newsletter_signup');// Track downloadwindow.aa.track('whitepaper_downloaded');

Events with Properties

Add contextual data to events using the properties parameter:

javascript
// Track button click with contextwindow.aa.track('button_clicked', {  button_id: 'hero_cta',  button_text: 'Get Started',  page: '/pricing'});// Track feature usagewindow.aa.track('feature_used', {  feature: 'export_data',  format: 'csv',  record_count: 150});

E-commerce Tracking Example

Track shopping and checkout events with product details:

E-commerce Events
// Add to cartwindow.aa.track('add_to_cart', {  product_id: 'prod_123',  product_name: 'Pro Plan',  price: 29.99,  quantity: 1,  currency: 'USD'});// Purchase completionwindow.aa.track('purchase', {  order_id: 'order_456',  total: 59.98,  items: 2,  payment_method: 'stripe',  currency: 'USD'});// Checkout stepwindow.aa.track('checkout_step', {  step: 'payment_info',  cart_total: 59.98});

Form Tracking Example

Track form interactions to understand conversion funnels:

Form Tracking
// Track form start (first field interaction)document.querySelector('#contact-form').addEventListener('focus', () => {  window.aa.track('form_started', {    form_id: 'contact',    form_type: 'sales_inquiry'  });}, { once: true });// Track form submissiondocument.querySelector('#contact-form').addEventListener('submit', (e) => {  window.aa.track('form_submitted', {    form_id: 'contact',    form_type: 'sales_inquiry',    field_count: 5  });});// Track form errorsfunction validateForm() {  const errors = getFormErrors();  if (errors.length > 0) {    window.aa.track('form_error', {      form_id: 'contact',      error_count: errors.length,      error_fields: errors.map(e => e.field).join(',')    });  }}

Best Practices

Event Naming

Use consistent, descriptive event names across your application:

javascript
// Good: Consistent naming with properties for variantswindow.aa.track('cta_clicked', { location: 'hero' });window.aa.track('cta_clicked', { location: 'footer' });// Bad: Inconsistent naming makes analysis difficultwindow.aa.track('hero_cta_click');window.aa.track('clicked_footer_cta');

Meaningful Properties

Include context that helps you analyze and segment events:

javascript
// Good: Rich context for analysiswindow.aa.track('video_played', {  video_id: 'intro_2024',  duration: 120,  autoplay: false,  position: 'hero'});// Bad: Missing contextwindow.aa.track('video_played');

Privacy Considerations

Never track personally identifiable information (PII):

javascript
// Bad: Contains PIIwindow.aa.track('form_submitted', {  email: 'user@example.com',  phone: '555-1234',  name: 'John Doe'});// Good: No PIIwindow.aa.track('form_submitted', {  form_type: 'contact',  field_count: 5,  has_message: true});

Property Guidelines

  • Use simple, serializable values: Strings, numbers, booleans work best
  • Keep property names consistent: Use snake_case or camelCase throughout
  • Avoid large objects: Keep properties under 1KB total
  • Don't include sensitive data: No passwords, tokens, credit cards, or PII
  • Avoid non-serializable values: No functions, undefined, or circular references

Checking Availability

The window.aa object is available immediately after the tracking script loads. To ensure it's available before calling:

javascript
// Option 1: Check before callingif (typeof window.aa !== 'undefined') {  window.aa.track('event_name');}// Option 2: Wrap in try-catchtry {  window.aa.track('event_name', { prop: 'value' });} catch (e) {  console.warn('Analytics not loaded');}// Option 3: Wait for DOMContentLoadeddocument.addEventListener('DOMContentLoaded', () => {  if (window.aa) {    window.aa.track('page_interactive');  }});

Configuration

Required Attributes

The tracking script requires one attribute:

  • data-site-id: Your unique site identifier from the Agent Analytics dashboard (required)

Optional Attributes

For optimal performance, consider these attributes:

  • async: Load the script asynchronously without blocking page rendering
  • defer: Load the script after the document has been parsed

Use either async or defer, but not both. For analytics, async is typically preferred.

API URL Derivation

The tracker automatically determines the API endpoint from the script source URL:

javascript
// If script src is: https://api.statscontext.com/tracker.js// API endpoint becomes: https://api.statscontext.com/api/eventvar script = document.currentScript;var apiBase = script.src.replace(/\/tracker\.js.*$/, "");// Result: https://api.statscontext.com

This means you don't need to configure the API endpoint separately - it's automatically derived from the script URL.

SPA Support

The tracker includes built-in support for single-page applications (SPAs) without requiring any additional configuration.

How It Works

The tracker patches the browser's History API to detect navigation:

javascript
// Intercept pushState (used by React Router, etc.)var origPushState = history.pushState;history.pushState = function() {  origPushState.apply(this, arguments);  detectNavigationAndTrack();};// Intercept replaceStatevar origReplaceState = history.replaceState;history.replaceState = function() {  origReplaceState.apply(this, arguments);  detectNavigationAndTrack();};// Listen for back/forward button clickswindow.addEventListener("popstate", detectNavigationAndTrack);

Supported Frameworks

The SPA support works automatically with:

  • React Router: Both v5 and v6
  • Next.js: App Router and Pages Router
  • Vue Router: All versions
  • Angular Router: All versions
  • Any framework using History API: Automatic detection

Navigation Event Flow

When a user navigates in an SPA:

  1. User clicks a link or uses browser back/forward
  2. Framework updates the URL using pushState or replaceState
  3. Tracker detects the URL change
  4. Tracker sends final heartbeat for previous page
  5. Tracker sends navigation event with prev_page_view_id
  6. Server marks previous page as non-bounce
  7. Server creates new page view and continues session
  8. Tracker starts new heartbeat timer

Session Continuity

SPA navigation maintains session continuity by:

  • Linking pages together via prev_page_view_id
  • Continuing the same session (no new session created)
  • Incrementing the session's page count
  • Updating the session's exit page
  • Correctly calculating bounce rates (navigation marks previous page as non-bounce)

Privacy

Agent Analytics is built privacy-first from the ground up. The tracking system respects user privacy while providing actionable analytics.

No Cookies

The tracker does not use cookies, which means:

  • No cookie consent banners required
  • No client-side data storage
  • Automatic compliance with cookie laws
  • Works in browsers with third-party cookies blocked

No Local Storage

The tracker does not use localStorage or any other client-side storage:

  • No persistent tracking identifiers
  • No cross-session fingerprinting
  • Works in private browsing mode
  • Respects browser privacy settings

Daily-Rotating Hashes

Visitor identification uses daily-rotating hashes to prevent long-term tracking:

Hash Formula
visitor_hash = SHA-256(
  daily_salt + ":" +
  site_id + ":" +
  ip_address + ":" +
  user_agent
)

How daily rotation works:

  • New salt each day: A unique salt is generated for each UTC day
  • Same-day continuity: Same visitor gets same hash within a day
  • Cross-day privacy: Hash changes daily, preventing multi-day tracking
  • Site isolation: Each site gets different hashes for the same visitor
  • One-way hashing: Cannot reverse hash to get IP or user agent

Do Not Track Compliance

The tracker fully respects the Do Not Track (DNT) browser setting:

javascript
// Check DNT on initializationvar dnt = navigator.doNotTrack === "1" || window.doNotTrack === "1";if (dnt) return; // Exit silently, no tracking

When DNT is enabled:

  • Tracker exits immediately on initialization
  • No network requests are sent
  • No errors are thrown
  • Website functionality is unaffected

Data Retention

Privacy is enforced through automatic data expiration:

  • Daily salts: Automatically deleted after 2 days
  • IP addresses: Never stored in the database
  • User agents: Only parsed metadata stored (browser, OS, device type)
  • Analytics data: Configurable retention period (typically 90 days)

No Personal Data

The tracker never collects personally identifiable information:

  • No email addresses
  • No names
  • No IP addresses stored
  • No unique device identifiers
  • No cross-site tracking

Technical Reference

Script Size

  • Unminified: ~2.5 KB
  • Minified: ~1.8 KB
  • Gzipped: ~0.9 KB

The tiny footprint ensures minimal impact on page load performance.

Browser Compatibility

The tracker is written in ES5-compatible JavaScript for maximum compatibility:

  • Modern browsers: Chrome, Firefox, Safari, Edge (full support)
  • Older browsers: IE11+ (full support)
  • Mobile browsers: iOS Safari, Chrome Mobile (full support)
  • Feature detection: Gracefully degrades if APIs are unavailable

Network Protocol

Events are sent via navigator.sendBeacon when available, with XMLHttpRequest fallback:

javascript
function send(data) {  var payload = JSON.stringify(data);  if (navigator.sendBeacon) {    // Preferred: Guaranteed delivery, non-blocking    navigator.sendBeacon(apiBase + "/api/event", payload);  } else {    // Fallback: Standard AJAX request    var xhr = new XMLHttpRequest();    xhr.open("POST", apiBase + "/api/event", true);    xhr.setRequestHeader("Content-Type", "application/json");    xhr.send(payload);  }}

Benefits of sendBeacon:

  • Guaranteed to send even on page unload
  • Non-blocking (doesn't delay navigation)
  • Browser-optimized for analytics use cases

Error Handling

The tracker is designed to fail silently to prevent tracking errors from breaking your website:

  • Network failures: No retries, fails silently
  • Invalid responses: Caught and ignored
  • Missing APIs: Feature detection prevents errors
  • Invalid configuration: Silent exit if site ID missing

This ensures tracking is a zero-risk addition to your website.

Performance Characteristics

  • Zero dependencies: No external libraries required
  • Minimal DOM access: Only reads necessary properties
  • Non-blocking loads: async/defer script loading
  • Efficient heartbeats: 5-second interval balances accuracy and performance
  • No render blocking: Never delays page rendering

Debugging

Verify that tracking is working correctly using browser developer tools.

Network Tab Inspection

Check that events are being sent to the API:

  1. Open your website in a browser
  2. Open Developer Tools (F12 or Cmd+Option+I)
  3. Go to the Network tab
  4. Filter by "event" or look for POST requests
  5. You should see requests to /api/event
  6. Click on a request to inspect the payload and response

Console Monitoring

Add debug logging to monitor custom events:

Console Debug Script
// Paste this in the browser console to debug trackingif (window.aa) {  const originalTrack = window.aa.track;  window.aa.track = function(name, properties) {    console.log('📊 Custom Event:', name, properties);    return originalTrack.apply(this, arguments);  };  console.log('✅ Analytics debug mode enabled');} else {  console.error('❌ window.aa not found - tracker may not be loaded');}

Verifying Installation

Quick checks to verify the tracker is properly installed:

javascript
// Check if tracker script loadedconsole.log('Tracker loaded:', typeof window.aa !== 'undefined');// Check site IDconst script = document.querySelector('script[data-site-id]');console.log('Site ID:', script?.getAttribute('data-site-id'));// Test custom eventif (window.aa) {  window.aa.track('test_event', { debug: true });  console.log('✅ Test event sent');}

Common Issues

No Network Requests

If you don't see any /api/event requests:

  • Check that the data-site-id attribute is present
  • Verify Do Not Track is not enabled in browser settings
  • Check browser console for JavaScript errors
  • Ensure the script URL is correct and accessible

Events Not Appearing in Dashboard

If network requests succeed but events don't appear:

  • Check that the site ID matches your dashboard site
  • Verify the origin matches the configured site domain
  • Wait a few seconds - there may be processing delay
  • Check for 403 responses indicating origin mismatch

SPA Navigation Not Tracking

If page views aren't tracked on SPA navigation:

  • Ensure the tracker loads before your framework initializes
  • Check that your framework uses the History API (not hash routing)
  • Verify that initial pageview succeeds (navigation requires page_view_id)

Test Custom Events

Send a test event from the browser console:

javascript
// Open browser console and run:window.aa.track('debug_test', {  timestamp: new Date().toISOString(),  test: true});// Check Network tab for the POST request// Check dashboard for the custom event