runroom-packages/cookies-bundle
A Symfony bundle by Runroom for GDPR-friendly cookie consent management. Define cookie categories, display a customizable consent banner, and control which scripts load based on user choices. Includes configuration options and Twig helpers for integrating consent into Symfony apps.
This is a Symfony bundle, not a Laravel package. As a Laravel developer, the first decision is whether you are actually working in a Symfony app; if not, treat this repository as a reference implementation rather than something you can composer require into Laravel and expect auto-discovery, a service provider, publishable config, or Blade views.
If you are in Symfony:
DependencyInjection/Configuration.php — the authoritative config schema.Resources/views/ — banner/modal templates and Twig helpers.Resources/assets/ or Resources/public/ — the JavaScript consent API.RunroomCookiesBundle.php — bundle registration class.composer require runroom-packages/cookies-bundle
// config/bundles.php
return [
// ...
Runroom\CookiesBundle\RunroomCookiesBundle::class => ['all' => true],
];
Configuration.php:# config/packages/runroom_cookies.yaml
runroom_cookies:
cookies:
necessary:
- { name: 'PHPSESSID', description: 'Session' }
analytics:
- { pattern: '_ga', description: 'Google Analytics' }
marketing:
- { pattern: '_fbp', description: 'Meta Pixel' }
{{ include('@RunroomCookies/cookies.html.twig') }}
analytics category. Do not load GA until consent exists, and make sure the bundle actually blocks the script rather than only displaying a banner.For Laravel, the practical equivalent is a small in-house consent module: a config file listing cookie categories, a Blade partial, a first-party consent cookie, and a middleware/helper that reads consent before server-side tracking. That is usually safer than trying to bridge a Symfony bundle into Laravel.
Category-first cookie inventory. Start with the categories your legal/privacy owner needs — typically necessary, preferences, analytics, marketing. Only necessary may be active before consent. Keep the inventory in config so it can be reviewed in code review rather than hidden in templates.
Render globally, decide locally. Put the banner partial in the base layout so it appears on every page, but keep script gating close to the script itself:
{# Illustrative: confirm helper names in the README #}
{% if runroom_cookies_allowed('analytics') %}
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXX"></script>
{% endif %}
If the bundle exposes only a JavaScript API, use that API to inject scripts after consent instead of relying on Twig-only gating.
Consent-state listener for third-party scripts. Third-party tags often need to load after the user accepts. Centralize this in one JS file:
// Confirm the actual event/API name in the bundle assets.
document.addEventListener('runroom:cookies:change', () => {
if (window.RunroomCookies?.allowed('analytics')) {
loadAnalytics();
}
});
Keep loadAnalytics() idempotent so it does not double-load on repeated consent changes.
Server-side gating. A frontend banner cannot prevent cookies set by PHP. If you set analytics or personalization cookies server-side, read the consent cookie from the request in a listener/middleware and skip those cookies until the relevant category is allowed.
Version the consent. When your cookie inventory changes, old consent may no longer be valid. Store a schema/config version with the consent state and re-prompt when it changes. This matters more than the banner styling.
Withdrawal path. Provide a persistent “Cookie settings” link in the footer that reopens the banner/modal. GDPR requires consent to be as easy to withdraw as to give.
Testing pattern. Functional-test the banner with no consent cookie, then set the consent cookie in the test client and assert that gated scripts disappear/appear. Also test with cookies disabled and with a malformed/old consent cookie.
Laravel adaptation pattern. If you are rebuilding this in Laravel:
config/cookies.php for categories and cookie definitions.layouts/app.blade.php.cookie_consent.cookies_allowed('analytics') reading that cookie.This mirrors the bundle’s useful architecture without pulling Symfony into a Laravel app.
Not Laravel-compatible out of the box. No Laravel service provider, no vendor:publish, no Blade views, no Eloquent. Installing it in Laravel will not “just work.”
Low adoption risk. Three stars and zero dependents means you should audit the source, pin a specific version or commit, and check recent maintenance activity. MIT license is permissive, but that is not a quality signal.
The bundle may record consent but not enforce blocking. Verify this explicitly. Many consent packages render UI and store preferences; blocking third-party scripts and server-side cookies remains your responsibility.
Config keys are the contract. The YAML example above is illustrative. Read DependencyInjection/Configuration.php before configuring; otherwise you will silently configure the wrong tree or hit InvalidConfigurationException.
Clear Symfony cache after config/template changes. Config changes in YAML often require bin/console cache:clear, especially in production-like environments.
Assets may need a build/install step. Check whether the bundle ships compiled JS/CSS or expects Webpack Encore/npm integration. A banner with missing CSS/JS is a common first-run failure.
Do not trust undocumented cookie names or JSON shapes. If you read the consent cookie in your own backend code, wrap that logic behind one service/helper so you can adapt when the bundle’s format changes.
Set the consent cookie correctly. Use a first-party cookie with appropriate Path, Domain, SameSite=Lax, and expiry. Avoid SameSite=None unless you genuinely need cross-site behavior.
Re-prompt on category changes. Adding marketing cookies after users already accepted analytics is a common compliance bug. Bump a version and invalidate old consent.
Test with a clean browser profile. Consent bugs often hide behind an existing cookie. Use incognito and DevTools → Application → Cookies to inspect state.
CSP can break consent assets. If you use a strict Content Security Policy, whitelist the bundle’s script/style or self-host them. Do not weaken CSP just to make the banner render.
Accessibility is easy to neglect. The banner must be keyboard-operable, screen-reader friendly, and must not trap focus incorrectly. Check the bundle template before shipping; you may need to override it.
Extension points to check: template overrides under templates/bundles/RunroomCookiesBundle/, service decoration for consent resolution, and config-level category/cookie definitions. Prefer overriding templates and decorating services over editing vendor code.
How can I help you explore Laravel packages today?