Blog

React Cookie Consent: How to Actually Block Trackers (Not Just Show a Banner)

If you searched for "react cookie consent," you probably want two things: a banner that asks visitors for permission, and the confidence that you are actually compliant. Here is the catch most tutorials skip. The banner is the easy 10 percent. The part that keeps you compliant, and out of a lawsuit, is blocking tracking scripts until the visitor agrees. Most popular React consent libraries never do that. They show a banner, store a true or false, and leave every tracker firing.

Key Takeaways

  • 01Cookie consent in React isn't about React. It's about blocking non-essential trackers until a visitor opts in (GDPR) or honoring their opt-out and GPC signal (US state laws).
  • 02The popular react-cookie-consent library shows a banner and stores a boolean, but it blocks nothing. You wire up and maintain all the gating yourself.
  • 03A compliant flow needs script-blocking before consent, granular categories, region-aware logic, GPC support, and a logged decision. The banner is the easy part.
  • 04@consentstack/react gives you a drop-in ConsentStack component that blocks trackers automatically, plus useConsentValue() hooks for fine-grained control.
  • 05Never trust a banner. Verify any setup with a scanner that checks what actually fires before and after a visitor clicks Reject.

This guide covers what cookie consent in React really requires, why the most-downloaded library is not enough on its own, and how to add a consent layer that actually blocks trackers in a few lines with @consentstack/react. Everything here works the same in the Next.js App Router, with a short Next.js section below.

Yes, but not because of React. Consent rules apply to what your cookies and scripts do, not the framework rendering them. Under the EU's GDPR and ePrivacy rules, you need prior opt-in consent before loading non-essential cookies such as analytics, ads, and most third-party pixels. Under US state laws like California's CCPA, you owe visitors a way to opt out and must honor the Global Privacy Control signal. React is just the interface layer on top of those duties.

The banner is the visible part. Underneath, a flow that holds up to a regulator (or a plaintiff's lawyer) needs all of this:

  • Script blocking before consent. Non-essential trackers must not run until the visitor opts in. This is the single most common failure, and the hardest part to build.
  • A genuine choice. Accept and Reject need equal weight. A prominent Accept next to a buried Reject is a dark pattern regulators now fine.
  • Granular categories. Visitors should be able to accept analytics but decline advertising, and change their mind later.
  • Region-aware logic. GDPR is opt-in. US state laws are opt-out plus GPC. The same banner should behave correctly for both visitors.
  • A stored, logged decision. You need a record of who consented to what, and when, in case you are ever asked to prove it.

Notice how little of that is "a banner." That gap, especially blocking trackers before consent, is where most React setups quietly fail.

Blocking is the hard part, and the part most tools fake. We broke down how script blocking actually works separately if you want to see what real blocking looks like under the hood.

Search "react cookie consent" and the top result is the react-cookie-consent npm package. It is genuinely nice for what it is: a small, customizable banner bar. A minimal setup looks like this:

CookieBanner.tsx
import CookieConsent from "react-cookie-consent"

export function CookieBanner() {
  return (
    <CookieConsent
      enableDeclineButton
      onAccept={() => loadAnalytics()}
      onDecline={() => {}}
    >
      This website uses cookies to improve your experience.
    </CookieConsent>
  )
}

That renders a banner and remembers the choice in a cookie. But look at what it does not do: it never blocks anything. Your analytics and pixels still load on page one unless you personally gate every script behind that onAccept callback. It has no consent categories, no region awareness, no GPC handling, and no server-side log of the decision. You are left hand-wiring the 90 percent that actually matters.

A banner is not blocking

This is the trap the ConsentStack scanner catches most often: a real cookie banner on the page, and analytics or ad trackers firing before anyone clicks a thing. The banner makes a site look compliant while it leaks data anyway.

Building it yourself

You can absolutely build the whole thing by hand: a context provider for consent state, conditional loading for every script, a preferences modal, geolocation to tell GDPR from CCPA, a GPC listener, and an endpoint to log decisions. It is a real amount of code, and it is code that has nothing to do with your product. Every framework upgrade and every new law becomes your maintenance problem.

For a side project, fine. For anything real, you are rebuilding a consent management platform. This is the point where most developers reach for a purpose-built one.

The drop-in approach: @consentstack/react

@consentstack/react wraps the ConsentStack SDK in React hooks and components. It renders the banner, blocks non-essential scripts until consent, handles region and GPC logic, and logs decisions, so the whole checklist above is handled for you. Install it:

bash
npm install @consentstack/react

1. Add the banner

Drop the component in once, at the root of your app. It loads the SDK, shows the banner, and starts blocking non-essential trackers automatically.

app/layout.tsx
import { ConsentStack } from "@consentstack/react"

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>
        {children}
        <ConsentStack siteKey="pk_your_site_key" />
      </body>
    </html>
  )
}

