familiewapen Mick Beermickbeer.com

manuscript ·

geverifieerdzekerOverheid, toezicht en de wetbronnenverwant

De cookiemuur toont minder partners dan de code telt

Wat de burger op de cookiemuur leest, komt niet overeen met wat de machine eronder declareert. Het getoonde aantal partners is lager dan het werkelijke. De belofte en de bytes lopen uiteen, precies op het punt waar je geacht wordt geinformeerd toe te stemmen.

Twee getallen die niet met elkaar kloppen

Wat de burger op de cookiemuur leest, komt niet overeen met wat de machine eronder declareert. De zichtbare toestemmingsmuur van een app of site noemt een aantal advertentiepartners. De onderliggende technische configuratie declareert er meer. Dat verschil is de kern van deze notitie, en het is precies het soort verschil dat een gewone bezoeker nooit kan zien, want hij leest de tekst en niet de bytes.

Het gaat niet om een marge van een paar partijen. Het gaat om een structureel verschil op het moment dat juridisch het zwaarst weegt: het moment waarop je geacht wordt geïnformeerd toe te stemmen. Toestemming die geïnformeerd heet maar op een te laag getal berust, is geen geldige toestemming. Je zegt ja tegen minder dan wat er werkelijk meekijkt.

Hoe de cookiemuur van binnen werkt

De meeste cookiemuren in Europa draaien op het IAB TCF, het Transparency and Consent Framework. Dat framework heeft twee onderdelen die hier tellen.

Het eerste is de Global Vendor List, kortweg GVL. Dat is een openbaar JSON-bestand dat het IAB bijhoudt, waarin elke deelnemende advertentiepartij een vast nummer heeft. Vendor 755 is de ene partij, vendor 32 een andere. De GVL bevat honderden vendors.

Het tweede is de TC string, de toestemmingsstring die de cookiemuur genereert zodra je een keuze maakt. Die string codeert jouw keuzes als een bitveld. Voor elke vendor staat er een bit die zegt: toestemming ja of nee. De string reist mee met elk biedverzoek, zodat elke ontvanger kan lezen of hij van jou mag verwerken. Een consent-platform biedt die string aan via een vaste interface, __tcfapi, die je in de browser kunt uitlezen.

Daarnaast bestaat er een Additional Consents-string, een aparte lijst voor advertentiepartijen van Google die buiten het TCF vallen. Die AC-string telt gewoon door boven op de TCF-vendors, en hij verschijnt zelden expliciet op de muur.

Waar de belofte en de bytes uiteenlopen

Op de muur staat een samenvatting. Vaak een zin als "wij en onze 100 partners". Dat getal is voor mensen. De machine rekent met de TC string en de AC-string, en die kun je decoderen. Het aantal vendors dat daarin toestemming krijgt, kun je gewoon tellen.

Ik lees de string uit de browser en tel de bits die op "ja" staan:

window.__tcfapi('getTCData', 2, (data, ok) => {
  if (!ok) return;
  const vendors = data.vendor.consents;      // { "1": true, "32": false, ... }
  const aantalJa = Object.values(vendors).filter(Boolean).length;
  console.log("TCF-vendors met toestemming:", aantalJa);
  console.log("TC string:", data.tcString);
});

Voor de Additional Consents doe ik hetzelfde met het addtlConsent-veld, dat een reeks vendor-id's bevat, gescheiden door punten. Ik tel de id's. De som van de TCF-vendors en de AC-vendors is het getal waarmee de machine werkt. Dat getal leg ik naast het getal dat op de muur stond. Het verschil is de bevinding.

Dat de string zo te decoderen is, is gemeten: de codering ligt vast in de TCF-specificatie en de GVL is openbaar. Dat een concrete muur een lager getal toont dan de string declareert, is per geval gemeten zodra ik beide heb uitgelezen. Waarom een bedrijf het lagere getal toont, kan ik niet in het bedrijf kijken en houd ik daarom op vermoed.

Waarom de code hier de waarheid is

