Remix cookie consent now lives in React Router: the Remix team released what would have been Remix v3 as React Router v7, and a Remix app moves to it by replacing its @remix-run/* imports with react-router. The consent pattern stays the same in both. Load the consent script in the <head> of app/root.tsx, let the root loader read the consent cookie, and render analytics and marketing scripts only once the visitor has accepted them.

Why Remix and React Router treat cookies differently

Remix is a full-stack React framework built around server rendering, nested routes and progressive enhancement. The Remix team announced in May 2024 that Remix and React Router were merging, and the framework now continues as React Router's framework mode. Everything below applies to both, with the import changes noted where they matter.

Unlike a client-only React app, every route runs loader and action functions on the server before any HTML reaches the browser. When a visitor lands on the app, the server reads the incoming Cookie header, runs the loaders and returns rendered HTML. If a loader sets an analytics or marketing cookie before the visitor has consented, the app has already broken Article 5(3) of the ePrivacy Directive, which governs storing anything on the visitor's device. The GDPR then governs what happens to any personal data collected that way.

The upside is that the framework gives you fine-grained control over cookies on the server, so holding non-essential cookies back before consent is manageable once you know the pattern.

Common cookies in a Remix or React Router app

Before adding a consent banner, find out which cookies your app actually sets. The framework sets none on its own, but your session storage and third-party integrations do.

CookieSourceCategoryNeeds consent?
__sessionCookie session storage (a common default name)Strictly necessaryNo
_ga, _ga_<container-id>Google Analytics 4AnalyticsYes
_fbpMeta PixelMarketingYes
__hstcHubSpotAnalyticsYes
A locale cookie your app setsLanguage preferenceFunctionalDepends on purpose

Run a cookie scan on your deployed app to get an accurate inventory. Cookies set by third-party scripts, such as Google Analytics, the Meta Pixel and chat widgets, are the ones that need consent under the GDPR, or an opt-out under the CCPA.

The loader and action consent pattern

The framework provides a createCookie utility that handles cookie serialising, parsing and signing. In Remix v2 it came from @remix-run/node. In React Router it is imported from react-router, in line with the React Router upgrade guide, which moves the shared server APIs into that package. You can use it for a consent cookie that records which categories the visitor accepted.

The pattern works like this:

  1. Create a consent cookie in a shared .server.ts file.
  2. In the root loader in app/root.tsx, parse the Cookie header and check whether consent was given.
  3. Return the consent state to the client as loader data.
  4. Render or leave out third-party scripts based on that state.
  5. When the visitor uses the banner, submit the choice to an action that sets the consent cookie in the response headers.

This server-first approach makes the consent state available on the very first render, so no tracking script flashes into the page before the banner loads.

Adding a cookie banner in root.tsx

app/root.tsx wraps every route. It is the right place for a cookie banner because it renders on every page, and the root loader runs before any child loader. There are two approaches.

A script tag in root.tsx

The most direct method adds the consent script in the root component's <head>, before any analytics or marketing script. With Kukie.io, that is one line:

<script src="https://cdn.kukie.io/s/YOUR-SITE-KEY/c.js" async />

The banner script runs on every page and manages consent in the browser, and your loaders can read the consent cookie on later requests. The Kukie.io script loads with async, so it does not block the first render.

Conditional script loading

For tighter control, load third-party scripts conditionally based on the consent value from the root loader. The analytics snippet then appears in the HTML only when the loader confirms consent, so non-essential scripts never reach the browser without it.

Server rendering pitfalls and how to avoid them

Server rendering brings consent challenges that client-only frameworks do not face.

Cookies set in loaders

If a loader sets a non-essential cookie in its Set-Cookie header, that cookie reaches the browser before the visitor sees the banner. Audit every loader and action. Any cookie in the analytics, marketing or personalisation category must sit behind a consent check.

Hydration mismatches

When the server renders HTML without tracking scripts (because there is no consent yet) and the client tries to add them during hydration, React reports a hydration mismatch. Keep the conditional logic consistent: if the server leaves a script out, the client must also leave it out during the first hydration pass.

Streamed data

Both Remix and React Router can stream loader data to the browser. If you stream data from an analytics endpoint before consent is confirmed, you may be processing personal data without a legal basis. Check consent before starting any streamed fetch that involves tracking.

Blocking third-party scripts until consent

The ePrivacy Directive and the GDPR require that non-essential cookies are not set until the visitor consents. In a Remix or React Router app, that means blocking scripts like Google Tag Manager, the Meta Pixel and similar trackers until the consent cookie confirms acceptance.

Two reliable methods exist:

  • Server-side conditional rendering: the root loader checks the consent cookie, and if consent is missing or refused, the component tree leaves the tracking script tags out. No tracking code reaches the browser.
  • Blocking by a consent tool: a consent tool such as Kukie.io runs scripts tagged with type="text/plain" and a data-cc-category attribute, for example data-cc-category="analytics", only after the visitor accepts that category. Kukie.io also holds more than 30 known trackers without any tagging.

Both methods meet the prior-consent rule of Article 5(3). The consent tool approach needs less custom code and sends Consent Mode signals for you once that integration is switched on.

Google Consent Mode v2 with Remix and React Router

If your app uses Google Analytics 4 or Google Ads, set up Google Consent Mode v2. Since March 2024, Google has required Consent Mode v2 signals for EEA and UK traffic used for ad personalisation and measurement.

Consent Mode sends a default state, usually denied, when the page loads and updates it to granted after the visitor accepts analytics or marketing cookies. The default must be set before the Google tag loads, so place the default snippet early in the <head> of your root component. A consent tool that supports Consent Mode v2 sends the consent update command when the visitor uses the banner.

Comparing Remix with other frameworks

Remix is not the only server-rendering framework that needs careful consent handling. The table shows where the integration points sit in each.

FrameworkScript injection pointServer-side cookie accessConsent pattern
Remix and React Routerapp/root.tsxLoaders and actionsLoader reads the consent cookie, scripts render conditionally
Next.jslayout.tsx or _app.tsxMiddleware, cookies(), getServerSidePropsLayout reads the cookie, Script component waits for consent
Nuxtapp.vue or a pluginServer middleware, useCookiePlugin sets the default state, a composable gates scripts
SvelteKitapp.html or hooksHandle function, cookies APIHook reads the cookie, layout loads scripts conditionally

The loader and action pattern gives you explicit control over what happens on the server, which makes consent handling easier to follow than in frameworks that mix server and client logic implicitly. The client-side side of the same problem is covered in the guide to React cookie banners.

Testing your consent set-up

After adding the banner, check that it works. Open Chrome DevTools, go to the Application tab and clear all cookies. Reload the app and, before touching the banner, look at the Cookies panel: only strictly necessary cookies such as __session should be there.

Accept the banner, then check again: analytics cookies such as _ga should now appear. Reject consent, clear cookies, reload and confirm that no analytics cookies are set.

For a fuller check, follow the cookie banner verification process, or scan the deployed app to find any cookie that slips through before consent.

Remix and React Router consent questions

Does Remix set any cookies by default that need consent?

No. Remix and React Router set no cookies on their own. A session cookie from createCookieSessionStorage is usually strictly necessary, and the analytics and marketing scripts you add are what need consent.

Can I use createCookie to store consent preferences?

Yes. A signed consent cookie made with createCookie can store the accepted categories and a timestamp. Read it in the root loader and use it to render scripts conditionally. The consent cookie itself is strictly necessary and needs no prior consent.

Do I need a cookie banner if my app only uses session cookies?

If your app sets only strictly necessary cookies, such as session, CSRF and sign-in cookies, you do not need a consent banner under the GDPR or the ePrivacy Directive. Once you add analytics, marketing pixels or other non-essential tracking, you do.

How do I block Google Analytics in Remix before consent?

Check the consent cookie in the root loader. If analytics has not been accepted, leave the GA4 script tag out of the component output so it never reaches the browser. If you load Google's tag anyway, set Consent Mode v2 defaults to denied before it runs.

Does moving from Remix v2 to React Router v7 change the consent pattern?

No. Loaders, actions and app/root.tsx work the same way after the move. What changes is the imports: @remix-run packages are replaced with react-router, so createCookie and the other shared server APIs come from react-router.

Check your Remix app for cookies set before consent

A loader that sets the wrong cookie is easy to miss in code review. The Cookie scanner loads your deployed app like a visitor and lists every cookie it finds by name and category, so you can see whether anything is set before the banner.

Scan your website