Skip to main content

How to Track SPA Sites

SealMetrics automatically tracks Single Page Applications (SPAs) without any additional configuration. The tracker detects URL changes via the History API and fires pageview events automatically.


Automatic SPA Tracking

Simply add the standard tracker script to your site:

<script src="https://t.sealmetrics.com/t.js?id=YOUR_ACCOUNT_ID" defer></script>

That's it. The tracker automatically:

  1. Tracks initial pageview on first load
  2. Detects pushState calls when navigating to new routes
  3. Detects replaceState calls when updating the URL
  4. Handles back/forward buttons via popstate events

Supported Frameworks

Works out of the box with any framework using the History API:

FrameworkRouterAuto-Tracking
Reactreact-router v5/v6
Vuevue-router v3/v4
Angular@angular/router
Next.jsApp Router / Pages Router
Nuxt.jsnuxt/router
SvelteSvelteKit
Remix@remix-run/react

Tracking Conversions in SPAs

React Example

// CheckoutSuccess.jsx
import { useEffect } from 'react';

function CheckoutSuccess({ order }) {
useEffect(() => {
// Pageview is automatic, just track the conversion
if (typeof sealmetrics !== 'undefined') {
sealmetrics.conv('purchase', order.total, {
order_id: order.id,
currency: order.currency
});
}
}, [order]);

return <div>Thank you for your order!</div>;
}

Vue Example

<script setup>
import { onMounted } from 'vue';

const props = defineProps(['order']);

onMounted(() => {
if (typeof sealmetrics !== 'undefined') {
sealmetrics.conv('purchase', props.order.total, {
order_id: props.order.id,
currency: props.order.currency
});
}
});
</script>

<template>
<div>Thank you for your order!</div>
</template>

Angular Example

// checkout-success.component.ts
import { Component, OnInit, Input } from '@angular/core';

@Component({
selector: 'app-checkout-success',
template: '<div>Thank you for your order!</div>'
})
export class CheckoutSuccessComponent implements OnInit {
@Input() order: any;

ngOnInit() {
if (typeof (window as any).sealmetrics !== 'undefined') {
(window as any).sealmetrics.conv('purchase', this.order.total, {
order_id: this.order.id,
currency: this.order.currency
});
}
}
}

Tracking Microconversions

Track user interactions like add-to-cart or form submissions:

// Add to cart button handler
function handleAddToCart(product) {
// Your cart logic here...

if (typeof sealmetrics !== 'undefined') {
sealmetrics.micro('add_to_cart', {
product_id: product.id,
product_name: product.name,
price: String(product.price)
});
}
}

Content Grouping

You can set content grouping dynamically after navigation:

// After navigating to a blog post
if (typeof sealmetrics !== 'undefined') {
sealmetrics({ group: 'blog' });
}

Or set it in the script URL for specific page types:

<!-- For blog pages -->
<script src="https://t.sealmetrics.com/t.js?id=YOUR_ACCOUNT_ID&group=blog" defer></script>

Hash-Based Routing

If your SPA uses hash-based routing (/#/path), automatic tracking won't work because the History API isn't used.

Solution: Listen for hashchange events:

window.addEventListener('hashchange', function() {
if (typeof sealmetrics !== 'undefined') {
sealmetrics();
}
});

Troubleshooting

Duplicate Pageviews

If you see duplicate pageviews:

  1. Ensure the tracker script is only included once
  2. Don't call sealmetrics() manually if automatic tracking is sufficient
  3. Check that no other code is triggering additional pageview events

Missing Pageviews on Navigation

If pageviews aren't tracked on route changes:

  1. Verify your router uses the History API
  2. For hash-based routing, add the hashchange listener above
  3. For custom navigation, manually call sealmetrics() after navigation

Server-Side Rendering (SSR)

Always check if the tracker exists before calling it:

// For SSR frameworks like Next.js or Nuxt
if (typeof window !== 'undefined' && typeof sealmetrics !== 'undefined') {
sealmetrics.conv('purchase', 99.99);
}