Skip to main content

Next.js Customization

shadcn/ui

Use your project's shadcn components for the consent banner and preferences. The registry copies the markup into your app. c15t's headless hooks handle consent state, policy actions and translations.

This setup is for the Next.js App Router with a server. For the Pages Router or static export, keep the setup from the Pages Router or static export guide and follow Use an existing ConsentRoot.

Before you start

Initialize shadcn/ui for Next.js. The registry supports Radix, Base UI and React Aria styles and installs c15t 3.2 or later as a dependency.

The generated setup uses an Inth backend. Create an Inth project, configure its policy rules, add your site's origin to its trusted origins, and copy its backend URL. A self-hosted backend works with the same setup and your own URL. For browser-only storage without consent records, see consent modes.

npx shadcn add @c15t/next-consent-manager

This installs c15t.config.ts at the project root and a ConsentManager component, usually under components/c15t/. Its dependencies include the banner, preference dialog, floating preferences button and the shadcn UI components they use. You do not need to install the banner separately.

If the CLI cannot find the @c15t namespace, merge this entry into components.json and rerun the command:

components.json
{
  "registries": {
    "@c15t": "https://c15t.com/r/{style}/{name}.json"
  }
}

Set your backend URL

The installer adds a demo backend URL. Replace it in .env.local and set the same value in your host's build settings:

.env.local
NEXT_PUBLIC_C15T_BACKEND_URL=https://your-project.inth.app

Use the URL from your Inth project. It is public configuration. Next.js inlines it at build time, so rebuild after changing it.

The generated c15t.config.ts leaves mode unset, which defaults to manifest(). Next.js resolves each visitor's consent from the policy bundled during the build. Choices are sent to your Inth backend for recording.

Connect Next.js

Wrap your existing Next.js config with withConsentManifest:

next.config.ts
import { withConsentManifest } from 'c15t/next/build';
import type { NextConfig } from 'next';

const nextConfig = {} satisfies NextConfig;

export default withConsentManifest(nextConfig);

The plugin discovers the generated c15t.config.ts. Keep that file's default export and add consent-gated scripts there using the scripts guide. Rebuild after changing policy rules, translations or vendors in Inth.

In app/layout.tsx, import ConsentManager from your generated component. With the default components alias, its import path is @/components/c15t/consent-manager. If aliases.components in components.json differs, use your configured alias. Inside <body>, wrap {children} in <ConsentManager>{children}</ConsentManager>. Keep the layout and the generated manager as Server Components.

The manager already renders ConsentRoot, the banner, the dialog and a floating button that reopens preferences after the banner closes. It passes resolveConsent() without awaiting it, so the page can stream while consent resolves. See rendering and deployment for cached pages and other rendering options.

Location-based policies need trusted geography headers. Without location data, c15t applies your unknown-location rule.

Use an existing ConsentRoot

If c15t already runs in your app, keep your existing root and config. Install the UI items directly:

npx shadcn add @c15t/next-consent-banner @c15t/next-consent-dialog @c15t/next-consent-dialog-trigger

Import these components from your generated components/c15t/ files and render them inside the existing ConsentRoot, replacing the stock banner, dialog and preferences control. Do not nest another ConsentRoot or ConsentProvider.

Customize and verify

Edit the files in components/c15t/ to change markup or Tailwind classes. They use your project's shadcn components and theme. Keep the headless hooks' policy actions and a way to reopen preferences. Updating c15t updates consent logic; the copied markup remains yours to maintain.

The registry also includes a preference sheet, an inline widget and an embed gate. Install them as @c15t/next-consent-sheet, @c15t/next-consent-widget or @c15t/next-consent-gate. For custom controls, see the headless guide.

There are no shadcn IAB TCF components yet. For IAB policies, use the IAB setup and its TCF UI.

Run your app and open a fresh browser session under an opt-in policy. Check that the banner appears, saving a choice closes it, and the floating button reopens preferences. Reload and confirm the choice persists. In the Network panel, choices should post to your backend's /subjects endpoint. Also verify vendor requests and consent signals, including loaders already in your app. The banner does not block scripts loaded outside c15t. Remove or migrate loaders that bypass your consent policy.