Sub-processor list template · checked
Sub-processor list template, column by column
A GDPR sub-processor list has one row per vendor that processes personal data on your behalf: who it is, what it does for you, which personal data it receives, where it processes it and on what transfer terms, and the agreement that binds it, with the date the list last changed. Copy the table below, or draft its rows from your code.
The columns, and why each is there
| Sub-processor | The vendor's legal name, as your contract with it names the entity. Customers must be able to tell who it is; EDPB Opinion 22/2024 expects you to know every processor in the chain. |
|---|---|
| Purpose | What it does for you: hosting, payments, email delivery, LLM inference. |
| Personal data | The categories it receives: names and emails, billing details, prompts, IP addresses. Not the fields, the kinds. |
| Location | Where it processes the data: a region you chose in its settings, or where it says it processes. It decides the transfer column. |
| Transfer mechanism | Only for processing outside the EEA: the Standard Contractual Clauses, or the EU-US Data Privacy Framework if the vendor is certified. Its DPA says which. |
| DPA | A link to the data processing agreement that binds it to the same obligations as you. |
| Its own sub-processors | A link to the vendor's list: the next link in the chain, for a customer who wants to trace it. |
| Since | The day it was added. With the list's own last-changed date, this is the record a notice is checked against. |
Copy it
Markdown, with the first rows of the example below filled in. Replace each vendor name with the entity your contract names, and every YYYY-MM-DD.
## Sub-processors Last changed: YYYY-MM-DD. We give customers N days' notice of a new sub-processor; subscribe at <link>. | Sub-processor | Purpose | Personal data | Location | Transfer mechanism | DPA | Since | | --- | --- | --- | --- | --- | --- | --- | | Vercel (legal entity) | Hosting and serverless functions; Web analytics (Vercel Analytics) | Everything your app serves and handles while it runs there, including request logs with IP addresses | fra1 (Frankfurt) | if outside the EEA | [DPA](https://vercel.com/legal/dpa) | YYYY-MM-DD | | Amazon Web Services (legal entity) | Cloud infrastructure; File storage (S3) | Depends on the services you use: anything you store or process there | eu-central-1 | if outside the EEA | [DPA](https://d1.awsstatic.com/legal/aws-dpa/aws-dpa.pdf) | YYYY-MM-DD | | Neon (legal entity) | Serverless Postgres database | All personal data your app stores | region | if outside the EEA | [DPA](https://neon.com/dpa) | YYYY-MM-DD | | … | | | | | | |
Rows drafted from code
The first rows of a list drafted from a small app's code (synthetic, written for the demo); the full example shows every row and where each came from.
| Sub-processor | Purpose | Personal data | Location | DPA |
|---|---|---|---|---|
| Vercel | Hosting and serverless functions; Web analytics (Vercel Analytics) | Everything your app serves and handles while it runs there, including request logs with IP addresses | fra1 (Frankfurt) | DPA |
| Amazon Web Services | Cloud infrastructure; File storage (S3) | Depends on the services you use: anything you store or process there | eu-central-1 | DPA |
| Neon | Serverless Postgres database | All personal data your app stores | to confirm | DPA |
| Stripe | Payments and billing | Customers' names, email and billing addresses; card details, which the vendor holds | to confirm | DPA |
Draft yours
$ grep -rnE --include=package.json --exclude-dir=node_modules '"(@ai-sdk/amazon-bedrock|@ai-sdk/anthropic|@ai-sdk/azure|@ai-sdk/cohere|@ai-sdk/gateway|@ai-sdk/google|@ai-sdk/google-vertex|@ai-sdk/groq|@ai-sdk/mistral|@ai-sdk/openai|@ai-sdk/togetherai|@ai-sdk/xai|@algolia/[^"]*|@amplitude/[^"]*|@anthropic-ai/bedrock-sdk|@anthropic-ai/claude-agent-sdk|@anthropic-ai/sdk|@anthropic-ai/vertex-sdk|@auth0/[^"]*|@aws-sdk/[^"]*|@aws-sdk/client-bedrock-runtime|@aws-sdk/client-dynamodb|@aws-sdk/client-s3|@aws-sdk/client-ses|@aws-sdk/client-sesv2|@aws-sdk/client-sqs|@aws-sdk/lib-dynamodb|@aws-sdk/lib-storage|@axiomhq/[^"]*|@azure/[^"]*|@azure/openai|@azure/storage-blob|@clerk/[^"]*|@cloudflare/next-on-pages|@cloudinary/[^"]*|@datadog/[^"]*|@deepgram/sdk|@discordjs/[^"]*|@elevenlabs/[^"]*|@google-cloud/[^"]*|@google-cloud/bigquery|@google-cloud/storage|@google-cloud/vertexai|@google/genai|@google/generative-ai|@helicone/[^"]*|@huggingface/inference|@intercom/[^"]*|@langfuse/[^"]*|@lemonsqueezy/[^"]*|@libsql/client|@liveblocks/[^"]*|@logtail/[^"]*|@mistralai/mistralai|@mux/[^"]*|@neondatabase/[^"]*|@netlify/[^"]*|@openai/agents|@opennextjs/cloudflare|@openrouter/ai-sdk-provider|@openrouter/sdk|@paddle/[^"]*|@pinecone-database/[^"]*|@planetscale/database|@plausible-analytics/tracker|@posthog/[^"]*|@prisma/adapter-neon|@segment/[^"]*|@sendgrid/[^"]*|@sentry/[^"]*|@slack/[^"]*|@stripe/[^"]*|@supabase/[^"]*|@trigger\.dev/[^"]*|@tursodatabase/[^"]*|@uploadthing/[^"]*|@upstash/[^"]*|@vercel/analytics|@vercel/blob|@vercel/edge-config|@vercel/functions|@vercel/kv|@vercel/og|@vercel/postgres|@vercel/speed-insights|@workos-inc/[^"]*|ably|algoliasearch|analytics-node|apify|apify-cli|apify-client|auth0|aws-cdk-lib|aws-sdk|cloudflare|cloudinary|cohere-ai|crisp-api|crisp-sdk-web|dd-trace|discord\.js|elevenlabs|firebase|firebase-admin|firebase-tools|ga-4-react|groq-sdk|inngest|intercom-client|langfuse|langfuse-langchain|langfuse-vercel|loops|mailgun-js|mailgun\.js|mixpanel|mixpanel-browser|mongodb|mongoose|netlify-cli|next-axiom|next-cloudinary|next-plausible|openai|plausible-tracker|posthog-js|posthog-node|postmark|pusher|pusher-js|raven-js|react-ga4|react-instantsearch|react-use-intercom|replicate|resend|stripe|supabase|together-ai|twilio|uploadthing|vercel|wrangler)"[[:space:]]*:' .
Run it from the repository root; it needs nothing installed and sends nothing anywhere. It finds every dependency, in every package.json, that names one of the 69 vendors in the table below. It cannot see a vendor your code calls without an SDK (an API host in a string, a webhook URL), or one named only by an env variable; check those by hand.
Not legal advice. Whether a vendor is your sub-processor depends on the personal data you send it and on your contracts; a list drafted from code is a draft for you to confirm, row by row. It also misses vendors outside the code (your workspace, support desk, CRM, payroll): add those by hand.
A hosted, dated sub-processor page that emails your customers each change is not built.
It would publish the list you approved at a public URL, keep every change with its date, email your subscribers the notice with the day their objection window closes, and record who was told when. agentcheck runs scheduled checks of endpoints today; this is not one of them. If you would pay for it, say so with one click. The click is counted; nothing else is sent or stored.
Counted. Thank you; nothing else was sent.Sources
- GDPR Art. 28: processor (read 9 October 2026)
- EDPB Opinion 22/2024 on sub-processing chains (Hogan Lovells summary) (read 9 October 2026)
- GitHub subprocessors: notice at least 30 days in advance (read 9 October 2026)
- Stripe's DPA: 30 days to object, then deemed accepted (ConductAtlas) (read 9 October 2026)
subprocessors is a free tool from agentcheck, which runs scheduled checks of your endpoints and alerts you when an answer changes. Vendor links come from each vendor's own pages, read on the day shown.