Add comprehensive visitor engagement tracking and scroll-to-top on navigation
Tracks scroll depth (25/50/75/90%), time on page, UTM parameters, outbound link clicks, search queries, audio pause/completion/listen time, and 404s. Logged-in study users are now tied to their visitor record and surfaced in the admin recent visits table. Scroll position resets on every route change. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+27
-1
@@ -13,11 +13,17 @@ import { useGlobalSearch } from './hooks/useGlobalSearch'
|
||||
import { GlobalSearch } from './components/GlobalSearch'
|
||||
import { EpisodeAudioPlayer } from './components/EpisodeAudioPlayer'
|
||||
import './App.css'
|
||||
|
||||
import { sendEvent, useScrollDepthTracking, useTimeOnPage, useUTMCapture, useOutboundLinkTracking } from './analytics'
|
||||
|
||||
const CONSENT_KEY = 'vbn_analytics_consent_choice'
|
||||
const HEADLINER_WIDGET_ID = 'WI_cmou3b4q7000701p0o9qmmcfj'
|
||||
|
||||
function ScrollToTop() {
|
||||
const { pathname } = useLocation()
|
||||
useEffect(() => { window.scrollTo(0, 0) }, [pathname])
|
||||
return null
|
||||
}
|
||||
|
||||
function usePageTracking() {
|
||||
const location = useLocation()
|
||||
useEffect(() => {
|
||||
@@ -2308,6 +2314,10 @@ export default function App() {
|
||||
const navigate = useNavigate()
|
||||
const location = useLocation()
|
||||
usePageTracking()
|
||||
useScrollDepthTracking()
|
||||
useTimeOnPage()
|
||||
useUTMCapture()
|
||||
useOutboundLinkTracking()
|
||||
|
||||
useEffect(() => {
|
||||
fetch('/api/admin-content')
|
||||
@@ -2375,6 +2385,7 @@ export default function App() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ScrollToTop />
|
||||
<Routes>
|
||||
<Route path="/" element={<LandingPage content={content} />} />
|
||||
<Route path="/start-here" element={<StartHerePage content={content} />} />
|
||||
@@ -2418,12 +2429,27 @@ export default function App() {
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Route path="*" element={<NotFoundPage />} />
|
||||
</Routes>
|
||||
<BackToTopButton />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function NotFoundPage() {
|
||||
const location = useLocation()
|
||||
useEffect(() => {
|
||||
sendEvent('not_found', { path: location.pathname })
|
||||
}, [location.pathname])
|
||||
return (
|
||||
<main style={{ padding: '4rem 2rem', textAlign: 'center' }}>
|
||||
<h1>Page not found</h1>
|
||||
<p>The page <code>{location.pathname}</code> doesn't exist.</p>
|
||||
<Link to="/" style={{ marginTop: '1rem', display: 'inline-block' }}>← Back to home</Link>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
function BackToTopButton() {
|
||||
const [visible, setVisible] = useState(false)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user