§Use caseOne operator

Watch your vendors' policy pages

A vendor adds a company to its subprocessor list. Where you gave general authorisation, it is supposed to inform you of that change so you have the chance to object. In practice it discharges that by publishing a page and waiting for somebody to read it, and almost nobody does. Below is how I watch those pages instead, including the eighteen subprocessors an early version of this parser invented before I caught it.

Resend's real register, compared against an archived copy of the same page from 2024
Resend's real register, compared against an archived copy of the same page from 2024
A parsed subprocessor register: six suppliers added and four removed, each named, with the date the comparison runs from.

The questionHow do I know when a supplier changes its terms or adds a subprocessor?

How the working version is put together

  1. Give it pages, or give it domains

    One URL per line if you already know them. A terms page, a privacy policy, a DPA, a subprocessor list, a security page: whatever you actually care about. Or hand it bare domains instead. It fetches each homepage and follows the links whose text or address points at privacy, terms, data processing, subprocessors or trust. Where the subprocessor link is missing from the homepage it takes one more hop through the privacy or terms page, which is usually where it actually lives.

  2. Reduce each page to its readable text

    Everything runs on plain HTTP requests, with no browser and no proxy behind it. The page gets stripped to the text a human would read, which is what makes a diff mean something. Comparing raw HTML would flag a changed build hash as a policy change and you would stop reading the alerts by the second week.

  3. Parse the register into named rows

    This is the part I care most about. A supplier register on the page becomes rows. Each row carries the supplier's name, alongside what that supplier does for the vendor and where the processing happens. It reads a register laid out as a table and one laid out as a bulleted list, because vendors genuinely do both.

  4. Compare by name, not by position

    Rows are matched against the last run by supplier name, with common company suffixes ignored so Acme Ltd and Acme Limited are one supplier. A vendor reordering its table alphabetically is not fifteen changes, and if the diff said it was you would learn to ignore it.

  5. Report what moved, in one sentence

    Back comes whether the page changed and how much of its text survived. Under that sit the lines that appeared and the lines that went away. Then the answer people actually want: these suppliers are new, that one is gone. What it will never tell you is what the change means legally. That is a contract question, and I will not have a scraper answering it.

The obligation this sits under

Article 28 of the GDPR is the one that governs processors. Under paragraph 2, a processor must not engage another processor without the controller's authorisation, and where that authorisation is given in general terms, the processor has to inform the controller of intended changes to the addition or replacement of other processors so the controller has the opportunity to object. I checked the wording at source rather than quoting it from memory.

That is what turns this from page-diffing into something with a reason. The vendor's usual way of informing you is a published page and an expectation that you are watching it. Almost nobody is. Worth saying plainly: a change this tool finds is not evidence that anyone breached anything. It reports what moved on a page. Whether it matters, and whether you were properly notified, belongs to whoever owns the contract.

What it parsed, counted

I ran the parser against live pages and checked every row by hand. Resend came back 22 of 22. Sentry came back 11 of 11, and it correctly dropped a postal address that was sitting inside the name cell rather than treating it as a supplier. n8n gave 9. Datadog gave 28. Buttondown gave 11.

Then I ran a real historical diff against Sentry's own page, comparing an older version to the current one. Three subprocessors added, one removed, with the summary naming them. Those are counts from my own testing and nothing more. There is no customer behind them, because this tool has no customers yet.

The eighteen subprocessors I invented

An early version had a fallback for tables whose header it did not recognise: assume the first column is the supplier name. Pointed at Sentry's DPA, it read the prose and reported eighteen subprocessors that do not exist. Every one of them looked completely plausible in the output.

A compliance tool that invents suppliers is worse than no tool, because you would act on it. So the fallback is gone. A table now needs a real name header before it is treated as a register, and a bare list of names with nothing else is skipped on purpose, since that is also what a page's link menu looks like. I would rather return nothing than return something confident and wrong.

What it cannot reach, and what it costs

Three well known vendors defeat a plain HTTP client, and I hit all three while testing. Cloudflare's own subprocessor page serves a JavaScript shell with no text in it. OpenAI returns a 403. Notion returns a 401. Those land in the output as errors rather than as a quiet pass, which matters more than the failure itself: an empty result that looks like a clean result is the failure mode worth engineering against.

Page discovery is best effort and does not reach pages more than two hops from a homepage, so pin the URLs once you know them. The first run has nothing to compare against and says so, which makes the second run the first one that tells you anything. Running cost is $0.004 per page checked, and a page that failed to load is not charged.

Read this before you spend anything

When I would tell you not to bother

If you have two vendors, bookmark their pages and look once a quarter. This is for the estate where twenty pages need watching and the job gets done thoroughly once, then never again.

If what you want is a verdict on whether a change puts you offside, this does not give you one and should not. It tells you what moved and who appeared. The judgement belongs to whoever owns the contract.

What lands on your desk

  • One row per watched page, with what changed since the last run
  • Suppliers added and removed by name, matched across a reordered table
  • The added and removed lines, plus how much of the page's text survived
  • Errors surfaced as errors, so a page nobody could read never passes quietly
  • If you want this wired into a register, a ticket or a monthly compliance digest, that is the work I do

Questions this page answers

What does GDPR Article 28 actually require here?
Under paragraph 2, a processor must not engage another processor without the controller's authorisation, and where that authorisation is general, the processor has to inform the controller of intended changes to the addition or replacement of other processors so the controller has the opportunity to object. I checked that wording at source.
Does a detected change mean my vendor breached something?
No, and the tool never says so. It reports what moved on a page. Whether the change matters, and whether you were properly notified, is a contract question for whoever owns the contract.
How accurate is the subprocessor parsing?
In my own testing it read Resend at 22 of 22 and Sentry at 11 of 11, correctly dropping a postal address embedded in a name cell. n8n gave 9, Datadog 28 and Buttondown 11. An earlier version with a loose fallback invented eighteen suppliers out of Sentry's DPA prose, so that fallback was removed and a real name header is now required.
Are there vendors it cannot read?
Yes, three that I hit in testing. Cloudflare's subprocessor page serves a JavaScript shell, OpenAI returns a 403 and Notion returns a 401. Those come back as errors rather than as an empty result that looks clean.
Why does the first run tell me nothing?
Because it has nothing to compare against, so it saves the baseline and says so. The second run is the first one that can report a change.

Want this built and handed over working?

One line is enough to start. You get an honest answer on fit, and a number rather than a discovery call.

Start a brief