Devtools for Next.js
A panel for your dev server that shows what the SDK is doing and lets you test consent, regions, languages and third-party scripts. Production builds leave it out.
What it does
@cookieyes/devtools adds a floating panel to your site while you develop. It shows the visitor's consent, what the SDK loaded or blocked, and the Google Consent Mode signals sent. It also lets you test other regions and languages without a VPN, and finds third-party scripts that load without consent.
A production build leaves the panel out completely, code and styles, so you can keep it mounted.
Set it up
Install it as a dev dependency:
npm install --save-dev @cookieyes/devtoolsCreate a small client component for it:
"use client";
import { CookieYesDevtools } from "@cookieyes/devtools";
import "@cookieyes/devtools/styles.css";
export function DevtoolsRoot() {
return <CookieYesDevtools />;
}Render <DevtoolsRoot /> once, in app/layout.tsx, next to your consent UI. In the root layout it stays mounted when you navigate, so its history and the Scanner's timings cover the whole visit.
A CookieYes button appears in the bottom-right corner once the SDK has started.
- Click the button, or press
Ctrl+Shift+Y(Cmd+Shift+Yon a Mac), to open or close the panel.Escapecloses it. - Drag the button to another corner. It snaps there and remembers it.
Show which header decided the region
The panel runs in the browser, so it cannot see the request headers that decided the visitor's region. Read them on the server with getServerRegion() and pass the result to the panel. Pass its forcedRegion to CookieYesProvider too, so the server-rendered banner follows a region you force in the panel.
"use client";
import { CookieYesDevtools, type CookieYesDevtoolsProps } from "@cookieyes/devtools";
import "@cookieyes/devtools/styles.css";
export function DevtoolsRoot({ serverRegion }: Pick<CookieYesDevtoolsProps, "serverRegion">) {
return <CookieYesDevtools serverRegion={serverRegion} />;
}import { CookieYesProvider, type RegionConfig } from "@cookieyes/nextjs";
import { getServerRegion } from "@cookieyes/nextjs/server";
// Your consent manager from Installation, and the region config you pass to it.
declare function CookieYesRoot(): React.ReactElement;
declare const region: RegionConfig;
export default async function RootLayout({ children }: { children: React.ReactNode }) {
const serverRegion = await getServerRegion();
return (
<html lang="en">
<body>
<CookieYesProvider region={region} forcedRegion={serverRegion.forcedRegion}>
<CookieYesRoot />
{children}
</CookieYesProvider>
<DevtoolsRoot serverRegion={serverRegion} />
</body>
</html>
);
}getServerRegion() reads request headers, which makes the route dynamic. In a production build its forcedRegion is always undefined.
Props
| Prop | Type | Default | What it does |
|---|---|---|---|
position | "bottom-right" | "bottom-left" | "top-right" | "top-left" | "bottom-right" | The corner the button starts in. |
theme | "system" | "light" | "dark" | "system" | The panel's colour scheme. The switch in the panel header overrides it. |
serverRegion | the result of getServerRegion() | none | Lets the Locale tab show which request header decided the region. Next.js only. |
The tabs
| Tab | Use it to |
|---|---|
| Consent | See each category's saved value next to the unsaved one. Toggle categories, save, accept or reject all, or reset so the banner shows again. |
| Integrations | Check each integration's status: idle (waiting for consent), loading, active, silenced, removed or error. |
| Blocked | See the requests the network blocker stopped. |
| Consent Mode | See the Google Consent Mode signals now, and every update sent. |
| Events | Follow consent saves, integration changes and blocked requests in order. Search, filter and export them. They survive a reload. |
| Locale | Check which region and regulation apply and why. Test another region or language. |
| Scanner | Find third-party scripts, requests and cookies, and anything that loaded without consent. |
| Actions | Open the preferences or opt-out dialog, copy the state, download a debug file for a bug report, or reset consent. |
Test another region or language
Region. In the Locale tab, pick a country or US state, or type a code such as US-TX. Each option shows the regulation it would get. A forced region applies on the next page load, so the tab shows Not applied yet with a Reload now button until you reload. While a region is forced, a warning says the result would differ in production. Press Clear, then reload, to go back to the real region.
Language. Pick a language in the same tab. The banner switches straight away and keeps it after a reload, until you press Reset. The list shows the languages your config loads and the ones in @cookieyes/translations. If a language has no translations, the tab says so and the banner stays as it was.
Find scripts that load without consent
The Scanner tab watches the page from the moment it loads. It lists scripts, iframes and requests from other sites, plus cookies and localStorage keys, and marks each one:
- Managed: the SDK loads or gates it.
- Unmanaged: a known tool the SDK does not control. Open the row to copy the code that would gate it.
- Necessary: needs no consent, such as payments or bot protection.
- Unclassified: not a tool the Scanner knows. Decide its category yourself.
Anything that appeared before its category was granted is flagged before consent. Anything that appeared, or stayed, after consent was withdrawn is flagged after withdrawal. Categories for unmanaged tools come from a built-in list of common vendors, so treat them as suggestions. Dismiss findings you have checked, and export the list as JSON.
Good to know
- It is left out of production. The package points a production build at an empty component and an empty stylesheet. You need no flag or environment check, and you can leave both imports in place.
- Overrides only work in development. A production build of the SDK ignores the forced-region cookie, even one set by hand.
- Nothing leaves the browser. The panel keeps its settings and history in the browser's own storage.
- The opt-out action needs CCPA. Visitors only reach the opt-out dialog under CCPA, so the action is disabled under other regulations.
- The Scanner cannot see everything. Cookies marked
HttpOnly, and requests made inside iframes from other sites, are invisible to code in the page.
Common mistakes
The panel does not appear.
You are running a production build (next start, vite preview), or the SDK has not started on the page. Use your dev server, and check that the SDK is initialised.
The panel has no styling.
The stylesheet import is missing. Add import "@cookieyes/devtools/styles.css" next to the component.
A forced region changes nothing.
Reload the page after forcing it. If the tab says the override has no effect, your config sets regulation directly, which always wins over the region.
Open preferences says nothing renders the dialog.
The page has no preferences dialog. Add CookiePreferences, or CookieOptOut for the opt-out action.
Next steps
- Network blocking: block requests the Scanner finds but you cannot gate
- Integrations: load common tools only after consent
- Translations: add the languages you test in the Locale tab