React Components
DevTools
DevTools is a floating panel for the c15t v3 kernel. Use it during development to inspect consent values, scripts, location, the resolved policy, IAB state, events, and consent actions. The framework adapter reads the kernel from the nearest v3 provider. It never discovers a store through a window global.
Warning
Load DevTools only in development. A conditional JSX expression stops it from mounting in production, but a static import can still add DevTools to the production bundle. Use a development-only dynamic import as shown below. The component renders nothing into the React tree and mounts its panel in document.body.
Installation
No extra package is required. The React adapter and its engine are included
with the c15t package. Install @c15t/dev-tools directly only when you
need the imperative createDevTools({ kernel }) API.
Render DevTools in development builds
Render DevTools inside ConsentProvider. This example loads it only in
development with Vite's import.meta.env.DEV flag, so production bundles never
download it. For another bundler, use its development flag instead; for
example, webpack projects can use a configured
process.env.NODE_ENV === 'development' replacement, since process is not a
browser global.
Render <ConsentDevTools /> inside the provider from your
quickstart, next to the banner. Import the
component from c15t/react/devtools when you installed the c15t package, or
from @c15t/react/devtools when you installed @c15t/react directly.
@c15t/dev-tools exports the imperative engine, not the React component.
If the CLI cannot identify your bundler's development flag, it generates
const DevTools = false with a setup comment. Replace false with your
configured build-time development flag to enable the panel. The fallback keeps
DevTools disabled instead of assuming browser globals or loading it in production.
Configuration
position accepts any corner: top-left, top-right, bottom-left, or
bottom-right. Set defaultOpen to open the initial panel and defaultTab
to choose that panel. maxEvents limits captured kernel and script events.
Set disabled to prevent mounting without removing the component. The
panel renders inside a shadow root by default, so page CSS does not reach
it. shadow={false} mounts it in the light DOM with its stylesheet in
<head>.
Open DevTools from the consent trigger
While ConsentDialogTriggerToolbar or the ready-made ConsentDialogTrigger
is visible, the trigger shows a DevTools button and DevTools hides its own
floating launcher, so one control occupies the corner. The button sits at the
end of the toolbar farthest from its corner. The panel opens just past the
toolbar, aligned with its outer edge, and follows it when a visitor drags the
toolbar to another corner. position applies again once no trigger is
visible.
ConsentDialogTrigger becomes a two-button toolbar while DevTools is
mounted. A trigger composed from ConsentDialogTrigger.Root keeps its own
markup, and DevTools keeps its floating launcher beside it.
DevTools brings its launcher back whenever no trigger is visible, for example
while showWhen="after-prompt" waits for a choice. A production build that
loads DevTools only in development shows no DevTools button in the trigger.
With the imperative engine, call devTools.dock({ position, inline, block })
to hide the launcher and anchor the panel inline and block pixels from the
viewport edges of position's corner. Call devTools.dock(null) to restore
the launcher.
Panels
Accept and reject apply only to categories displayed by the provider, leaving
hidden consent values unchanged. necessary always remains enabled. The
React adapter uses the current policy categories by default.
For an imperative integration with a narrower UI, pass
getConsentCategories: () => ['necessary', 'measurement'] to
createDevTools. The getter is read again when an action runs. Headless UI
actions can use kernel.commands.save('all', { categories: displayed }) or
kernel.commands.save('none', { categories: displayed }). These scoped bulk
saves use a custom transport action when they cover only part of the policy.
Actions covering the whole policy retain all or necessary. Without an
explicit scope or policy categories, bulk saves cover all known categories.
| Panel | What it shows |
|---|---|
| Consents | Inspect and save categories, accept all, or reject optional categories |
| Scripts | Configured scripts, loading status, search, and external page resources |
| Location | Resolved country and region, and location overrides |
| Policy | Resolved policy and UI configuration |
| IAB | Edit vendors, purposes, legitimate interests, and special features; save and copy TC strings |
| Events | Timeline of consent changes, kernel events, and script lifecycle events |
| Actions | Show the banner, open preferences, hide consent UI, or refresh consent data |
Script inspection
Set defaultTab="scripts" to open script inspection first. It reads all script
loaders attached to the current provider's kernel, including loaders created
before DevTools mounts. Search by script ID, category, URL, or status, then
expand a script to inspect its configuration and latest lifecycle event.
loading means an external script was inserted; loaded means its browser
load event fired, or an inline script or callback-only integration mounted.
error reports a loader error. blocked means consent requirements were not
met, and pending means an eligible script has not mounted. present means
the loader reused an element without a confirmed load result. retained
means consent was revoked but persistAfterConsentRevoked kept the element.
Retained scripts still receive onConsentChange with hasConsent: false, so
their integrations can send the vendor's consent-revocation command.
alwaysLoad bypasses the loading gate, not consent: callbacks receive the
actual consent state and updates across categories for integrations such as
Google Consent Mode.
Script details distinguish allowedToLoad from consentGranted. An
alwaysLoad integration can be allowed to load while its consent is denied.
Diagnostics expose these as eligible and hasConsent, respectively.
Lifecycle diagnostics work even when legacy debug forwarding is disabled. The page scan lists external scripts and iframes present in the DOM; it does not prove that they loaded successfully or were consent-gated.
For custom inspection tools, import getScriptDiagnostics(kernel) and
subscribeScriptDiagnostics(kernel, listener) from
c15t/modules/script-loader. The subscription reports loader
registration, updates, disposal, and lifecycle events. Read a fresh snapshot
after changes and call the returned unsubscribe function during cleanup.
IAB editing
Under an IAB policy, the Consents tab is read-only. Edit and save vendors and purposes in the IAB tab so the derived categories and TC string stay consistent.
The IAB panel connects to the existing @c15t/iab module attached to the
provider's kernel. It does not create a second CMP or replace __tcfapi.
Controls become available after initialization, when the current policy uses
IAB and the vendor list is loaded.
Choose Vendors, Purposes, or Special features, then search by name or ID. Vendors include the provider's custom vendors. Long lists show 20 entries per page. Legitimate-interest controls appear for declared legitimate interests. Search only filters the view; Accept all IAB and Reject all IAB apply to the configured choices, including custom vendors.
Toggles update live IAB state and script gating immediately. Use Save IAB consent to generate a fresh TC string and run the configured save transport. The panel displays the last generated string; unsaved edits are not represented in it. Copy TC string confirms success or reports clipboard failures. Raw IAB data remains available in an expandable section.
IAB saves normally write the TC string to its standard cookie and localStorage.
For an in-memory playground, set persistence: false in the IAB module options
as well as disabling the provider's core persistence. The IAB option prevents
TC-string storage writes; it does not disable the configured save transport
or remove previously stored values.
Save and refresh actions show pending, success, and failure feedback. Controls are disabled while a request is pending. A failed save does not roll back the live choices; retry to record them.
For custom inspection tools, getIABControls(kernel) and
subscribeIABControls(kernel, listener) are exported from c15t.
The getter returns undefined before module initialization and after disposal.
A snapshot without an attached IAB module is read-only in DevTools.
TanStack Devtools
Each embedded panel owns its event history and subscriptions. Unmounting it destroys the instance; remounting starts a new history. If you need to capture events while switching plugins, keep the c15t panel mounted. This differs from the old globally shared DevTools store.
The React v3 DevTools adapter exports a panel component and plugin factory that match TanStack Devtools' plugin API:
In a Next.js app, import c15tDevtools from c15t/next/devtools instead. Scoped installs use @c15t/react/devtools and @c15t/nextjs/devtools.
The c15t panel follows the TanStack Devtools light or dark theme, not your app's consent theme. If you write the plugin entry yourself, use a render function and pass the theme to C15tTanStackDevtoolsPanel:
Props
Warning: ExtractedTypeTable: Could not extract "ConsentDevToolsProps" from "./packages/react/src/devtools.tsx" using base path "/vercel/path0/apps/c15t-docs/.leadtype/c15t". Verify the path/name and that the file is included by your tsconfig.