slova / module-cookie-consent
Free GDPR / ePrivacy cookie consent banner for Hyvä: granular categories, equal-weight Accept and Reject, Google Consent Mode v2, script blocking until consent, Alpine CSP compatible.
Package info
github.com/SlovaTechModules/module-cookie-consent
Type:magento2-module
pkg:composer/slova/module-cookie-consent
Requires
- php: ~8.3.0||~8.4.0
- hyva-themes/magento2-theme-module: ^1.3
- magento/framework: ^103.0.8
- magento/module-config: ^101.2.8
- magento/module-cookie: ^100.4.8
- magento/module-store: ^101.1.8
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-11-11 14:23:45 UTC
README
A cookie consent banner for Magento 2 stores on Hyvä: Reject all as easy as Accept all, a choice per category, nothing optional before the visitor answers, Google Consent Mode v2 set before any Google tag (Google Tag Manager included), and a way back to the settings on every page. Free, MIT-licensed, no account and no external service.
What it does
- Reject as easy as Accept. Reject all and Accept all have the same size and colour, side by side; Customize opens one switch per category. Nothing optional is on until the visitor says so, and the banner does not close without an answer.
- Categories you choose. Necessary (always on), Preferences, Analytics and Marketing; offer only the ones your store uses, per store view. Add your own from
di.xml. - Google Consent Mode v2, before any Google tag. All optional signals are denied right after
<title>— before any Google tag, Google Tag Manager included, even when its snippet sits in HTML Head > Scripts and Style Sheets — and updated the moment the visitor chooses. Returning visitors get their stored choice before the first tag fires. - Blocks other scripts until consent. Mark a script
type="text/plain" data-consent="marketing", or an iframe withdata-consentanddata-src, and it runs only once its categories are allowed. - Withdrawal on every page. A small corner button, any link to
#cookie-settings(put one in your footer) andwindow.slovaConsent.open(). Withdrawing a category reloads the page so scripts that already ran stop. - Built for Hyvä. Works with Alpine's CSP build, no inline scripts or styles, no Tailwind rebuild, safe in the full page cache. 4.4 KB of JavaScript gzipped, both files together (
consent.js3.4 KB,consent-mode.js1.1 KB, measured withgzip -9on 1.0.0). Follows your theme's primary color. - Replaces Magento's Cookie Restriction Mode and silences its notice while enabled.
- For developers: a browser API and events (mirrored into
dataLayerfor Google Tag Manager) and a server-side PHP class for code that must respect consent. - Translated into English, Romanian, German, French, Spanish, Italian and Dutch.
What it does not do
It does not scan your store for cookies, keep a server-side log of consents, adapt the banner to the visitor's country, or implement the IAB TCF framework. If you need any of those, a hosted consent platform (Cookiebot, Usercentrics, CookieYes…) is the better tool.
The module gives you the mechanics: the choice, the categories, the Consent Mode signals and the scripts held back until consent. Whether your store complies with the rules that apply to it also depends on the scripts you run, your privacy policy and the texts you choose; check those with your legal adviser.
Screenshots
Taken on the Hyvä default theme with the module's default settings.
Customize opens one switch per category; the optional ones are off until the visitor turns them on.
On a phone the two buttons stay side by side, the same size.
Requirements
| Requirement | Supported |
|---|---|
| Magento Open Source | 2.4.8 (tested on 2.4.8-p5) |
| Adobe Commerce | Not tested yet |
| Hyvä Theme | 1.3 or newer (tested on 1.5.3) |
| PHP | 8.3 – 8.4 |
The storefront part uses Hyvä's Alpine.js; Luma storefronts are not supported. hyva-themes/magento2-theme-module comes from Hyvä's own Composer repository, which every Hyvä store already has configured.
Installation
composer require slova/module-cookie-consent
bin/magento module:enable Slova_CookieConsent
bin/magento setup:upgrade
bin/magento setup:di:compile # production mode
bin/magento cache:flush
The banner appears right away with sensible defaults. Then:
- Set Stores → Configuration → General → Web → Default Cookie Settings → Cookie Restriction Mode to No (this module replaces it).
- Point Privacy Policy Link at your policy page.
- Mark the scripts that need consent (see Blocking scripts until consent), or rely on Consent Mode for Google tags.
- Check that it works (see Checking that it works).
Upgrading
composer update slova/module-cookie-consent bin/magento setup:upgrade bin/magento cache:flush
Uninstalling
bin/magento module:uninstall Slova_CookieConsent --remove-data
--remove-data deletes the module's settings (slova_cookieconsent/*). Visitors' consent cookies expire on their own. Turn Magento's Cookie Restriction Mode back on, or install another banner first, so the store is never left without one.
Configuration
Stores → Configuration → Slova → Cookie Consent
| Setting | Notes |
|---|---|
| Enable Cookie Consent | Per store view. |
| Optional Categories | The categories visitors can switch. Necessary is always listed. Default: Analytics, Marketing. |
| Privacy Policy Link | A CMS page URL key (privacy-policy) or a full https:// URL. Empty: no link. |
| Consent Version | Raise it after you change your policy or add a category: everyone is asked again. |
| Remember the Choice For (Days) | Default 180 (about six months, as the French CNIL recommends). |
| Floating Settings Button | Reopens the preferences after a choice. If you turn it off, link to #cookie-settings from every page. |
| Texts | Banner title, message and link text per store view. Empty: the built-in, translated text. |
| Banner Position | Card bottom right, card bottom left, or a bar across the bottom. |
| Accent Color | A hex color for buttons, links and switches. Empty: your theme's --color-primary. |
| Send Google Consent Mode | On by default. Turn off only if your GTM container or another module already sends the consent defaults. |
| Wait for Update (ms) | 500, Google's recommendation. |
| Redact Ads Data Without Consent | On by default (ads_data_redaction). |
Categories and Google Consent Mode
| Category | Consent Mode signals it grants |
|---|---|
| Necessary (always on) | security_storage |
| Preferences | functionality_storage, personalization_storage |
| Analytics | analytics_storage |
| Marketing | ad_storage, ad_user_data, ad_personalization |
A signal whose category is not offered stays denied.
Blocking scripts until consent
Google tags (gtag.js, Google Tag Manager's Google tags) follow Consent Mode on their own. Everything else must not run before consent. Change the script's type to text/plain and name the categories it needs:
<!-- Runs once marketing is allowed. Paste the platform's base code inside, unchanged: only the opening tag differs from what the platform gives you. --> <script type="text/plain" data-consent="marketing"> /* PLACEHOLDER: your Meta Pixel base code from Events Manager, as given, ending with fbq('init', 'YOUR_PIXEL_ID'); fbq('track', 'PageView'); */ </script> <!-- External script; needs both categories --> <script type="text/plain" data-consent="analytics marketing" src="https://example.com/tag.js"></script> <!-- A module script: the real type goes in data-type --> <script type="text/plain" data-consent="analytics" data-type="module" src="/js/stats.mjs"></script> <!-- Embedded video: loads once marketing is allowed --> <iframe data-consent="marketing" data-src="https://www.youtube.com/embed/VIDEO_ID" width="560" height="315"></iframe>
Blocked scripts keep their order. Under a strict Content Security Policy, an inline script still needs to be allowed by hash or nonce: with Hyvä, call $hyvaCsp->registerInlineScript() right after the placeholder. Whether Hyvä adds a hash (same text once activated) or a nonce (copied to the activated script), it carries over.
In Google Tag Manager, non-Google tags can use the built-in consent checks (they read Consent Mode), or a Custom Event trigger on slova_consent_ready / slova_consent_updated with a Data Layer Variable slova_consent.marketing (or any category code).
Checking that it works
In a private window, so no earlier choice is stored:
- The banner appears on the first page, with no floating settings button yet.
- Consent Mode starts denied. In the browser console,
dataLayer.filter(e => e[0] === 'consent')returns adefaultentry first, with every optional signaldeniedandsecurity_storagegranted. Google Tag Assistant shows the same on its Consent tab. - A choice updates it. Click Accept all: the same command now ends with an
updateentry setting the allowed signals togranted. Theslova_consentcookie holds the choice, for example{"necessary":true,"analytics":true,"marketing":true,"v":1,"ts":…}. - Blocked scripts wait. Start again in a new private window and click Reject all: in the Network tab, nothing marked
data-consent="marketing"is loaded (nofbevents.jsfor a Meta Pixel, for example). - The way back works. The corner button, or a link to
#cookie-settings, opens the preferences with the current choice.
Letting visitors change their mind
Any of these opens the preferences:
<a href="#cookie-settings">Cookie settings</a> <button type="button" data-consent-open>Cookie settings</button>
A link to /some-page#cookie-settings opens them on that page after it loads.
For developers
Browser
window.slovaConsent.has('analytics'); // true once allowed (required categories always are) window.slovaConsent.get(); // { necessary: true, analytics: false, marketing: true } window.slovaConsent.isDecided(); // false until the visitor answers window.slovaConsent.open(); // open the preferences window.slovaConsent.acceptAll(); window.slovaConsent.rejectAll(); window.slovaConsent.save({ analytics: true }); window.addEventListener('slova:consent-ready', e => console.log(e.detail)); // once per page window.addEventListener('slova:consent-updated', e => console.log(e.detail)); // after every choice
window.slovaConsent exists as soon as the module's deferred script has run, before Alpine starts. Scripts in <head> should listen for slova:consent-ready rather than call the API directly.
The choice is stored in the first-party cookie slova_consent as JSON: {"v": <consent version>, "ts": <unix time>, "necessary": true, "analytics": false, …}.
Server
For server-side code that must respect consent — a Conversions API call when an order is placed, a cookie set by a controller:
public function __construct(private \Slova\CookieConsent\Model\Consent $consent) {} if ($this->consent->allows('marketing')) { /* … */ } $this->consent->hasDecided(); $this->consent->getChoices(); // ['necessary' => true, 'analytics' => false, …]
Do not use it to vary the HTML of full-page-cached pages: the cached copy would carry the first visitor's choice.
Adding a category
In your module's etc/di.xml:
<type name="Slova\CookieConsent\Model\CategoryPool"> <arguments> <argument name="categories" xsi:type="array"> <item name="social" xsi:type="array"> <item name="label" xsi:type="string">Social media</item> <item name="description" xsi:type="string">Share buttons and embedded posts.</item> <item name="required" xsi:type="boolean">false</item> <item name="sort_order" xsi:type="number">35</item> </item> </argument> </arguments> </type>
It then appears under Optional Categories. Codes are lowercase letters, digits and underscores. Translate the label and description in your module's i18n/*.csv. Raise Consent Version so existing visitors are asked about it.
Styling
Styles live in view/frontend/web/css/consent.css and are driven by custom properties on .slova-cc; override them from your theme:
.slova-cc { --slova-cc-accent: #0f766e; --slova-cc-banner-bg: #f0fafa; --slova-cc-banner-border: #0f766e; --slova-cc-radius: .75rem; }
| Property | Default | What it styles |
|---|---|---|
--slova-cc-accent |
your theme's --color-primary (else #1d4ed8) |
Buttons, links, switches; the Accent Color setting overrides it |
--slova-cc-on-accent |
your theme's --color-on-primary (else #fff) |
Text on accent buttons |
--slova-cc-text |
#111827 |
Titles and labels |
--slova-cc-muted |
#4b5563 |
Descriptions |
--slova-cc-border |
#e5e7eb |
Dividers and outlines |
--slova-cc-bg |
#fff |
The preferences panel |
--slova-cc-banner-bg |
--slova-cc-bg |
The banner |
--slova-cc-banner-border |
--slova-cc-border |
The banner's border |
--slova-cc-overlay |
rgb(17 24 39 / .6) |
The backdrop behind the preferences |
--slova-cc-switch-off |
#cbd5e1 |
A switch that is off |
--slova-cc-radius |
.5rem |
Corners |
--slova-cc-z-banner |
30 |
The banner's stacking order |
--slova-cc-z-modal |
60 |
The preferences panel's stacking order |
For deeper changes, override Slova_CookieConsent::consent.phtml in your theme; keep the x-data, data-category and event bindings.
With Slova Tracking
Slova Tracking sends conversions to Meta, Google (GA4 and Google Ads), TikTok and ChatGPT Ads, from the browser and from the server. It reads the visitor's choice from Google Consent Mode v2, so with this banner on the page set its Consent Source to Google Consent Mode v2; nothing else is needed. Analytics opens GA4, Marketing opens the ad platforms, and the purchase sent from the server follows the same choice as the browser tags.
Frequently asked questions
Does it keep a record of consents?
Not on the server. Each visitor's choice is stored in their browser, in the slova_consent cookie, with the consent version and the time it was given. If you need a central log of consents, a hosted consent platform is the better tool.
Does it work with GA4 and Google Ads?
Yes, through Google Consent Mode v2, which gtag.js and the Google tags in Google Tag Manager read on their own. Analytics controls analytics_storage; Marketing controls ad_storage, ad_user_data and ad_personalization. If your GTM container already sends consent defaults, turn Send Google Consent Mode off so they are not sent twice.
Can I add my own categories?
Yes: see Adding a category. Raise Consent Version afterwards so existing visitors are asked again.
Does it work on Adobe Commerce?
It is built and tested on Magento Open Source. Adobe Commerce is not tested yet.
Troubleshooting
- The banner does not appear. It shows only until a choice is made: test in a private window. Check Enable Cookie Consent for the store view, and flush the full-page cache after changing settings.
- Two banners. Magento's Cookie Restriction notice is silenced while this module is on; a second banner comes from another module, the theme or a script in HTML Head. Remove it.
- A marked script never runs. Every category in its
data-consentmust be allowed, and offered: a category missing from Optional Categories is never allowed. Under a strict Content Security Policy an inline script also needs its hash or nonce (see Blocking scripts until consent). - Visitors are asked again. That happens when Consent Version is raised, and after Remember the Choice For (Days).
Support and license
Bugs and questions: open an issue on GitHub, or write to contact@slova.tech. Installation and setup by us, if you prefer: slova.tech/modules/cookie-consent.
MIT — see LICENSE. © 2026 Carusel Multimedia SRL, trading as Slova.


