Manage Cookie Consent Without a Paid CMP

How to handle cookie consent on a Laravel site without paying for a third-party CMP, using the whitecube/laravel-cookie-consent package.

For a long time, I simply had no cookie manager on my sites. Then came Google Consent Mode v2 with its share of texts, warnings, and supposed obligations. After reading all that, I thought I absolutely needed a certified third-party tool. So I installed CookieHub. But looking back, I realized I had mostly been overwhelmed by the marketing copy from those same tools, who have every interest in making you believe their subscription is indispensable.

The myth of mandatory CMPs

Everywhere, the same message: "You must use a Google-certified CMP, otherwise your Analytics data will disappear, your Ads campaigns will suffer…". Agencies, service providers, and SaaS tools took advantage of this to push their paid subscriptions. And honestly, for a while, I believed it.

But digging deeper, I realized this is a misleading shortcut. Google Consent Mode v2 is a consent signaling technology to Google. It does not require you to use a certified external platform. What Google asks is that consent signals are correctly sent. Nothing technically prevents you from doing this with your own manager, as long as the right signals go out.

In short: you are not legally required to have a subscription to a third-party CMP. You can absolutely handle this yourself.

While looking for a clean solution for my Laravel projects, I came across the package whitecube/laravel-cookie-consent. It really checks all the boxes:

  • 100% GDPR compliant: designed with legal experts
  • 🎨 Fully customizable: publishable Blade views, editable CSS
  • Works without JavaScript: consent submission uses plain HTTP requests (native forms). JS is used as an enhancement for better UX (async reload), but the core works without it
  • 🚀 Zero third-party CDN dependency: the banner is served directly by your application. No external requests, faster loading, and a better Google PageSpeed Insights score
  • 🌍 Multilingual: translations available including French
  • 🔧 Native Laravel integration: Service Provider, Facade, Blade directives

This package is part of my selection of tools discovered while building ilogus.fr. Discover other Spatie packages I use in my article: Essential Laravel Spatie Packages.

Installation

composer require whitecube/laravel-cookie-consent

Then publish the necessary files:

# The Service Provider
php artisan vendor:publish --tag=laravel-cookie-consent-service-provider

# The configuration
php artisan vendor:publish --tag=laravel-cookie-consent-config

# (Optional) Views for design customization
php artisan vendor:publish --tag=laravel-cookie-consent-views

# (Optional) Translation files
php artisan vendor:publish --tag=laravel-cookie-consent-lang

For Laravel 11+, add the provider in bootstrap/providers.php:

return [
    App\Providers\AppServiceProvider::class,
    App\Providers\CookiesServiceProvider::class,
];

My configuration

In App\Providers\CookiesServiceProvider, I only use two categories: essential cookies and Google Analytics. That's all I need.

use Whitecube\LaravelCookieConsent\Facades\Cookies;

protected function registerCookies(): void
{
    // Essential cookies: Laravel automatically handles session and CSRF
    Cookies::essentials()
        ->session()
        ->csrf();

    // Google Analytics: the script is only injected if the user accepts
    Cookies::analytics()
        ->google(
            id: config('cookieconsent.google_analytics.id'),
            anonymizeIp: config('cookieconsent.google_analytics.anonymize_ip')
        );
}

What's really elegant here: ->session() and ->csrf() automatically declare Laravel's internal cookies (session, XSRF-TOKEN…) without having to list them manually. And ->google() injects the Analytics script into the <head> only if the user has given consent. Zero tracking before agreement, in one line.

Integration in views

In the main layout, two directives are enough:

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- ... -->
    @cookieconsentscripts
</head>
<body>
    <!-- ... -->
    @cookieconsentview
</body>
</html>

An often overlooked point: the cookie policy page must list all cookies used, their duration, and their purpose. The package directly exposes the data declared in the provider, allowing you to generate this page dynamically, without ever having to maintain it manually:

<div class="legal-content">
    <p class="legal-intro">
        {{ __('messages.legal_cookies_intro') }}
    </p>

    @foreach($categories as $category)
        <div class="cookie-category">
            <h2>{{ $category->title }}</h2>
            @if($category->description)
                <p class="category-description">{{ $category->description }}</p>
            @endif

            <div class="cookie-table-wrapper">
                <table class="cookie-table">
                    <thead>
                        <tr>
                            <th>{{ __('messages.legal_cookies_table_name') }}</th>
                            <th>{{ __('messages.legal_cookies_table_purpose') }}</th>
                            <th>{{ __('messages.legal_cookies_table_duration') }}</th>
                        </tr>
                    </thead>
                    <tbody>
                        @foreach($category->getCookies() as $cookie)
                            <tr>
                                <td><code>{{ $cookie->name }}</code></td>
                                <td>{{ $cookie->description }}</td>
                                <td>
                                    {{ \Carbon\Carbon::now()->diffForHumans(\Carbon\Carbon::now()->addMinutes($cookie->duration), true) }}
                                </td>
                            </tr>
                        @endforeach
                    </tbody>
                </table>
            </div>
        </div>
    @endforeach

    <div class="legal-block">
        <h2>{{ __('messages.legal_cookies_management_title') }}</h2>
        <p>{!! __('messages.legal_cookies_management_content') !!}</p>
        <p>
            @cookieconsentbutton(action: 'reset', label: __('messages.legal_cookies_management_button'), attributes: ['class' => 'legal-link'])
        </p>
    </div>

    <div class="legal-notice">
        <p><small>{{ __('messages.legal_cookies_notice') }}</small></p>
    </div>
</div>

The reset button at the bottom allows users to change their consent at any time. This is a GDPR legal requirement often forgotten, and here it's just a directive.

CSS customization

I didn't publish the Blade views. I simply targeted the id of the banner generated by the package to override the CSS:

/* The banner is rendered in a <aside id="cookies-policy"> */
#cookies-policy .cookies__title {
    color: var(--text-primary);
    font-weight: 700;
    line-height: 1.4em;
    margin-bottom: 0.8em;
}

That's enough to adapt it to the site's design without touching the vendor views.

⚠️ Important note: when a certified CMP becomes mandatory

Everything above applies to a specific case: a site that uses only analytical or functional cookies (like Google Analytics), without programmatic advertising or data resale.

If you serve ad banners through networks like Google AdSense or Ad Manager, the situation is different. In this case, you fall under the IAB TCF (Transparency and Consent Framework), a European standard that requires using a certified CMP to transmit consent signals to the entire programmatic advertising chain. Since February 2026, Google explicitly requires this certification to continue serving ads in the EEA. Without a TCF v2.3 compatible CMP, you are simply excluded from bidding.

In summary:

  • Showcase site / blog / analytics only → a solution like whitecube/laravel-cookie-consent is sufficient, legally and technically
  • Site with programmatic advertising or data resale → an IAB TCF certified CMP (Cookiebot, Didomi, Axeptio...) is mandatory

Key takeaways

For Laravel projects without ultra-complex needs, this package is a clean, lightweight, and economical solution. No need to pay for CookieHub or others when you have full code control, a dynamically generated policy page, and Google Analytics integration in one line.

Another notable benefit: no dependency on a third-party CDN. The banner is entirely served by your own application, which directly translates to faster loading and a better Google PageSpeed Insights score. A detail often forgotten when you slap a CookieHub or Cookiebot script at the bottom of the page.