Home / Blog / How to handle consent across route changes in single-page apps

How to handle consent across route changes in single-page apps

Single-page applications break a core assumption of most consent banners: that a page load is the moment to check consent state. In a React, Vue, or Angular app, the user navigates between views without ever reloading, which means a banner that checks once on load can miss consent changes entirely. Visitors who update their preferences mid-session, or pages that mount tracking code on navigation, create gaps that a standard banner never sees. Here is how to make consent work across client-side routing.

Why route changes are a consent problem

In a traditional site, every navigation reloads the page, and the banner or tag manager re-reads the consent state fresh. In a single-page app, navigation is a JavaScript route change: the URL updates, new components mount, and no reload happens. Any tracking script that initializes on route change, analytics pageviews, ad refreshes, chat widgets, can fire against a stale or default consent state.

The failure modes are concrete. A visitor lands, declines everything, navigates to a new view, and the app mounts a fresh analytics event or re-initializes a widget that was never gated. Or the visitor opens the preference center mid-session, withdraws consent, and already-mounted components keep collecting because nothing told them to stop. Both are real consent violations, and both are invisible to audits that only test the initial page load.

The consent event bus pattern

The robust fix is to treat consent as application state, not banner state. Store the consent decision in a central store or a well-known global, and emit an event whenever it changes. Every component that touches tracking subscribes to that event and starts or stops collection accordingly. The banner writes to the store; the store is the single source of truth.

On every route change, the app should re-resolve consent before firing any new tracking: read the current state from the store, not from a cached copy in the route handler, and gate the route-level events on it. This means wrapping analytics calls and third-party initializations in a consent check that runs per navigation, not per page load. A small middleware in the router, checking state before emitting pageview events, closes most of the gap in one place.

Handling withdrawal mid-session

Withdrawal is the harder half. Granting consent late is easy: the next route change picks it up. Withdrawing consent mid-session requires actively stopping what already started. Components holding analytics timers, session recording, or open connections to vendors need to tear down when the consent event fires. Design your tracking modules with a destroy path from the start, because retrofitting teardown into a live app is the expensive part.

Also handle the consent cookie itself. If your CMP writes consent state to storage, make sure the write is readable synchronously on route change, or gate route events on the async read completing. The classic bug is a route change that fires tracking in the gap between the visitor clicking withdraw and the new state propagating. A few hundred milliseconds of race is enough to violate the promise.

Testing consent in a single-page app

Automated tests should simulate the full lifecycle: load, decline, navigate, verify no tracking fired on the route change, then accept, navigate, verify tracking starts, then withdraw, navigate, and verify tracking stops. Run this against your actual router, not a mocked one, because the bugs live in the real navigation flow.

Add consent assertions to your CI pipeline alongside the unit tests. A consent regression that ships is usually a dependency update or a refactor that moved initialization out of the consent check. The test suite catches it the same day instead of the audit catching it next quarter. Consent in a single-page app is application state: treat it with the same rigor as auth state, because legally it carries similar weight.

Get a free consent audit of your website

Free consent audit