SPA Support

Using Zero Trust Analytics with React, Vue, Next.js, and other single-page applications

Automatic SPA Detection

Our tracking script automatically detects single-page application navigation using the History API. No additional configuration needed for most SPAs.

Manual Page Tracking

If automatic detection doesn’t work for your setup, manually track page views:

// Call after each route change
zta.trackPageview()

// Optionally specify a custom path
zta.trackPageview('/custom/path')

React Router

import { useEffect } from 'react'
import { useLocation } from 'react-router-dom'

function App() {
  const location = useLocation()

  useEffect(() => {
    // Track page view on route change
    if (window.zta) {
      window.zta.trackPageview()
    }
  }, [location])

  return (
    // Your app content
  )
}

Next.js (App Router)

// app/layout.js
'use client'
import { usePathname } from 'next/navigation'
import { useEffect } from 'react'

export default function RootLayout({ children }) {
  const pathname = usePathname()

  useEffect(() => {
    if (window.zta) {
      window.zta.trackPageview()
    }
  }, [pathname])

  return (
    <html>
      <body>{children}</body>
    </html>
  )
}

Next.js (Pages Router)

// pages/_app.js
import { useRouter } from 'next/router'
import { useEffect } from 'react'

function MyApp({ Component, pageProps }) {
  const router = useRouter()

  useEffect(() => {
    const handleRouteChange = () => {
      if (window.zta) {
        window.zta.trackPageview()
      }
    }

    router.events.on('routeChangeComplete', handleRouteChange)
    return () => {
      router.events.off('routeChangeComplete', handleRouteChange)
    }
  }, [router.events])

  return <Component {...pageProps} />
}

export default MyApp

Vue Router

// router/index.js
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [/* your routes */]
})

router.afterEach(() => {
  if (window.zta) {
    window.zta.trackPageview()
  }
})

export default router

Angular

// app.component.ts
import { Component } from '@angular/core'
import { Router, NavigationEnd } from '@angular/router'
import { filter } from 'rxjs/operators'

@Component({
  selector: 'app-root',
  template: '<router-outlet></router-outlet>'
})
export class AppComponent {
  constructor(private router: Router) {
    this.router.events
      .pipe(filter(event => event instanceof NavigationEnd))
      .subscribe(() => {
        if ((window as any).zta) {
          (window as any).zta.trackPageview()
        }
      })
  }
}

Troubleshooting

Pageviews not tracking on navigation

Make sure the script is loaded before navigation occurs. Add it to the <head> with defer.

Double pageviews

If you’re seeing duplicate pageviews, the automatic detection might be conflicting with manual tracking. Remove manual trackPageview() calls.

Script not available

The zta object might not be available immediately. Wrap calls in a check:

if (window.zta) {
  window.zta.trackPageview()
}