pierre-brtrd/cookie-consent-bundle
A Symfony bundle for adding a configurable cookie consent banner to your application, letting visitors accept or reject cookies and helping you meet GDPR and ePrivacy requirements with minimal setup. Provides templates, configuration options, and JavaScript hooks for customizing consent behavior.
Before you run composer require, confirm what you are actually installing. The name, the repo path, and the description ("Symfony bundle") all point to a Symfony bundle, not a Laravel package. Check for a Laravel service provider before assuming auto-discovery:
composer require pierre-brtrd/cookie-consent-bundle:^1.0
composer show pierre-brtrd/cookie-consent-bundle
Then inspect composer.json for extra.laravel.providers and extra.symfony. If it only declares a Symfony Bundle class and Twig templates, you are bridging a Symfony component into Laravel, not consuming a Laravel package:
php artisan vendor:publish # expect little or nothing to publish
Look here first: the package's config/ tree and its Twig template under Resources/views (Symfony convention). That is where consent categories, cookie name/lifetime, and banner markup are defined. Read the config before the README — the config is the real API surface, and this package has almost no prose documentation. The v1.0.2 release notes are only a compare link, so if you are already on 1.0.1 in staging, diff it before deploying to production.
First use case — get one round-trip working:
necessary, analytics, marketing) in the config, matching the package's config keys.resources/views/layouts/app.blade.php. Because the package ships Twig, you will either port the template to Blade (usually a 30-line file) or use TwigBridge if it is already in your stack.<script> fires only after opt-in → reload does not re-show the banner.Do not wire every category, the preference center, or audit logging until this single loop is green. The rest is repetition of the same pattern.
Treat the package as a component, not a framework integration. For a Laravel app, the pragmatic day-to-day pattern is: reuse the package's config schema, cookie contract, and template as inspiration, and write a thin ConsentManager service in your app that owns the actual reads/writes. That gives you a working banner in an afternoon and keeps a future swap (to a real CMP, or a Laravel-native package) to one class.
Bind a ConsentManager singleton in your own service provider so call sites stay clean:
class CookieConsentServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->singleton(ConsentManager::class, function ($app) {
return new ConsentManager(
$app['request']->cookies->all(),
config('cookie-consent.categories'),
config('cookie-consent.cookie_name', 'cookie_consent'),
);
});
}
}
Expose allows(string $category): bool, granted(): bool, and record(array $payload): void. Consume that interface in Blade, middleware, and tests — never the package's raw classes.
Banner in the base layout, state in a middleware / service. Put the banner partial in layouts/app.blade.php so it is present on every page, but do not read cookies in the view. Let a middleware (or the service above) resolve consent and share it with View::share('consent', $manager). Views render state; they never own it.
Consent is a server-side concept too. Do not rely only on the client-side cookie. When the user accepts, POST the choice to an endpoint and persist it (user id or generated consent id, categories, timestamp, policy version, IP or region if required). This is what gives you the audit trail GDPR actually asks for, and it lets you gate server-rendered tags:
@if(app(\App\Support\ConsentManager::class)->allows('analytics'))
<script src="https://www.googletagmanager.com/gtag/js?id=..."></script>
@endif
Blade component for script gating. Wrap third-party snippets in a component that renders <script type="text/plain" data-consent="analytics">, plus a ~20-line framework-free JS shim that activates them on opt-in. Adding a new tracker then becomes a one-line change:
<x-consent-script category="marketing" src="https://connect.facebook.net/..."/>
Derive everything from one category array. The banner checkboxes, the stored payload, and the allows() checks should all come from config/cookie-consent.php. The most common bug in consent code is defining analytics in three places and drifting — e.g. the banner says the user accepted analytics but the stored JSON says analytics_v2.
Version the consent record. Store policy_version alongside the categories. When copy or categories change, bump the version and treat older records as unconsented (re-show the banner). Retro-fitting this after a legal review is painful and risks invalidating historical consents.
Testing — one test per category, both directions. Use cookies in feature tests to drive the manager:
$this->withCookie('cookie_consent', json_encode([
'necessary' => true,
'analytics' => true,
'marketing' => false,
]))->get('/')->assertSee('ga-js');
Then flip analytics to false and assert the snippet is absent. Repeat per category. This is where most of your regression risk lives.
extra.laravel block, and 0 dependents. Everything past the config is likely something you reimplement in Blade. Budget for that up front rather than discovering it at vendor:publish time.tests/ directory, CI config, security contact, and supported PHP version range. A consent package is security- and compliance-relevant; a stale repo is a real operational risk. Pin ^1.0, and isolate the integration behind your own ConsentManager so a repo abandonment story is a one-file swap.true, override it in your config/cookie-consent.php. This is a compliance bug, not a preference, and the banner looks fine either way — you have to read the config to catch it.spatie/laravel-responsecache, Cache-Control) can serve a banner-state or gated snippet to the wrong user. Either exclude consent-dependent fragments from the cache or resolve consent client-side for cached pages.SameSite / Secure on local HTTP. "It never remembers my choice" almost always traces to a SameSite=Strict or Secure cookie being dropped on http://localhost or a cross-site POST. Inspect document.cookie and $request->cookie('cookie_consent') before blaming the package._ga, Meta _fbp, etc.). Consent must be as easy to withdraw as to give; leaving users stuck is itself a compliance finding.How can I help you explore Laravel packages today?