Your siteKey comes from the ConsentStack dashboard. That is the entire baseline setup: a banner that blocks trackers before consent, respects the visitor's region, and honors GPC, with no gating code from you.

When you want to load something only after consent, for example a marketing pixel, use the useConsentValue hook. It returns a boolean for one category and only re-renders when that category changes.

MarketingPixel.tsx
"use client"
import { useConsentValue } from "@consentstack/react"

export function MarketingPixel() {
  const marketingAllowed = useConsentValue("marketing")

  if (!marketingAllowed) return null

  return (
    <script
      async
      src="https://connect.facebook.net/en_US/fbevents.js"
    />
  )
}

For the hooks to work, wrap your app in ConsentStackProvider instead of the bare component:

app/layout.tsx
import { ConsentStackProvider } from "@consentstack/react"

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>
        <ConsentStackProvider siteKey="pk_your_site_key">
          {children}
        </ConsentStackProvider>
      </body>
    </html>
  )
}

The useConsent hook gives you the full picture: effective consent per category, the visitor's region, whether they have made an explicit decision yet, and a setConsent function to update it programmatically.

ConsentStatus.tsx
"use client"
import { useConsent } from "@consentstack/react"

export function ConsentStatus() {
  const { consent, region, hasDecision, isReady } = useConsent()

  if (!isReady) return null

  return (
    <p>
      Region: {region}, analytics:{" "}
      {consent?.analytics ? "granted" : "denied"}
    </p>
  )
}
Use hasDecision, not consent === null

consent is the visitor's effective consent, and it is populated from your consent model even before they choose. To tell whether someone has actually made a decision, read hasDecision. It is the difference between defaulted and chosen.

4. Let visitors change their mind

Regulations require an easy way to reopen and change consent. Drop PrivacyChoicesButton in your footer. It opens the preferences panel, and it switches its own label to "Do Not Sell My Personal Information" for California visitors automatically.

Footer.tsx
"use client"
import { PrivacyChoicesButton } from "@consentstack/react"

export function Footer() {
  return (
    <footer>
      {/* ...your footer links... */}
      <PrivacyChoicesButton className="text-sm text-gray-500" />
    </footer>
  )
}

Everything above works in the Next.js App Router. The provider and hooks are client components (they carry the "use client" directive), so put ConsentStackProvider in your root layout and it will wrap your server-rendered pages through the children prop. You only need "use client" on the components that call the hooks, not your whole tree. The same rule applies to analytics: do not drop a raw Google Analytics or GTM script into your layout and hope a cookie flag hides it. Gate it with useConsentValue so it never loads until the visitor opts in. A cookies-next boolean or a hidden script tag is not blocking, because the script has already run.

Verify it actually works

However you add consent, in React or anywhere else, do not take the banner's word for it. The only real test is what fires before and after a visitor makes a choice. Run your site through the free ConsentStack scanner: it loads your page, clicks Reject, clicks Accept, and reports exactly which trackers ran when. If something fires before consent, your banner is decorative.

See what your React app does before consent

Run your site through the free compliance scanner. No signup, no sales call. You will see every tracker that fires before and after a visitor chooses.

React cookie consent options at a glance
Capabilityreact-cookie-consentBuild it yourself@consentstack/react
Shows a bannerYesYesYes
Blocks trackers before consentNo, manualYou build itYes, automatic
Granular categoriesNoYou build itYes
Region-aware (GDPR vs US)NoYou build itYes
Honors GPC signalNoYou build itYes
Logs the consent decisionNoYou build itYes
Ongoing maintenanceYoursAll yoursHandled for you
PriceFree (MIT)Your dev timeFree plan, paid from $29/mo

react-cookie-consent is a fine choice when you genuinely only need a banner and you will handle blocking yourself. The moment you care about actually not leaking data, across regions, without babysitting it, a purpose-built consent layer is less code and less risk.

Frequently asked questions

Ship a React banner that actually blocks trackers

Create a free ConsentStack account, drop in @consentstack/react, and get a consent layer that blocks trackers before consent, handles GDPR and US rules, and installs in minutes.

Related Posts