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

indigophp/cookie-consent-bundle

Symfony bundle for GDPR-friendly cookie consent. It shows a customizable consent banner, lets visitors accept or reject cookie categories, and stores their choices so analytics, tracking, and other scripts load only after permission is granted.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first: this is a Symfony Bundle, not a Laravel package. There is no service provider, no facade, no auto-discovery, no Blade views. composer require indigophp/cookie-consent-bundle will pull in symfony/framework-bundle and twig/twig transitive dependencies that your Laravel app will never instantiate. The repo is also archived — treat it as reference source, not a dependency.

Where to look first (in the GitHub repo, not in vendor/):

  • Resources/ — the front-end JS/CSS assets wrapping the upstream Cookie Consent plugin. This is the only artifact with day-to-day value.
  • The bundle's DI Configuration.php / Extension — read it as a spec for the config surface (theme, position, copy, policy URL, categories, accept/deny callbacks). Port the shape into config/cookie-consent.php; discard the Symfony plumbing.
  • The default Twig template — a 20-line starting point for your Blade partial.

Minimal first use case (30–60 minutes):

  1. composer remove indigophp/cookie-consent-bundle if you already added it (keep vendor/ around until you've copied assets out).
  2. Copy Resources/public/* into resources/vendor/cookie-consent/ or, better, npm i cookieconsent (the upstream osilviotti/cookieconsent package) and import it in resources/js/app.js.
  3. Publish a config file: php artisan vendor:publish won't work — just create config/cookie-consent.php by hand with enabled, policy_url, theme, position, categories keys.
  4. Create resources/views/components/cookie-consent.blade.php and include it once in layouts/app.blade.php, guarded by @if(config('cookie-consent.enabled')).
  5. Initialize on DOMContentLoaded with a callback that only then loads GA4 / Meta Pixel.

That's the whole "integration" — the bundle saves you maybe an hour of figuring out the JS options object.

Implementation Patterns

Config-as-spec port. Lift the bundle's option tree verbatim into config/cookie-consent.php so the mental model carries over:

return [
    'enabled'    => env('COOKIE_CONSENT_ENABLED', true),
    'policy_url' => '/privacy',
    'theme'      => 'light',
    'position'   => 'bottom',
    'categories' => ['necessary', 'analytics', 'marketing'],
];

Blade component with Alpine.js for state. The bundle delegates state to the JS plugin; do the same but keep your own localStorage key so you control versioning:

<div x-data="cookieConsent()" x-show="!decided" …>

Store {version, timestamp, categories} — Legal will eventually ask for the version so you can re-prompt after a policy change.

Service-provider-only wiring. Unlike the Symfony bundle, everything goes in AppServiceProvider::boot() — config merge is unnecessary (Laravel merges config/ automatically) and asset registration is a Vite::asset() call. There are no events, no container bindings, no Twig. This is the entire reason the Symfony layer is dead weight here.

Gate scripts server-side in Blade, not just client-side. The most common failure pattern: banner shows, user denies, but the <script> tag for GA4 was already rendered in the layout. Use a directive:

@cookieConsent('analytics')
  <script async src="...gtag/js"></script>
@endif

Implement it in a Blade directive registered in AppServiceProvider that reads a consent cookie set on accept. Client-side gating alone is theater — a hard refresh of page source shows the pixels.

Deferred analytics bootstrap. Rather than conditional rendering, register a JS hook fired from the accept handler:

window.dataLayer = window.dataLayer || [];
document.addEventListener('cookie-consent:accepted', ({detail}) => {
  if (detail.categories.includes('analytics')) loadGA4();
});

This is the closest analogue to the bundle's accept callback and matches Consent Mode v2 patterns if you later graduate.

Layout-level invocation via a single partial. Render <x-cookie-consent /> in layouts/app.blade.php and layouts/guest.blade.php only — not in emails, PDFs, or admin layouts. The Symfony bundle's request-lifecycle integration is the analogue; a Blade include is the Laravel equivalent.

Feature-flag and geo-gate behind an abstraction now. Even if you don't need geo today, wrap the decision in a tiny service:

class ConsentBannerPolicy {
    public function shouldShow(Request $r): bool {
        return config('cookie-consent.enabled')
            && ! $r->cookie('cookie_consent_version') === current_version();
    }
}

When Legal asks for EU-only banners, you add a GeoIP check in one place instead of hunting through Blade files.

Settings/revocation link. The bundle ships no revocation UI. Add a persistent "Cookie settings" link in your footer that clears the consent cookie and re-opens the modal — a five-line Alpine dispatch. Do this on day one; it's the requirement everyone forgets until the first DPO review.

Gotchas and Tips

It will not install cleanly on Laravel 10/11. Constraint resolution will fail against modern Symfony. If you must inspect it, use composer require --dev --ignore-platform-reqs in a scratch directory — do not add it to the main composer.json. composer why-not indigophp/cookie-consent-bundle before anything else.

The PHP layer is inert in a Laravel context. No registerBundles(), no bundle Extension, no PackageManifest entry that does anything. Copying vendor/ into your app and expecting behaviour is a common first stumble — only Resources/public/ matters.

Upstream Cookie Consent is deprecated. The bundle wraps Silktide/Insites Cookie Consent v3, which has been superseded. The modern replacement is orestbida/vanilla-cookieconsent (MIT, actively maintained, granular per-category, Consent Mode v2 support). If you're doing the pattern anyway, use the maintained JS and skip the bundle's fork entirely.

Twig leakage. Adding the bundle without removing it puts twig/twig in your composer.lock. It won't do anything, but it's a runtime dependency, an audit finding, and noise in security scans. Remove the requirement after extraction.

Don't trust a banner for compliance. The bundle delivers notice only. It does not give you: proof-of-consent records, per-category opt-in state persisted server-side, revocation API, geo-targeting, or Google Consent Mode v2. For a Laravel app with EU traffic, the pattern is: banner (UI) + Blade directive (blocking) + consent record table (audit) + revocation link (settings). The bundle covers the first; build the other three.

Cookie name and version collisions. If you copy the bundle's default cookie name, and later migrate to vanilla-cookieconsent, existing users will have stale preferences that don't match your new category schema. Namespace it from the start (yourco_consent_v1) and bump on every policy change.

CSP and asset delivery. The bundle's inline <style> in the Twig template will break a strict style-src policy. When you port to Blade, publish the CSS as a Vite entry rather than inlining. Same for the JS init — move it to your bundler entry so a nonce or hash isn't needed.

Debug tip: in config/cookie-consent.php, gate enabled on ! app()->isProduction() or a COOKIE_CONSENT_ENABLED env var so CI/QA doesn't see a banner on every screenshot test, but staging matches prod behaviour.

Extension point you'll actually use: the accept callback. Wrap it in a Laravel-idiomatic event (ConsentGranted) so analytics, marketing pixels, chat widgets, and future integrations all subscribe independently. The bundle's single JS callback would otherwise become an unmaintainable switch statement within a quarter.

Bottom line for the ticket: do not add this to composer.json. Read it as a reference for a 1–2 day in-house Blade component plus a service provider, and keep the CMP buy/no-buy decision as a separate v2 conversation owned by Legal and Product.

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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle