Platforms

How to add a cookie consent banner to a Laravel app

In Laravel, paste the snippet in the head of the Blade layout every page extends (resources/views/components/layout.blade.php or resources/views/layouts/app.blade.php), above @vite and any other script. Read the site key from config/services.php rather than calling env() in the view, and mark tracking tags in the same layout. Livewire's wire:navigate needs no extra code: the banner stays in place across visits.
Published 21 October 2026 · By the Cookiequiet team · Markdown

Steps

Copy the snippetIn the Cookiequiet dashboard, add the website and copy the snippet with your site key, data-consent-mode="1" and data-auto-block="1".
Store the key in configAdd COOKIEQUIET_SITE to .env and a cookiequiet entry to config/services.php that reads it with env(), so the value survives php artisan config:cache.
Paste the snippet in the layoutOpen the layout every page uses and paste the snippet in the head, above @vite and any other script, with data-site set from config('services.cookiequiet.site').
Mark your tagsPaste analytics and advertising tags below the snippet with type="text/plain" and data-cq-category, inside @production if they should only run in production.
Handle Livewire or InertiaWith wire:navigate, send per-page code such as page views from a livewire:navigated listener. With Inertia, gate components as the React or Vue guide shows.
Add the Cookie preferences linkIn the footer partial, add a plain anchor with href="#cq-preferences" and the data-cq-show-preferences attribute.
Test with Reject allOpen the site in a private window, click Reject all and check that only cq_consent and your session cookies are set. Accept all, reload and check the consent log.

Where does the snippet go in Laravel?

Laravel pages share a Blade layout: a component such as resources/views/components/layout.blade.php rendered with <x-layout>, or a parent view such as resources/views/layouts/app.blade.php that child views name with @extends. Paste the snippet in the head of that layout, above @vite and any other script:

blade
{{-- resources/views/layouts/app.blade.php --}}
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cookiequiet.com/cq.js" data-site="{{ config('services.cookiequiet.site') }}" data-consent-mode="1" data-auto-block="1" defer></script>
<title>{{ config('app.name') }}</title>
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body>
@yield('content')
</body>
</html>

Keep the key in config. Add COOKIEQUIET_SITE=your-key to .env and read it in config/services.php:

php
'cookiequiet' => [
'site' => env('COOKIEQUIET_SITE'),
],

Laravel's documentation warns that once php artisan config:cache has run, the .env file is no longer loaded and env() only returns system-level environment variables, so it should only be called in configuration files. Calling config() in the view avoids an empty data-site in production.

If the app has several layouts (a guest layout for login pages, an app layout for signed-in users), put the snippet in each, or in a partial they all include with @include.

Paste tracking tags under the snippet and change their opening tag. Blade's @production directive keeps them out of local and staging environments:

blade
@production
<script type="text/plain" data-cq-category="analytics" src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX"></script>
<script type="text/plain" data-cq-category="analytics">
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXX');
</script>
@endproduction

Cookiequiet runs marked tags when the category is granted, and at once on later visits where the stored choice includes it. The Google Analytics 4 guide covers the Consent Mode alternative and the Meta Pixel guide the pixel. Tags pushed from child views with @push into a stack in the head work the same way, as long as the stack is printed below the snippet. Scripts added at runtime by JavaScript are held by the auto-blocker when they come from one of the about 80 trackers it knows.

What about Livewire and Inertia?

Livewire with wire:navigate. Livewire's documentation says scripts in the head run only on the first visit, so the snippet runs once and the stored choice stays applied. It also says the whole body is replaced on each visit. The banner's container lives in the body, and Cookiequiet puts it back into each new body, so a banner waiting for an answer, the preferences button and showPreferences() keep working without extra code.

Keep marked tags in the layout head, and listen for livewire:navigated, which fires after every navigation and on the first load, for code that sends page views.

Inertia. The root template (resources/views/app.blade.php with @inertiaHead) takes the snippet above @vite. The pages are React or Vue components, so read the choice in them as the React and Vue guides show, with the cq:consent event Cookiequiet dispatches on window each time it applies a choice.

In the footer partial:

html
<a href="#cq-preferences" data-cq-show-preferences>Cookie preferences</a>

How do I test it?

  1. Run php artisan config:cache once to check that the key still renders, then view the page source: cq.js is the first script in the head.
  2. Open the site in a private window and click Reject all. The cookies are cq_consent, your session cookie and XSRF-TOKEN: these two are Laravel's own, set for every visitor, and are strictly necessary.
  3. Clear the cookies, click Accept all, reload: the marked tags run.
  4. With wire:navigate, open a second page before choosing: the banner stays visible.
  5. Check the consent log in the dashboard.

A Content Security Policy must allow https://cookiequiet.com in script-src and connect-src. Cookiequiet is free for one website with geo-targeting; Starter is €3 per website per month with unlimited pageviews.

Questions

No. The banner is one script tag in your Blade layout, with the site key read from config. There is nothing to install with Composer or npm.
Laravel's documentation says that once the configuration is cached, the .env file is not loaded and env() only returns system-level environment variables, so env() belongs in configuration files only. Reading the key through config/services.php keeps it working after php artisan config:cache.
They keep the session and protect forms against cross-site request forgery, which makes them strictly necessary in most readings of the ePrivacy rules. List them in the cookie table as necessary; the banner does not block them.
Yes. The script in the head runs once and the choice stays applied. Livewire replaces the body on each visit, and Cookiequiet moves its banner's container into the new body by itself, so a visitor who navigates before choosing still sees the banner.

Put a quiet banner on your website today

Free for one website with every core feature, no card and no trial clock. Upgrade a website to Starter for $3 a month to match your brand with AI and drop the branding, or to Pro for $9 to design it with the AI agent.