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

Symfony Cookie Consent Bundle Laravel Package

fatalnetwork/symfony-cookie-consent-bundle

A Symfony bundle for adding cookie consent to your application, with configurable consent banners and cookie handling. Integrates consent management into Symfony projects so visitors can accept or reject cookies.

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 config/cookie-consent.php, and no Blade directives. If you're on Laravel, you cannot composer require this and expect it to boot — you'd be reading it as a reference implementation and porting the consent model (cookie name, category shape, banner partial) to something like spatie/laravel-cookie-consent or a hand-rolled middleware. If you're maintaining a Symfony app, the steps below apply.

Install and register (Symfony):

composer require fatalnetwork/symfony-cookie-consent-bundle

Then register in config/bundles.php (Symfony 4+/Flex) or app/AppKernel.php (legacy):

// config/bundles.php
FatalNetwork\CookieConsentBundle\FatalNetworkCookieConsentBundle::class => ['all' => true],

Where to look first, in this order:

  1. The bundle's DependencyInjection/Configuration.php — this is the authoritative list of every config key, its default, and whether it's required. Ignore the README config sample until you've confirmed it matches.
  2. The Twig templates shipped under Resources/views/ — that's the banner markup you'll be overriding.
  3. Any route/controller the bundle registers — usually a POST endpoint that persists the consent choice into a cookie.

Minimal config (typical shape for this class of bundle — verify key names against the config tree):

# config/packages/fatal_network_cookie_consent.yaml
fatal_network_cookie_consent:
    cookie_name: cookie_consent
    cookie_lifetime: 31536000   # 1 year
    categories:
        - necessary
        - preferences
        - statistics
        - marketing

First use case — gate analytics behind consent. Render the banner once in your base layout and wrap every non-essential script in a category marker so it only executes after opt-in:

{# templates/base.html.twig #}
{{ cookie_consent_banner() }}   {# adjust to the actual Twig function/embed #}

<script type="text/plain" data-cookie-category="statistics">
    /* GA / Matomo snippet */
</script>

The banner JS flips type="text/plain" back to type="text/javascript" for categories the visitor accepted. That is the whole trick, and it's the pattern you'll reuse for every third-party tag.

Implementation Patterns

Category model, not a boolean. Treat consent as a set of independent categories rather than a single yes/no. Necessary cookies are always on and non-revocable; everything else defaults to off. This matches how GDPR consent actually works and it keeps you from rewriting the cookie format later when marketing asks for a separate opt-in.

Server-side gating for things JS can't fix. Client-side type="text/plain" only stops script tags in the DOM. It does nothing for a tracking pixel injected by PHP, an analytics call made from a controller, or a server-rendered <img> beacon. Read the consent cookie on the request and branch:

// Symfony: a small service or Twig extension
public function hasConsent(string $category): bool
{
    $cookie = $this->requestStack->getCurrentRequest()?->cookies->get('cookie_consent');
    if (!$cookie) {
        return false;
    }
    $granted = json_decode($cookie, true)['categories'] ?? [];

    return in_array($category, $granted, true);
}

In Laravel the equivalent is a CookieConsent singleton bound in a service provider, resolved from $request->cookie(), plus a Blade @hasConsent('statistics') directive.

A single persistence endpoint. One POST route that accepts the category payload, validates it against the configured category whitelist (never trust the client to send arbitrary keys), writes the cookie with Secure, HttpOnly, SameSite=Lax, and returns 204. This gives you one place to add an audit log later — timestamp, IP hash, categories, banner version — which is what you'll need if a regulator or a customer's DPO ever asks you to prove consent.

Preferences re-entry. Put a "Cookie settings" link in the footer on every page that reopens the banner pre-populated with the current cookie state. Withdrawal must be as easy as granting; a banner that only appears on first visit is a common and avoidable compliance gap.

Reuse the same JSON blob for both sides. Whatever the JS writes, make the server read the exact same structure. Two sources of truth (a JS localStorage flag and a PHP cookie) drift within a sprint.

Testing. In functional/feature tests, set the consent cookie directly on the request rather than driving the banner through a headless browser:

$client->request('GET', '/', [], ['cookie_consent' => json_encode(['categories' => ['statistics']])]);

Then assert that the analytics markup is rendered as a real script tag (or absent entirely). That's a fast regression test for the most likely production bug: someone refactors the layout and drops the category attribute.

Gotchas and Tips

Adoption risk is the headline issue. One star, zero dependents, and a single maintainer means you are effectively adopting an unmaintained dependency. Pin the exact version in composer.json, fork it into your VCS if you're shipping to production, and budget a day to read the ~20 files that matter. The bundle is thin enough that a fork is cheap; it is also thin enough that "why not just write the 150 lines myself" is a legitimate answer.

Full-page caching breaks the banner state. If you use Symfony HttpCache, Varnish, or Cloudflare, a cached page will serve one visitor's banner state to everyone. Either vary the cache key on the consent cookie, render the banner purely client-side from a JS-readable cookie, or exclude the banner partial from the cached fragment.

HttpOnly vs. the JS toggle. The bundle's JS needs to read the consent cookie to know which categories to activate. If you set HttpOnly: true for security, the client-side activation silently stops working. Either keep the consent cookie JS-readable (it contains no secrets, so this is acceptable) or expose the state via a data- attribute on the banner element and keep the cookie HttpOnly.

First-request blindness. On the very first request there is no cookie, so any server-side hasConsent() returns false and your analytics markup is stripped from the HTML. That's correct behavior, but it means the consent grant doesn't retroactively apply until the next navigation. If that matters (single-page journeys), have the JS re-trigger the gated blocks on accept rather than waiting for a reload.

Don't let the bundle own the cookie policy. Cookie name collisions with other packages are common — prefix it (app_consent), and check Set-Cookie headers for a duplicate-name scenario where your middleware and the bundle's listener both write. Also confirm the bundle's SameSite default against your session config; a mismatch on a cross-subdomain flow (e.g. login on auth.example.com, app on app.example.com) will silently drop consent.

Debugging checklist. Consent "not sticking" almost always resolves to one of: cookie domain mismatch, Secure set while testing on plain HTTP locally, a JS exception in the banner bundle before the cookie write, or the config tree silently ignoring your key because of a typo (Symfony will not always throw on unused config keys). Read Set-Cookie in the network tab before touching any code.

Extension points, in order of safety: override the templates (copy the bundle's views into templates/bundles/FatalNetworkCookieConsentBundle/), then decorate the service that resolves consent, then override the config, and only as a last resort monkey-patch the vendored file. Template override is the only one that survives a composer update cleanly.

Legal is not a library feature. The bundle renders a banner and stores a cookie. It does not give you a cookie audit, a consent log, a data-processing register, or granular per-vendor consent — all of which show up in real AVG/GDPR reviews. If the compliance bar is high, treat this as the front-end scaffold and build the record-keeping yourself.

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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo