Remix Integration
This guide shows how to integrate ConsentLayer with a Remix application (works on both Remix v2 and React Router v7).
1. Install the SDK
npm install @consentlayer/sdk2. Add the banner script in app/root.tsx
// app/root.tsx
import {
Links,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from "@remix-run/react";
export default function App() {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<Meta />
<Links />
<script src="https://b.consentlayer.com/YOUR_PROJECT_KEY/banner.js" />
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
</body>
</html>
);
}Use a plain <script> tag — not Remix's <Scripts /> component, which is
reserved for the app's own bundle. The banner needs to run before any
client code, so put it directly in <head> before <Scripts />.
Remix renders app/root.tsx on the server, so the tag is emitted as static
HTML. The browser runs it synchronously while parsing <head>, before any
tracking scripts can fire.
3. Wrap consent-aware UI with the Provider
Like Next.js App Router, Remix server-renders by default. Any component that reads consent state needs to be mounted before it tries to render — gate it behind a flag so server HTML matches the first client render:
// app/components/ConsentArea.tsx
import { useEffect, useState } from "react";
import { ConsentLayerProvider, ConsentGate } from "@consentlayer/sdk/react";
export function ConsentArea({ children }: { children: React.ReactNode }) {
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
if (!mounted) return null;
return (
<ConsentLayerProvider>
<ConsentGate category="statistics">{children}</ConsentGate>
</ConsentLayerProvider>
);
}Use it in any route:
// app/routes/_index.tsx
import { ConsentArea } from "../components/ConsentArea";
import { Analytics } from "../components/Analytics";
export default function Index() {
return (
<main>
<h1>My site</h1>
<ConsentArea>
<Analytics />
</ConsentArea>
</main>
);
}4. Manage preferences link
import { useConsent } from "@consentlayer/sdk/react";
export function CookieLink() {
const { showPreferences } = useConsent();
return <button onClick={showPreferences}>Manage cookies</button>;
}Or use the class hook anywhere (no JS, no hooks):
<a href="#" className="consentlayer-open-preferences">Manage cookies</a>5. Verify it works
npm run dev- Banner appears on first load
- Accept all → banner disappears,
cl_consentcookie set - Reload → no banner, gated component still renders
- Manage cookies link → preferences modal opens
- Toggle a category off + save → gated component re-renders the fallback