Does Matomo need a consent banner? Cookieless tracking, fingerprinting, and making 'Refuse' actually work

Matomo's cookieless config_id isn't a classic fingerprint, ePrivacy and GDPR are two separate questions, and the reason 'Refuse' doesn't stop your tracking is almost always a double-injected tracker. Here's the config behind all three. Not legal advice, just the mechanics.

Two questions come up constantly in the Matomo forums, and they turn out to be the same question wearing different clothes. Does Matomo's cookieless tracking, the config_id that people keep calling a "fingerprint," need consent at all? And once you bolt a consent manager like tarteaucitron onto the site, why does Matomo keep recording visits from people who clicked Refuse?

The part that matters before anything else: this is configuration guidance, not legal advice. Whether you need a banner depends on your jurisdiction, the data you collect, and how your install is configured, and that call belongs to your DPO or legal counsel, not a blog post and not Matomo's defaults. What we can do is explain how Matomo's consent model works and how to wire the config so it matches whatever decision they hand you. Everything below is Matomo 5.x.

TL;DR

Cookieless Matomo drops the consent banner only where your jurisdiction grants a narrow analytics exemption and you meet every condition; France, via the CNIL, is the clearest case. Everywhere else, gate Matomo behind consent. If people who clicked Refuse still show up in your reports, the cause is almost always two trackers loading at once: one auto-injected by your CMS or plugin, one by your consent manager. Disable the auto-injected copy so your consent manager is the only thing loading Matomo.

