Most website GDPR audits begin with a questionnaire and end with a score. The result may look official, but it often leaves the developer with the same question: what exactly should change in the code?
A technical audit has a narrower and more useful job. It records what the website actually does in a browser, under defined consent states, and compares that behaviour with the site’s own disclosures. It can find a Google request fired before consent, a forgotten tracking pixel, an external font, a form that sends more fields than expected, or a Reject button that changes the interface but not the network.
It cannot certify the whole organisation as GDPR-compliant. A browser does not know the company’s legal basis, contracts, offline processes, staff access, or whether a stated business purpose is legitimate.
The right deliverable is an evidence report, not a magic percentage.
Executive Summary
- A developer can test network requests, storage, scripts, embeds, form behaviour, consent states, security headers, and policy/runtime mismatches.
- Each test must start from a clean browser profile and record the page, time, region, browser, and consent state.
- Findings should separate observed evidence, technical interpretation, and questions requiring legal or organisational review.
- Reject, selective consent, Accept all, withdrawal, and a returning visit are different application states and should be tested separately.
- Automated scanning can cover repeatable browser behaviour. It cannot prove a lawful basis, validate every contract, or certify GDPR compliance.
Define the scope before opening DevTools
A reproducible audit starts with a page list and a state matrix, not random clicking. The homepage alone rarely exercises contact forms, video embeds, checkout tools, account areas, or marketing landing pages.
Select representative page types:
- homepage;
- contact or lead form;
- article with embedded media;
- service or campaign landing page;
- search, login, checkout, or account page where applicable;
- one page per language or regional version;
- any page that loads a different tag-manager container or integration.
For every page, plan the same consent states:
| State | What it answers |
|---|---|
| Fresh visit | What loads before the visitor decides? |
| Reject optional | Does refusing change requests and storage? |
| Selective consent | Are purposes and providers actually separated? |
| Accept all | Which optional services become active? |
| Withdraw | Can the visitor reverse the decision effectively? |
| Returning visit | Is the saved choice respected without a flash of early loading? |
Record the test region because provider behaviour and consent interfaces may vary by geography. Record browser and timestamp because third-party scripts change.
Capture the network before consent
The first page load is the highest-value test because optional services often initialise before the consent tool does. Use a clean browser context, preserve the network log, disable cache, and do not interact with the page until loading has settled.
For every request, retain:
- full destination domain and path, with secrets and personal values redacted;
- initiator or call chain;
- resource type;
- timestamp relative to navigation;
- request method;
- relevant request and response headers;
- whether the domain is first party or third party;
- which page component appears to trigger it.
Do not classify a request only by its domain name. A CDN may serve a necessary stylesheet on one site and tracking code on another. The evidence should connect the request to its observed purpose and initiator.
Useful categories include analytics, advertising, session replay, error reporting, chat, maps, video, fonts, A/B testing, payment, anti-spam, CDN, tag management, and unknown.
Unknown is a valid finding. Guessing is not.
Inspect browser storage, not only cookies
A cookie list misses localStorage, sessionStorage, IndexedDB, caches, and identifiers passed through URLs. Record storage before interaction and after each consent action.
For each item, capture:
- name or key;
- origin;
- creation state;
- expiry where visible;
- value shape after redaction;
- likely owner and initiator;
- observed change between consent states.
Avoid copying live identifiers into the report. Hash or redact values while preserving enough structure to show that the same identifier persists across page loads.
Under German TDDDG Section 25, the technical question is broader than whether a browser cookie exists. Storage of information on, or access to information from, terminal equipment may involve other mechanisms. The legal assessment of an exemption still requires context, but the developer can document the behaviour precisely.
Prove that consent controls execution
A consent interface works only when its state changes what the application loads or accesses. Test behaviour, not button labels.
Compare request and storage sets after:
- no choice;
- Reject all optional purposes;
- analytics-only consent;
- another available category;
- Accept all;
- withdrawal;
- reload and a new page navigation.
Flag observable discrepancies:
- the same optional request appears before consent and after Accept;
- Reject and Accept produce identical behaviour;
- a disabled category still starts its provider;
- withdrawing updates the banner but future requests continue;
- optional code briefly loads before the stored Reject preference is applied;
- the consent record contains a choice, but the application never reads it;
- tags are blocked on the homepage but fire on another template.
The German supervisory authorities’ cookie-banner guidance states that consent-dependent scripts should initially remain blocked and should execute only after active consent. That gives developers a direct implementation test.
Map every third party to a component and disclosure
A domain inventory becomes useful when it identifies why the request exists and where it comes from. For each third party, map:
| Evidence field | Example |
|---|---|
| Provider or domain | External font host |
| Initiating component | Global stylesheet |
| First observed state | Fresh visit, before choice |
| Data visible in request | IP connection data, user agent, referrer depending on request |
| Site disclosure | Provider absent from EN and PL privacy notices |
| Technical remediation | Self-host licensed font files and remove preconnect |
| Manual review | Confirm disclosure and legal analysis |
This prevents vague tickets such as “fix GDPR.” A developer receives a concrete component, request, state, and expected result.
External fonts are a good example. The audit does not need to declare a legal violation to show that the visitor’s browser contacts a third party before consent. Self-hosting the font may remove the transfer and improve resilience and performance at the same time.
Test forms and data minimisation
A form audit compares the visible fields, transmitted payload, destination, and retained records. Never submit real personal data during testing. Use clearly synthetic values and avoid triggering messages to real staff or external workflows without permission.
Check:
- hidden fields added by plugins or marketing scripts;
- full page URLs and referrers attached to a submission;
- third-party form endpoints;
- CAPTCHA and anti-spam providers;
- client-side validation messages exposing submitted content;
- duplicate copies in analytics, email, CRM, and logs;
- fields collected but not used by the stated workflow;
- whether sensitive values appear in GET parameters or browser history.
The technical report can identify unnecessary fields and unexpected destinations. The business owner must confirm the purpose and required retention.
Compare runtime behaviour with every policy language
The privacy notice should describe the system that currently runs, not the system remembered from the last redesign. Extract provider names, purposes, retention statements, and consent claims from each language version and compare them with observed behaviour.
Look for:
- a live provider missing from the notice;
- a retired provider still documented;
- analytics described as consent-gated while it fires immediately;
- different provider lists across languages;
- broken privacy or imprint links;
- an interface that calls a category “necessary” while the policy describes it as optional analytics;
- retention periods that do not match configuration;
- no explanation of how to change a decision.
A mismatch is not automatically proof of unlawful processing. It is strong evidence that implementation and documentation need a joint review.
Check security signals without overstating them
A public scan can find useful security weaknesses, but it cannot see the complete security programme. Record observable controls such as:
- HTTPS and mixed content;
- HSTS and redirect behaviour;
- Content Security Policy;
- framing protections;
- Referrer-Policy;
- Permissions-Policy;
- cookie flags such as
Secure,HttpOnly, andSameSite; - exposed source maps, keys, debug endpoints, or stack traces;
- public administrative paths and software version leakage.
Missing headers do not alone prove a GDPR violation. They can still indicate avoidable exposure and inform the Article 32 security review.
Do not run intrusive vulnerability tests as part of a routine privacy scan. Port scanning, authentication attacks, form flooding, exploit attempts, or access to private areas require separate authorisation and scope.
Write findings developers can close
Every finding should contain enough evidence to reproduce and retest it. Use a consistent structure:
ID: CONSENT-003
Observed: analytics request fired 420 ms after navigation in a clean profile
Page: /services/
Consent state: untouched
Initiator: /assets/analytics-loader.js
Evidence: network-before-consent.json, request 47, screenshot 02
Likely issue: optional analytics appears to start before a user choice
Source: TDDDG §25 and DSK consent guidance
Remediation: gate loader behind the analytics consent state
Manual review: confirm purpose, configuration, and claimed legal basis
Retest: request must be absent before consent and after Reject
Severity should reflect exposure and confidence, not visual drama. A useful model considers whether personal or device information is involved, how early and broadly the behaviour occurs, how many pages are affected, whether the visitor can prevent it, and how certain the evidence is.
What automated scanners can and cannot establish
Automation should report observed browser behaviour and stop before pretending to be a lawyer.
| Automated check can establish | It cannot establish alone |
|---|---|
| A request occurred before consent | The organisation’s complete lawful-basis analysis |
| Storage differed after Accept | That consent wording is valid in every context |
| A provider is absent from policy text | The contents of every contract or DPA |
| Reject and Accept behaved identically | The company’s offline processing activities |
| A withdrawal control was not found | That no alternative valid withdrawal path exists anywhere |
| A security header is missing | That the entire processing environment is insecure |
Avoid a universal compliance score. Combining one missing header, one external font, and one serious pre-consent tracker into “63% compliant” creates precision without meaning.
Retest after remediation
A finding is not closed when the code changes; it is closed when the expected browser behaviour is observed. Repeat the original test with the same page, browser, region, state, and capture method.
Keep before and after evidence. The final record should show:
- original observation;
- implemented change;
- new request and storage comparison;
- remaining limitations;
- tester and timestamp;
- audit rule or methodology version.
This turns privacy work into ordinary engineering: scoped behaviour, evidence, change, and regression test.
Frequently asked questions
Can a developer perform a GDPR audit without a lawyer?
A developer can perform the technical evidence collection and identify implementation discrepancies. Legal counsel or a data protection specialist should evaluate questions involving lawful basis, contracts, high-risk processing, rights, and organisational context.
Is a cookie scanner enough?
No. It may miss local storage, pixels, fingerprinting, server-side forwarding, embedded content, form destinations, consent-state bugs, and policy mismatches. Use browser instrumentation and compare multiple states.
Should the audit click Accept automatically?
It may do so in a controlled test after capturing the untouched and Reject states. Automated interaction must record which control was clicked and verify the resulting behaviour rather than assume the button worked.
Can we scan a client’s website without access to its code?
You can observe public browser behaviour, but code access makes remediation and initiator mapping much stronger. Get permission before actions that submit forms, enter private areas, or create load.
How often should the audit run?
Run it after consent, analytics, marketing, embed, form, or deployment changes, and periodically because third-party scripts evolve. High-change marketing sites benefit from scheduled regression scans.
Official sources
- GDPR on EUR-Lex
- TDDDG Section 25
- DSK guidance on cookie banners and consent tools
- DSK telemedia guidance, version 1.1
- EDPB Guidelines 4/2019 on Data Protection by Design and by Default
A useful audit should leave your developer with evidence and closable tasks, not a badge. Run the free check on your homepage to see the first evidence in a minute, or ask ILF Studio for a full technical audit.