hello@newnorth.nl+31 (0) 85 401 31 62
/Journal

PII in je analytics: hoe e-mailadressen in GA4 belanden en hoe je ze eruit houdt

NaslagAnalytics2023.01.30
Freek Kampen
Freek KampenMede-oprichter, New North Digital

Google verbiedt persoonsgegevens in Analytics en Ads. Waar ze toch binnenlekken, hoe je ze opspoort in BigQuery, en wat je ertegen doet.

Wat PII is en waarom Google het weigert

PII staat voor personally identifiable information: gegevens waarmee je een persoon kunt identificeren. E-mailadres, naam, telefoonnummer, adres, klantnummer met naam erbij, een factuuradres in een URL.

Google verbiedt het sturen van zulke gegevens naar Google Analytics en Google Ads. Dat staat in de gebruiksvoorwaarden, niet in een richtlijn waar je omheen kunt praten. Google mag bij overtreding data verwijderen of je account sluiten.

Daarnaast heb je de AVG. Een e-mailadres in je GA4-property deel je met een verwerker voor een doel dat nergens in je verwerkingsregister staat, en je krijgt het er niet meer uit als iemand daarom vraagt.

Vrijwel niemand doet dit met opzet. Het lekt binnen.

Waar het binnenlekt

Vijf routes die we in de praktijk het vaakst tegenkomen:

  • Het e-mailadres in de URL. Een formulier dat met GET verstuurt, zet de velden in de querystring: /bedankt?email=jan@voorbeeld.nl. GA4 legt die volledige URL vast in page_location, en in de rapporten staat hij als landingspagina.
  • user_id gevuld met een e-mailadres. De user-ID is bedoeld voor een intern, niet-herleidbaar ID. Een developer die snel wil koppelen, pakt het e-mailadres, omdat dat het veld is dat in beide systemen bestaat.
  • Naam of ordergegevens in page_title. Bedankpagina's met "Bedankt Jan de Vries, order 10482". De titel gaat als page_title mee naar GA4.
  • Een formulierveld als eventparameter. Iemand bouwt een dataLayer-push op formulierverzending en neemt "voor de zekerheid" alle velden mee. Daar zitten telefoonnummer en e-mailadres tussen.
  • De volledige page_location in een server-side opstelling. Server-side GTM krijgt het verzoek met alle parameters binnen en stuurt dat door naar GA4 en naar BigQuery. In de interface zie je die rijen misschien nooit, in de export staan ze.

Hoe je het opspoort

Begin in GA4 zelf. Maak in Verkennen een vrije-vormverkenning met Paginalocatie als dimensie en een filter "bevat @". Doe hetzelfde met "bevat %40", want de apenstaart wordt vaak gecodeerd. Voeg Paginatitel toe als tweede controle.

Heb je de BigQuery-export, dan is dat de betrouwbaarste plek. Daar zie je de ruwe parameters, ook de rijen die in de interface onder (other) zijn verdwenen.

SELECT
  event_date,
  event_name,
  (SELECT value.string_value FROM UNNEST(event_params)
   WHERE key = 'page_location') AS page_location,
  COUNT(*) AS hits
FROM `mijn-project.analytics_123456789.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20240101' AND '20240131'
  AND REGEXP_CONTAINS(
        (SELECT value.string_value FROM UNNEST(event_params)
         WHERE key = 'page_location'),
        r'(@|%40)')
GROUP BY 1, 2, 3
ORDER BY hits DESC

Draai dezelfde controle op user_id en scan je eventparameters op namen als email, phone, name en postcode. Zet het weg als geplande query en laat hem maandelijks lopen: één release die een formulier omgooit, brengt dit probleem zo weer terug.

Hoe je het eruit houdt

Opschonen doe je voordat de tag afvuurt, niet erna. In GA4 zelf is er geen knop die dit terugdraait.

In GTM. Maak een eigen JavaScript-variabele die de URL herschrijft en gebruik die als page_location in je GA4-configuratie. Strip de parameters die je niet nodig hebt, of werk met een lijst van parameters die je wel toestaat. Dat tweede is veiliger: nieuwe parameters die je niet kent, komen er dan niet doorheen.

function() {
  var url = new URL({{Page URL}});
  var toegestaan = ['gclid', 'utm_source', 'utm_medium', 'utm_campaign'];
  var schoon = new URLSearchParams();
  toegestaan.forEach(function(p) {
    if (url.searchParams.has(p)) schoon.set(p, url.searchParams.get(p));
  });
  url.search = schoon.toString();
  return url.toString();
}

Server-side. Heb je een server-side container, herschrijf het daar in de client of in een transformatie, voordat de GA4-tag het verzoek naar Google stuurt. Dat vangt ook de hits die niet via jouw webcontainer binnenkomen. Welke hosting daarvoor past, beschreven we in Cloud Run of Stape.

Staat het er al in. Voor GA4 dien je een verzoek tot gegevensverwijdering in onder Beheer, en dat werkt alleen binnen de termijn die Google daarvoor hanteert. In BigQuery ben je zelf de eigenaar: daar herschrijf of maskeer je de kolom.

Gehashte e-mailadressen zijn iets anders

Hier gaat veel discussie mis. Een met SHA-256 gehasht e-mailadres naar Google Enhanced Conversions of naar de Meta Conversions API is niet hetzelfde als PII in je analytics, en is binnen de voorwaarden van die producten toegestaan.

Het verschil zit in het kanaal en het doel. Enhanced Conversions en de Conversions API zijn gebouwd om een conversie te matchen aan een gebruiker die het platform al kent. De hash gaat daarheen, niet naar je GA4-property, en komt nooit terug in een rapport.

Normaliseer voordat je hasht: spaties eraf, alles naar kleine letters. En zorg voor een geldige grondslag, want onder de AVG blijft een gehasht e-mailadres een persoonsgegeven. Consent Mode en je toestemmingsbeheer gelden onverkort.

Wat niet mag: diezelfde hash als eventparameter in GA4 zetten omdat "het toch gehasht is".

Wat je hiermee doet

  • Draai vandaag de controle op page_location met een filter op @ en %40, in een verkenning of in BigQuery.
  • Controleer of je formulieren met POST versturen. Een GET-formulier zet persoonsgegevens in de URL van iedere bezoeker die het invult.
  • Vul user_id met een intern ID of een hash, nooit met een e-mailadres.
  • Haal namen en ordergegevens uit de title van je bedankpagina, of overschrijf page_title in je tag.
  • Bouw je URL-opschoning met een lijst van toegestane parameters, in GTM of server-side, en test hem in de preview-modus voordat je publiceert.
  • Stuur gehashte e-mailadressen alleen naar Enhanced Conversions of de Conversions API, en houd ze uit je analytics.

Wil je hierover doorpraten?

Praten over jouw data?

Vertel ons over je stack, je doelen en de data die je nu mist.

Duurt 1 minuut