What Matomo actually collects (and why the config_id isn't a classic fingerprint)

Start here, because the legal question is downstream of the technical one. Out of the box, Matomo tracks immediately. Consent is something you opt into. It's not the default state, and if you do nothing the tracker fires.

When cookies are disabled, Matomo stops storing an identifier on the device and derives a server-side config_id for each visit instead. The config_id is a hash of a limited set of attributes (browser, operating system, plugins, IP address, language) mixed with a random salt that rotates every 24 hours and is then deleted. The IP goes in after your anonymisation setting is applied, which by default masks it; an install configured to skip IP anonymisation feeds the full address into the hash, so confirm that setting is on. Three things fall out of the design:

  • The same visitor gets a completely different config_id the next day, so no person or device can be recognised across days. The salt that would let you reconnect them is already gone.
  • The hash is scoped per website ID, so the same visitor browsing two of your sites gets two unrelated values.
  • With no cookie, the default look-back window for stitching actions into one visit is only about 30 minutes.

That's the real difference between this and the kind of fingerprinting regulators worry about. A classic fingerprint is built to be stable, to recognise you next week. Matomo's is built to forget. It's a session-grouping hash with a 24-hour shelf life, not a persistent identifier. (Matomo documents this in its config_id FAQ, worth a read if you ever need to defend the choice internally.)

ePrivacy and GDPR are two different questions

Most of the confusion in those forum threads comes from collapsing two legal layers into one. They're separate, and clearing one does not clear the other:

  • ePrivacy (Article 5(3), as transposed into your national law) governs access to the device: reading or writing information on the user's terminal. That's the "do you need a cookie banner" question.
  • GDPR governs what you do with the data once you have it: your lawful basis, retention, the rights you owe the visitor.

Cookieless Matomo removes the cookie-storage trigger, but it doesn't automatically put you outside ePrivacy. In most European countries the rules can still reach client-side analytics even when no cookie is written; a few jurisdictions, France among them, recognise a narrow exemption for audience measurement if you meet every condition. So going cookieless drops the banner question in some places and not others, and either way you still carry GDPR obligations on the data you collect. The reverse also happens: you can be fully GDPR-documented and still owe a banner because you're setting a cookie. Don't treat them as one switch.

Route A: configure for exemption (no banner)

In France, the CNIL lists Matomo among the audience-measurement tools that can be exempt from prior consent when you configure it to their guidance. Broadly, exemption asks you to:

  • Anonymise IP addresses (mask at least the last two bytes).
  • Not cross-reference the data with other processing or share it with third parties.
  • Disable cross-visit profiling (visitor profiles, Heatmaps & Session Recording) and avoid User ID and personal data.
  • Cap the cookie lifespan (CNIL: 13 months maximum) and data retention (25 months maximum).
  • Offer a visible opt-out and still inform visitors through your privacy policy.

As of Matomo 5.9.0 (and on Matomo Cloud), you don't have to hand-check those any more. Administration → Privacy → Compliance runs your config against the CNIL requirements per site and flags each setting as compliant, non-compliant, or unknown. Tick "enforce compliance where possible" and it applies the supported ones in one go: the two-byte IP mask, disabling visitor profiles and heatmaps, stripping campaign parameters, and dropping data retention to 180 days. It won't set up your opt-out or make the legal call for you, but it clears most of the manual fiddling.

Before you tick 'enforce compliance'

Run the assessment first and read what it will change. Enforcing CNIL mode does more than mask IPs: depending on your setup it can switch off the Visits Log, real-time reports, raw-data exports, User ID, cross-domain tracking and ad-conversion exports, and restrict Ecommerce. Enabling it also permanently deletes any A/B Testing experiments. On a live shop or experimentation setup, confirm those losses are acceptable before you enforce, not after.

Two cautions on the route itself. This is a France-specific interpretation of how French law transposes ePrivacy, and another DPA may take a stricter line. And "exempt" means exempt from the prior-consent banner; it does not remove your transparency and opt-out duties. Decide with legal before you lean on it.

If you (or your regulator) want prior consent, you wire Matomo to wait for it. Matomo gives you two distinct modes, and picking the wrong one (or mixing the two APIs in one callback) is behind a lot of "this isn't behaving how I expected" threads. The difference is what each one gates:

requireConsent (strict)requireCookieConsent (cookie-only)
Tracking request before consentnonefires, cookieless
_pk_* cookies before consentnonenone
What it holds backthe whole tracking requestonly the persistent cookies
Grant on AcceptrememberConsentGivenrememberCookieConsentGiven
Revoke on RefuseforgetConsentGivenforgetCookieConsentGiven
Use it whentracking itself needs a lawful basiscookieless-by-default, only the cookie needs opt-in

The two APIs are parallel but separate: the consent calls govern whether anything is sent at all, the cookie-consent calls govern only the _pk_* cookies. Keep a callback to one column and don't reach across.

js
var _paq = window._paq = window._paq || [];
 
// No request and no cookie until the visitor consents.
_paq.push(['requireConsent']);
_paq.push(['trackPageView']);

Grant and revoke from your banner's callbacks:

js
// On Accept
_paq.push(['rememberConsentGiven', 720]); // persist ~30 days; omit the number to remember until cleared
 
// On Refuse, or a later withdrawal
_paq.push(['forgetConsentGiven']);
_paq.push(['deleteCookies']);             // clears any _pk_* cookies left from a previous Accept

This is the setup for "count visits before consent, set the persistent cookie after." It's the right answer when you want cookieless measurement up front rather than fully blocking Matomo.

js
var _paq = window._paq = window._paq || [];
 
// Requests fire cookielessly right away; only the _pk_* cookies wait for consent.
_paq.push(['requireCookieConsent']);
_paq.push(['trackPageView']);
js
// On Accept
_paq.push(['rememberCookieConsentGiven', 720]);
 
// On Refuse, or a later withdrawal
_paq.push(['forgetCookieConsentGiven']);
_paq.push(['deleteCookies']);

Two things that catch people out. The remember* calls persist the decision so Matomo re-applies it on the next page; the matching setConsentGiven / setCookieConsentGiven grant for the current pageview only, so use those only if your consent manager stores the choice itself and re-calls them on every load. And requireConsent / requireCookieConsent has to be pushed before trackPageView in the queue, or the gate arrives after the hit has already gone out.

Why "Refuse" doesn't stop Matomo

Here's the one that fills the forums: you installed a consent manager, the banner shows up, you click Refuse, and Matomo records the visit anyway. More often than not the consent API isn't the problem at all. The Matomo tracking code is loading twice. Your CMS or plugin auto-adds it, and your consent manager adds it too, and the auto-injected copy runs no matter what the visitor clicks. The banner faithfully controls its own copy of the tracker while a second, ungated copy fires underneath it.

Visitor clicks Refuse

Consent manager

  1. Its tracker copy stays gated

    no request leaves the page

CMS or plugin auto-inject

  1. Second copy fires anyway

    the banner never gated it

matomo.php

still receives the ungated hit

Two loaders, one endpoint. The consent manager gates its own copy, but the auto-injected copy ignores the banner, so Refuse still produces a hit.

The fix is to make the consent manager the only thing that loads Matomo. In WordPress, which plugin you have decides where that switch lives:

  • Matomo for WordPress (the all-in-one plugin that runs Matomo inside WordPress): go to Matomo Analytics → Settings and set Tracking mode to Disabled.
  • Connect Matomo (formerly WP-Matomo, which connects to an external Matomo): go to Settings → Connect Matomo → Enable Tracking and set "Add tracking code" to Disabled.

Save, and the plugin stops auto-injecting the tracker. Now let your consent manager load Matomo instead. With the self-hosted tarteaucitron.js, configure the Matomo service and run it in explicit-consent mode so nothing fires until the visitor chooses:

js
tarteaucitron.user.matomoId   = 1;                          // your Matomo Site ID
tarteaucitron.user.matomoHost = '//analytics.example.com/'; // your Matomo URL, with trailing slash
(tarteaucitron.job = tarteaucitron.job || []).push('matomo');

The integration key isn't the same across tarteaucitron versions and products: the self-hosted open-source build documents the 'matomo' job key shown above, while Matomo's own Tarte au Citron guide defines a custom MatomoAnalytics service. Check which one your version expects rather than copying a snippet meant for the other. The same overall pattern (disable the plugin's own tracker, then let the consent manager load Matomo) applies to Complianz, Cookiebot and the rest; only the configuration surface changes.

Verify it in the Network tab

Don't trust the banner; watch the wire. In a fresh incognito window, open DevTools → Network and filter for matomo.php:

  • Before choosing, with requireConsent and an explicit-consent banner, you should see no request to matomo.php.
  • Click Refuse: still no matomo.php request, and no _pk_id or _pk_ses cookies in the Application tab.
  • Click Accept: the request fires, and the hit shows up in Matomo → Visits Log.
  • Accept, then withdraw and reload: confirm the _pk_* cookies are gone. That's what deleteCookies is for, and it's the test people skip.
  • In cookieless mode (requireCookieConsent), hits should arrive without any _pk_* cookies until consent.

If a matomo.php request still slips through on Refuse, double injection is the first suspect but not the only one. Walk the loaders in order:

  1. The CMS or plugin auto-tracker (the switch above).
  2. A hard-coded snippet in your theme.
  3. A Matomo Tag Manager container firing a tag outside its consent rule.
  4. A consent-manager snippet queued wrong, e.g. requireConsent pushed after trackPageView, so the gate lands too late.
  5. A server-side tracking endpoint. DevTools won't show a server-to-server hit, so the same consent decision has to gate that call too.
  6. A cached matomo.js or cached HTML still serving an old snippet.

Item 5 is the one to keep in mind if you're routing hits through a server-side endpoint or the HTTP Tracking API. And because the config_id is scoped per site, getting this right matters most when you run multiple sites or domains in one Matomo. For the broader privacy posture around all of this, our notes on hardening a Matomo install cover the settings that sit next to these.

What we'd actually do

If you're France-based and your data stays inside Matomo, run the 5.9.0 Compliance assessment first and see how close you already are to exemption. It's the lowest-effort honest path, and it's now a few clicks. If you operate under a stricter DPA, or you're not sure, default to requireConsent, wire it through one consent manager, and verify Refuse in the Network tab before you call it done. Either way the technical work is small. Deciding which route is legitimate for you is the part to hand to someone qualified to make it.

The thing to hold onto is that Matomo's cookieless mode really is different from surveillance fingerprinting. A 24-hour hash that deletes its own salt is built to forget you, not to follow you. That gives you configuration options most analytics stacks don't have. Use them on purpose.

Martez connects Matomo with Meta Ads and Google Ads so ROAS, CLV, and attribution sit next to your web analytics instead of in a separate spreadsheet. It's in private beta. Join the waitlist if that's relevant to you.

Configure the tracker to match the legal call. Don't let the legal call get made by a tracker you forgot was running twice.