Auditing a privacy policy against the codebase
A privacy policy is a set of factual claims about a running system. Those claims can be checked the same way you check anything else — by reading the code.
Most privacy policies are written once, at the point where a company needs one, and then quietly diverge from the product for years. Not through negligence — through ordinary shipping. Every feature that stores something new, and every integration added after the policy was signed off, moves the system further from the document describing it.
The useful reframing is that a privacy policy is not a legal artefact that happens to mention software. It is a set of factual claims about a running system, and factual claims can be verified.
Here is the method we use.
Start from the schema, not the policy
Reading the policy first anchors you to it, and you end up confirming what it says instead of discovering what it missed.
Enumerate every table that stores anything about a person. For each one, find the code that writes to it and answer three questions: what fields does it actually capture, who can trigger the write, and what deletes the row.
That last question is usually the one with no answer. Retention clauses tend to describe an intention rather than a mechanism — and if nothing prunes the table, the honest statement is that the data is kept until the account is deleted, not that it is kept "for a limited period".
Pay attention to models added after the policy's effective date. That date is on the page; anything newer is worth a second look. In our case an entire support-request feature — subject lines, categories, full message threads — had shipped without the word "support" appearing anywhere in the policy.
Separate wired from configured
This is where the audit repays the effort, and it is the check people skip.
For every third-party SDK, establish two independent facts:
- Is the integration present in the code?
- Is it actually configured, with a key or DSN, in production?
These come apart constantly. An analytics or error-monitoring provider gets wired up during a sprint, the account is never created, and the integration sits there initialising to nothing. The provider ends up named in the policy as a sub-processor while having never received a single byte.
Naming a processor that holds nothing is a smaller problem than omitting one that does, but it is still an inaccuracy, and on a page whose entire purpose is to be trusted it costs more than it saves. We now mark those providers as planned rather than deleting them — it stays auditable without overstating where data goes.
Follow the assets, not just the API calls
The omission that matters most is rarely a service your servers call. It is a service your visitors' browsers call.
An image host is the classic example. Uploads go through your backend, so it reads as internal infrastructure. But the stored URL points at the provider's CDN, and every reader who loads a page containing that image makes a direct request — sending their IP address and user-agent to a third party, quite possibly in another jurisdiction.
That is a disclosable transfer, and it is invisible if you only audit server-side integrations. The same reasoning applies to externally-hosted fonts, embedded video, and any <img> or <script> whose src is not your own domain.
A quick way to find them all: load a page, open the network panel, and list every distinct domain your browser contacted. Anything that is not you is a candidate.
Check both directions
Audits naturally look for missing disclosures. Look for surplus ones too — capabilities the policy claims that the product does not have.
Both are inaccuracies. Under-disclosure carries the regulatory risk; over-disclosure quietly erodes the credibility of everything else on the page, because a reader who checks one claim and finds it hollow has no reason to trust the rest.
Make it a habit, not an event
The audit is cheap once you have done it once. What keeps it accurate is attaching it to the moments where drift is introduced: a new model that stores personal data, or a new third-party integration, should both prompt the question of whether the policy still describes the system.
It is the same discipline as keeping documentation current, applied to a document that has consequences when it is wrong.