Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Cookie Consent Bundle Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

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:

  1. Define three or four categories (necessary, analytics, marketing) in the config, matching the package's config keys.
  2. Render the banner markup in 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.
  3. Gate one non-essential script — analytics — on stored consent.
  4. Verify: banner shows on first visit → choice persists to a cookie → the analytics <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.

Implementation Patterns

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.

Gotchas and Tips

  • Framework mismatch is the headline risk. It is a Symfony bundle with Twig templates, no 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.
  • One star, single maintainer, no test evidence. Verify before adoption: license file present (MIT per metadata), a 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.
  • The cookie name and payload shape are a de facto contract. Once users have consented, renaming the cookie or reshaping the JSON silently invalidates everyone's consent (or, worse, marks them as consented with a shape you no longer read correctly). Wrap all reads in an adapter so the package's storage format never leaks into views, middleware, tests, and mail templates.
  • Consent must be opt-in, never pre-checked. If the config defaults any non-necessary category to 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.
  • Never gate necessary cookies. Session, CSRF, auth, and cookie-set-by-framework must load unconditionally. Gate only analytics/marketing. Getting this backwards produces a "login randomly fails for EU users" bug — the worst kind, because it looks like a session bug, not a consent bug.
  • Verify that non-essential scripts actually do not fire before consent. The most common false-compliance failure is a banner that records a choice but leaves the analytics snippet loading normally. Open DevTools → Network, clear cookies, reload, and look for the request to Google/Meta/Hotjar before you click Accept. If it appears, your gating is broken.
  • Cache layers. Full-page caches (CDN, 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.
  • No external JS dependencies is a genuine win. That means no bundler step, no framework widget to maintain, and it keeps the shim portable to a future CMP. Preserve that — don't add Alpine/React around the banner just to style it.
  • Provide revocation, not just acceptance. A persistent "Cookie settings" link in the footer that reopens the banner and clears previously set tracker cookies (GA _ga, Meta _fbp, etc.). Consent must be as easy to withdraw as to give; leaving users stuck is itself a compliance finding.
  • Extension points to look at in the source (before you fork): the config tree (categories, cookie lifetime, template override path), the renderer/template (so you can swap in a Blade view), and any event or callback fired on consent change — hooking there is much cleaner than subclassing a Symfony class in a Laravel app.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums