Single Page Applications
Narrowbeam automatically tracks page navigation in Single Page Applications (SPAs) built with React, Vue, Angular, and other modern frameworks.
How SPA Tracking Works
Single Page Applications don't reload the page when navigating. Instead, they use the History API (pushState, replaceState) and client-side routing. Narrowbeam detects these navigation events and automatically tracks them as page views.
What Gets Tracked
- Initial page load: First page view when the app loads
- History API navigation: Routes changed via
pushStateorreplaceState - Back/forward buttons: Browser navigation via
popstateevents - Hash changes: URL hash navigation (if used for routing)
Supported Frameworks
SPA tracking works automatically with all major frameworks:
React
- React Router
- Next.js (App Router & Pages Router)
- Remix
- Gatsby
Vue
- Vue Router
- Nuxt.js
- Quasar
Angular
- Angular Router
- Angular Universal
Other Frameworks
- Svelte / SvelteKit
- Solid.js
- Any framework using History API
Installation
For framework-specific installation instructions, see:
How It Works Technically
When the Narrowbeam script loads, it automatically sets up SPA tracking by:
1. Intercepting History API Calls
// Narrowbeam wraps pushState and replaceState
const originalPushState = history.pushState;
history.pushState = function(...args) {
originalPushState.apply(this, args);
// Track the new page view
checkForRouteChange();
};2. Listening for Navigation Events
// Listen for back/forward button clicks
window.addEventListener('popstate', () => {
checkForRouteChange();
});3. Detecting Route Changes
// Track when the URL actually changes
function checkForRouteChange() {
if (currentUrl !== window.location.href) {
currentUrl = window.location.href;
trackPageView();
}
}Manual Page View Tracking
In rare cases where automatic tracking doesn't work (custom routing solutions), you can manually track page views:
// In your custom router
router.on('route-change', () => {
window.narrowbeam.checkPageChange();
});Manual Tracking Rarely Needed
Manual tracking is only needed for very custom routing implementations. All standard frameworks and routing libraries work automatically.
Page Leave Events
Narrowbeam also tracks when users leave pages in an SPA. This happens:
- Before navigating to a new route
- When the user closes the tab or browser
- When the user navigates away from your site
Page leave events use navigator.sendBeacon for reliable tracking even during navigation.
Framework-Specific Examples
React with React Router
// No configuration needed!
// Narrowbeam automatically detects React Router navigation
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>
);
}Next.js App Router
// No configuration needed!
// Narrowbeam tracks Next.js navigation automatically
import Link from 'next/link';
export default function Nav() {
return (
<nav>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
</nav>
);
}Vue with Vue Router
// No configuration needed!
// Narrowbeam tracks Vue Router navigation automatically
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About }
]
});Verifying SPA Tracking
To verify that SPA navigation is being tracked:
- Open your browser's Developer Tools (F12)
- Go to the Network tab
- Filter by "Fetch/XHR" or search for your Narrowbeam domain
- Navigate between pages in your SPA
- You should see a new request to
/api/eventsfor each navigation
What to Look For
Each navigation should create a request with:
event_type: "pageview"- Updated
urlvalue - New
pageview_id - Previous page as
referrer(for internal navigation)
Common Issues
Hash-Based Routing
If your app uses hash-based routing (example.com/#/page), navigation should still be tracked automatically. However, consider migrating to History API routing for better SEO and cleaner URLs.
Custom Routing Libraries
If you're using a custom routing library that doesn't use the History API, you may need to manually trigger page view tracking:
// After your custom routing logic
customRouter.afterNavigation(() => {
window.narrowbeam.checkPageChange();
});Server-Side Rendering (SSR)
For SSR apps (Next.js, Nuxt, etc.):
- Initial page load is tracked as a normal page view
- Subsequent client-side navigation is tracked as SPA navigation
- Hard refreshes create new page views (as expected)
Best Practices
- Use standard routing: Stick to popular routing libraries that use the History API
- Test navigation flows: Verify that all navigation patterns trigger page views
- Clean URLs: Use readable routes like
/products/123instead of/products?id=123 - Consistent routes: Avoid having the same page accessible via multiple URLs
- Monitor analytics: Check that page view counts match expected user behavior
Performance Impact
SPA tracking has minimal performance impact:
- Navigation detection adds less than 1ms of overhead
- Page view events are sent asynchronously (non-blocking)
- Uses
sendBeaconfor reliable, low-overhead transmission - No impact on your app's routing or navigation speed