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.Steps
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.
How do I block my tags until consent?
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.
How do I add the Cookie preferences link?
In the footer partial:
html<a href="#cq-preferences" data-cq-show-preferences>Cookie preferences</a>
How do I test it?
- Run
php artisan config:cacheonce to check that the key still renders, then view the page source:cq.jsis the first script in the head. - Open the site in a private window and click Reject all. The cookies are
cq_consent, your session cookie andXSRF-TOKEN: these two are Laravel's own, set for every visitor, and are strictly necessary. - Clear the cookies, click Accept all, reload: the marked tags run.
- With wire:navigate, open a second page before choosing: the banner stays visible.
- 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.