Single-Page App Routing
How elNudge handles SPA navigation and how to integrate with React Router, Next.js, and Vue Router.
elNudge is built to work with single-page applications. It automatically detects most client-side navigation and fires PAGE_VIEW events without any extra code. This page explains how it works and what to do in edge cases.
How automatic detection works
The SDK patches the browser's History API when it loads:
history.pushState— wrapped so every call fires aPAGE_VIEWevent after navigation.history.replaceState— same as above.popstateevent listener — handles browser back/forward button navigation.hashchangeevent listener — handles hash-based routing (/#/products/123).
For the vast majority of SPAs, this covers all navigation automatically.
Session continuity
A session does not reset on route changes. The same ses_01HXXXXX session ID is carried through the entire visit, across all page transitions, until the session times out (30 minutes of inactivity) or the visitor closes all tabs. This gives the AI a complete picture of the visitor's journey on your site.
Manual PAGE_VIEW call
Some frameworks emit navigation events before patching the URL, or bypass the History API entirely (e.g. in server components or custom routers). If you notice that some route changes do not appear in the Live Preview event stream, fire PAGE_VIEW manually:
window.__eln('track', 'PAGE_VIEW', {
url: window.location.href,
})
You can pass url explicitly or omit it — the SDK will use window.location.href as a fallback.
Framework examples
React Router (v6)
React Router uses the History API internally, so automatic detection works out of the box. You do not need to add any code.
If you want explicit tracking (for example, to include additional metadata per route), add a listener using the useLocation hook:
import { useEffect } from 'react'
import { useLocation } from 'react-router-dom'
function ElnudgeRouteTracker() {
const location = useLocation()
useEffect(() => {
window.__eln?.('track', 'PAGE_VIEW', {
url: window.location.href,
})
}, [location.pathname, location.search])
return null
}
// Add it once inside your router, e.g. in App.tsx
export default function App() {
return (
<BrowserRouter>
<ElnudgeRouteTracker />
<Routes>
{/* your routes */}
</Routes>
</BrowserRouter>
)
}
Next.js — App Router
In the App Router, server components render on the server and the browser receives HTML patches for each navigation. The SDK's History API patches handle this correctly for client-side transitions.
For full coverage including the initial load and hard navigations, add a root client component:
// app/_components/ElnudgeTracker.tsx
'use client'
import { usePathname, useSearchParams } from 'next/navigation'
import { useEffect } from 'react'
export function ElnudgeTracker() {
const pathname = usePathname()
const searchParams = useSearchParams()
useEffect(() => {
window.__eln?.('track', 'PAGE_VIEW', {
url: window.location.href,
})
}, [pathname, searchParams])
return null
}
// app/layout.tsx
import { ElnudgeTracker } from './_components/ElnudgeTracker'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<head>
<script
src="https://cdn.elnudge.com/v1/sdk.js"
data-site-key="sk_live_YOUR_SITE_KEY"
async
/>
</head>
<body>
<ElnudgeTracker />
{children}
</body>
</html>
)
}
Next.js — Pages Router
The Pages Router exposes a router events API that makes it easy to hook into navigation:
// pages/_app.tsx
import { useEffect } from 'react'
import { useRouter } from 'next/router'
import type { AppProps } from 'next/app'
export default function App({ Component, pageProps }: AppProps) {
const router = useRouter()
useEffect(() => {
const handleRouteChange = () => {
window.__eln?.('track', 'PAGE_VIEW', {
url: window.location.href,
})
}
router.events.on('routeChangeComplete', handleRouteChange)
return () => {
router.events.off('routeChangeComplete', handleRouteChange)
}
}, [router.events])
return <Component {...pageProps} />
}
Add the script tag to pages/_document.tsx:
import { Html, Head, Main, NextScript } from 'next/document'
export default function Document() {
return (
<Html>
<Head>
<script
src="https://cdn.elnudge.com/v1/sdk.js"
data-site-key="sk_live_YOUR_SITE_KEY"
async
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
Vue Router (v4)
Use Vue Router's afterEach navigation guard:
// main.js or router/index.js
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(),
routes: [ /* your routes */ ],
})
router.afterEach(() => {
window.__eln?.('track', 'PAGE_VIEW', {
url: window.location.href,
})
})
export default router
Vue Router uses the History API, so automatic detection already covers it. The afterEach hook is optional but useful if you want to fire the event only after the new component has mounted (which afterEach guarantees).
Verifying SPA navigation events
- Open Live Preview in the dashboard.
- Navigate between pages in your SPA.
- A
PAGE_VIEWevent should appear in Live Preview for each navigation.
If events are missing for some routes, add the manual PAGE_VIEW call described above to your router's navigation callback.