De tekst op de muur is de belofte. De configuratie is de uitvoering. Ik reken met de configuratie, want die stuurt de machine aan en de tekst doet dat niet. Wat de gebruiker te zien krijgt, is een samenvatting, en die samenvatting is naar beneden afgerond op een manier die de kant op valt die het bedrijf uitkomt.

Dat is belangrijker dan het klinkt. De AVG stelt geen eis aan de tekst op de muur, ze stelt een eis aan de verwerking. En de verwerking wordt aangestuurd door de string, niet door de zin. Als de string tweehonderd vendors toestemming geeft en de muur er honderd noemt, dan verwerken tweehonderd partijen op basis van een toestemming die voor honderd is gevraagd. De helft van de verwerkers leunt op een grondslag die de gebruiker nooit heeft gezien.

De TCF-specificatie stelt bovendien een eis aan de toestemming zelf: ze moet geïnformeerd, specifiek en vrij zijn. Geïnformeerd betekent dat je weet aan wie je iets toestaat. Een getal dat lager is dan het werkelijke aantal vendors, tast precies dat kenmerk aan. Je kunt niet geïnformeerd instemmen met partijen die je niet zijn getoond. De consent string die daaruit voortkomt, draagt dan een claim van geldigheid die de onderliggende presentatie niet waarmaakt. En omdat die string met elk biedverzoek meereist, herhaalt de gebrekkige grondslag zich bij elke verwerker in de keten. Eén verkeerd getal op de muur plant zich voort tot in tweehonderd systemen.

Er is een tweede laag die het beeld nog verder scheeftrekt: de purposes. Het TCF codeert twee dingen. Ten eerste aan wie je toestemming geeft. Ten tweede waarvoor, in de vorm van een lijst genummerde doeleinden, van het opslaan van informatie tot het opbouwen van een advertentieprofiel. De muur vat die doeleinden vaak samen in een geruststellende zin over "een betere ervaring". De string codeert de nummers hard. Ik lees daarom ook de purpose.consents uit, want een vendor met toestemming voor doel 3 en doel 4 mag een profiel opbouwen, ongeacht hoe vriendelijk de samenvatting klonk.

De keten achter die vendors is nog langer dan de vendorlijst zelf, want elke vendor heeft weer eigen doorverkopers. Dat werk ik uit in De advertentieketen heeft schakels die niemand in de verklaring noemt. En waar die vendors met je gegevens naartoe gaan, is de veiling die ik beschrijf in Real-time bidding biedt jouw toestel in een veiling aan, in milliseconden.

Wat ik ervan vind

Dit is het schoolvoorbeeld van een verschil dat alleen zichtbaar wordt als je onder de motorkap kijkt. De gemiddelde bezoeker heeft geen manier om de string te decoderen. De toezichthouder heeft die manier wel, en ik ook. Dat maakt dit een dankbaar soort bevinding, want ze is hard te maken met openbare middelen: de GVL is openbaar, de TCF-codering is gedocumenteerd, de string staat in je eigen browser. Ik hoef niets te vermoeden over de intentie. Ik hoef alleen twee getallen naast elkaar te leggen en het verschil te laten zien. Een belofte die de code tegenspreekt, is een belofte waar een gebruiker niets aan heeft, en die je zwart op wit kunt aantonen.

Zie ook De advertentieketen heeft schakels die niemand in de verklaring noemt, Real-time bidding biedt jouw toestel in een veiling aan, in milliseconden en Cookies weigeren scheelt echt, maar reken er niet blind op.

bronnen
  1. Mick Beer, "101 advertentiepartners: het probleem met informed consent op Nederlandse nieuwssites"het verschil tussen het getal in de banner en het aantal partijen in de code
  2. IAB Europe, Transparency and Consent Framework, vendorlijstde lijst waartegen het getoonde aantal is na te rekenen
citeer alsBeer, M. (2026, 18 juli). De cookiemuur toont minder partners dan de code telt. mickbeer.com. https://mickbeer.com/#de-cookiemuur-toont-minder-partners-dan-de-code-telt

lees dit stuk in het manuscript, met alles waar het aan hangt