This workflow corresponds to n8n.io template #14145 — we link there as the canonical source.
This workflow follows the Agent → Airtable recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"meta": {
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "d9dc102f-c0f6-429d-98f2-87569eea5b5a",
"name": "Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
22288,
6288
],
"parameters": {
"color": 7,
"width": 680,
"height": 340,
"content": "## GDPR Data Subject Request Handler\nVersion 1.0.0 \u2014 Compliance\n\nProcesses inbound GDPR access/erasure requests from Gmail. Classifies the request with AI, queries Supabase (primary DB) and Airtable (CRM), compiles a full data report, sends the response to the data subject, and logs the completion to Google Sheets for audit.\n\nFlow: Gmail Trigger => Classify Request (AI Agent) => Query Supabase => Consolidate DB => Query Airtable => Consolidate CRM => Compile Report (AI Agent) => Access or Erasure? (IF) => Send Access Report / Execute Erasure => Log Audit Trail"
},
"typeVersion": 1
},
{
"id": "4e918b7c-94b3-4435-a71f-073b5064184c",
"name": "Prerequisites",
"type": "n8n-nodes-base.stickyNote",
"position": [
22976,
6256
],
"parameters": {
"color": 5,
"width": 420,
"height": 376,
"content": "## Prerequisites\n- Gmail account for incoming DSR emails (Gmail OAuth2 credential)\n- OpenAI API key (GPT-4o)\n- Supabase project with users table (Supabase API credential)\n- Airtable base with a Contacts table (Airtable Personal Access Token)\n- Google Sheets for audit log (Google Sheets OAuth2)\n- Gmail for sending responses (reuse inbox or separate send-only account)"
},
"typeVersion": 1
},
{
"id": "80c01d34-2f1e-40b6-812d-ca37a3e351f0",
"name": "Setup Required",
"type": "n8n-nodes-base.stickyNote",
"position": [
23392,
6256
],
"parameters": {
"color": 3,
"width": 420,
"height": 376,
"content": "## Setup Required\n1. Gmail Trigger \u2014 connect Gmail OAuth2 credential\n2. Classify DSR Request \u2014 connect OpenAI credential\n3. Query Supabase \u2014 connect Supabase API credential, update table name 'users'\n4. Query Airtable \u2014 connect Airtable credential, replace YOUR_BASE_ID and YOUR_TABLE_NAME\n5. Compile Report \u2014 connect OpenAI credential\n6. Send Access Report / Erasure Notice \u2014 connect Gmail OAuth2 credential\n7. Log Audit Trail \u2014 connect Google Sheets credential, replace YOUR_AUDIT_SHEET_ID"
},
"typeVersion": 1
},
{
"id": "09b6bd7a-f2c5-4ca3-936c-da80f2540858",
"name": "How It Works",
"type": "n8n-nodes-base.stickyNote",
"position": [
22288,
6640
],
"parameters": {
"color": 4,
"width": 500,
"height": 504,
"content": "## How It Works\n1. Gmail Trigger fires when a new email arrives\n2. AI Agent classifies: access or erasure, extracts requester and data subject email\n3. Supabase queried for all rows matching data subject email; Code consolidates to 1 item\n4. Airtable CRM queried for matching contact; Code consolidates to 1 item\n5. Second AI Agent compiles all found data into a human-readable GDPR report\n6. IF node routes: access => send report email; erasure => delete from both systems then send confirmation\n7. Audit trail logged to Google Sheets with timestamp, request type, and outcome"
},
"typeVersion": 1
},
{
"id": "fe4f8c23-c0aa-4e1e-86a6-7d7f20864c34",
"name": "Gmail \u2014 DSR Inbox",
"type": "n8n-nodes-base.gmailTrigger",
"position": [
22816,
7008
],
"parameters": {
"filters": {
"includeSpamTrash": false
},
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "88128837-7fd8-4b42-b94e-87f407fbfa93",
"name": "Classify note",
"type": "n8n-nodes-base.stickyNote",
"position": [
22976,
6896
],
"parameters": {
"width": 270,
"height": 60,
"content": "AI classifies request type and extracts emails from raw email body"
},
"typeVersion": 1
},
{
"id": "985b7f4e-6be7-4557-a765-0edfe3cdbae8",
"name": "Classify DSR Request",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
23024,
7008
],
"parameters": {
"text": "=Classify this GDPR data subject request email and extract all relevant details.\n\nFrom: {{ $json.from }}\nSubject: {{ $json.subject }}\nBody: {{ $json.text || $json.snippet }}\n\nDetermine if this is an access request (subject wants to see their data) or erasure request (subject wants data deleted). Extract the requester email and the data subject email (may differ if sent by a lawyer or agent).",
"options": {
"systemMessage": "You are a GDPR compliance assistant. Analyse inbound emails to determine if they are data access requests (Article 15) or data erasure requests (Article 17). Extract the requester's email and the data subject email precisely. If the request type is ambiguous, classify as 'unknown'.",
"returnIntermediateSteps": false
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 1.8
},
{
"id": "42f1ca01-579a-4135-9e46-16f630a38d89",
"name": "OpenAI \u2014 Classify",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
22928,
7232
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o"
},
"options": {
"temperature": 0
}
},
"typeVersion": 1.2
},
{
"id": "16c5bb7d-13b5-4562-aa50-0285106065d7",
"name": "DSR Classification Schema",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
23200,
7264
],
"parameters": {
"schemaType": "manual",
"inputSchema": "{\"type\":\"object\",\"properties\":{\"request_type\":{\"type\":\"string\",\"enum\":[\"access\",\"erasure\",\"unknown\"]},\"requester_email\":{\"type\":\"string\"},\"requester_name\":{\"type\":\"string\"},\"data_subject_email\":{\"type\":\"string\"},\"request_summary\":{\"type\":\"string\"}},\"required\":[\"request_type\",\"requester_email\",\"requester_name\",\"data_subject_email\",\"request_summary\"]}"
},
"typeVersion": 1.2
},
{
"id": "d70dac45-5751-4c96-9a68-487f475df720",
"name": "Supabase note",
"type": "n8n-nodes-base.stickyNote",
"position": [
23280,
6880
],
"parameters": {
"width": 207,
"height": 80,
"content": "Query users table for all rows matching data subject email"
},
"typeVersion": 1
},
{
"id": "8da85649-609d-45af-8752-f1fa2c34cd93",
"name": "Query Supabase",
"type": "n8n-nodes-base.supabase",
"onError": "continueErrorOutput",
"maxTries": 3,
"position": [
23280,
7008
],
"parameters": {
"filters": {
"conditions": [
{
"keyName": "email",
"keyValue": "={{ $json.output.data_subject_email }}",
"condition": "eq"
}
]
},
"tableId": "users",
"operation": "getAll",
"returnAll": true
},
"retryOnFail": true,
"typeVersion": 1,
"waitBetweenTries": 2000
},
{
"id": "84f6fcc1-7429-4e2d-afc5-ec540a4c015f",
"name": "Consolidate DB note",
"type": "n8n-nodes-base.stickyNote",
"position": [
23504,
6880
],
"parameters": {
"width": 254,
"height": 80,
"content": "Merges all Supabase rows into a single item to prevent duplication downstream"
},
"typeVersion": 1
},
{
"id": "d66531e0-60c3-4b63-b642-72209e325bff",
"name": "Consolidate DB Results",
"type": "n8n-nodes-base.code",
"position": [
23536,
6992
],
"parameters": {
"jsCode": "const rows = $input.all();\nconst classify = $('Classify DSR Request').first().json.output || {};\nconst dbRecords = rows.filter(r => !r.json.error).map(r => r.json);\nreturn [{ json: {\n request_type: classify.request_type,\n requester_email: classify.requester_email,\n requester_name: classify.requester_name,\n data_subject_email: classify.data_subject_email,\n request_summary: classify.request_summary,\n db_records: dbRecords,\n db_record_count: dbRecords.length\n}}];"
},
"typeVersion": 2
},
{
"id": "a033148d-af5b-4f3e-803b-e93381db0293",
"name": "Airtable note",
"type": "n8n-nodes-base.stickyNote",
"position": [
23792,
6896
],
"parameters": {
"width": 207,
"height": 80,
"content": "Query CRM Contacts table for matching email via filterByFormula"
},
"typeVersion": 1
},
{
"id": "007bb8cc-847c-41ad-8fe7-e69be4ba79be",
"name": "Query Airtable CRM",
"type": "n8n-nodes-base.airtable",
"onError": "continueErrorOutput",
"maxTries": 3,
"position": [
23792,
6992
],
"parameters": {
"base": {
"__rl": true,
"mode": "id",
"value": "YOUR_BASE_ID"
},
"table": {
"__rl": true,
"mode": "name",
"value": "YOUR_TABLE_NAME"
},
"options": {},
"operation": "search",
"filterByFormula": "={{ `{Email}='${$json.data_subject_email}'` }}"
},
"retryOnFail": true,
"typeVersion": 2.1,
"waitBetweenTries": 2000
},
{
"id": "1cc4fe23-20d4-4437-8d3b-4b1b440e9d80",
"name": "Consolidate CRM note",
"type": "n8n-nodes-base.stickyNote",
"position": [
24032,
6880
],
"parameters": {
"width": 223,
"height": 80,
"content": "Merges all Airtable rows into a single item for the AI agent"
},
"typeVersion": 1
},
{
"id": "9e9ff4e0-e746-4ed8-92c9-13934d6748e8",
"name": "Consolidate CRM Results",
"type": "n8n-nodes-base.code",
"position": [
24064,
6976
],
"parameters": {
"jsCode": "const rows = $input.all();\nconst ctx = $('Consolidate DB Results').first().json;\nconst crmRecords = rows.filter(r => !r.json.error).map(r => r.json.fields || r.json);\nreturn [{ json: {\n ...ctx,\n crm_records: crmRecords,\n crm_record_count: crmRecords.length\n}}];"
},
"typeVersion": 2
},
{
"id": "b9ebe3ed-956e-47de-8139-b8c444c581fe",
"name": "Compile note",
"type": "n8n-nodes-base.stickyNote",
"position": [
24288,
6880
],
"parameters": {
"width": 260,
"height": 60,
"content": "AI compiles all data sources into a legally-compliant GDPR report email"
},
"typeVersion": 1
},
{
"id": "de779723-f8ad-41e2-845a-fe133b4fdad9",
"name": "Compile Data Report",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
24320,
6976
],
"parameters": {
"text": "=Compile a comprehensive GDPR data report for the following request.\n\nRequest Type: {{ $json.request_type }}\nData Subject Email: {{ $json.data_subject_email }}\nRequester: {{ $json.requester_name }} <{{ $json.requester_email }}>\nRequest Summary: {{ $json.request_summary }}\n\nDatabase Records Found ({{ $json.db_record_count }}):\n{{ JSON.stringify($json.db_records, null, 2) }}\n\nCRM Records Found ({{ $json.crm_record_count }}):\n{{ JSON.stringify($json.crm_records, null, 2) }}\n\nGenerate an email subject line and full HTML email body. For access requests, list all personal data found. For erasure requests, confirm what data will be deleted.",
"options": {
"systemMessage": "You are a GDPR Data Protection Officer assistant. Compile accurate data reports for data subjects. For access requests (Article 15), list all personal data found across all systems in a clear, readable HTML table. For erasure requests (Article 17), list the data that will be erased and provide a legally-compliant confirmation. Be precise, professional, and GDPR-compliant. Output valid HTML for the email body.",
"returnIntermediateSteps": false
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 1.8
},
{
"id": "f249f49c-77ed-42ac-86cf-205043471096",
"name": "OpenAI \u2014 Compile",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
24240,
7200
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o"
},
"options": {
"temperature": 0.2
}
},
"typeVersion": 1.2
},
{
"id": "1863c521-22af-4d12-b3dd-d2dc718e932b",
"name": "Report Schema",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
24512,
7200
],
"parameters": {
"schemaType": "manual",
"inputSchema": "{\"type\":\"object\",\"properties\":{\"email_subject\":{\"type\":\"string\"},\"email_body_html\":{\"type\":\"string\"},\"data_found\":{\"type\":\"boolean\"},\"systems_checked\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"erasure_scope\":{\"type\":\"string\"}},\"required\":[\"email_subject\",\"email_body_html\",\"data_found\",\"systems_checked\"]}"
},
"typeVersion": 1.2
},
{
"id": "4092c85e-ce28-4e1a-b62a-96b304bce56b",
"name": "Route note",
"type": "n8n-nodes-base.stickyNote",
"position": [
24592,
6880
],
"parameters": {
"width": 255,
"height": 60,
"content": "Routes to access response path or erasure execution path"
},
"typeVersion": 1
},
{
"id": "d97df75d-bd31-43b3-ac41-317c82b29f3e",
"name": "Access or Erasure?",
"type": "n8n-nodes-base.if",
"position": [
24576,
7008
],
"parameters": {
"options": {},
"conditions": {
"options": {
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "cond-access",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $('Consolidate CRM Results').first().json.request_type }}",
"rightValue": "access"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "1b0d1c25-da19-424e-8473-045ff6961d43",
"name": "Send Access Report",
"type": "n8n-nodes-base.gmail",
"onError": "continueErrorOutput",
"maxTries": 3,
"position": [
24912,
6880
],
"parameters": {
"sendTo": "={{ $('Consolidate CRM Results').first().json.requester_email }}",
"message": "={{ $json.output.email_body_html }}",
"options": {},
"subject": "={{ $json.output.email_subject }}"
},
"retryOnFail": true,
"typeVersion": 2.1,
"waitBetweenTries": 2000
},
{
"id": "84422f4f-839c-47e0-9f5e-662da51fa7e0",
"name": "Delete DB note",
"type": "n8n-nodes-base.stickyNote",
"position": [
24816,
7072
],
"parameters": {
"width": 250,
"height": 60,
"content": "Deletes data subject records from Supabase (primary DB)"
},
"typeVersion": 1
},
{
"id": "1850bb05-78a2-4b9d-9358-65c556592e58",
"name": "Delete from Supabase",
"type": "n8n-nodes-base.supabase",
"onError": "continueErrorOutput",
"maxTries": 3,
"position": [
24832,
7184
],
"parameters": {
"filters": {
"conditions": [
{
"keyName": "email",
"keyValue": "={{ $('Consolidate CRM Results').first().json.data_subject_email }}",
"condition": "eq"
}
]
},
"tableId": "users",
"operation": "delete"
},
"retryOnFail": true,
"typeVersion": 1,
"waitBetweenTries": 2000
},
{
"id": "56166b3e-69aa-4944-8d77-bee31be3f5bc",
"name": "Delete from Airtable",
"type": "n8n-nodes-base.airtable",
"onError": "continueErrorOutput",
"maxTries": 3,
"position": [
25104,
7168
],
"parameters": {
"base": {
"__rl": true,
"mode": "id",
"value": "YOUR_BASE_ID"
},
"table": {
"__rl": true,
"mode": "name",
"value": "YOUR_TABLE_NAME"
},
"operation": "delete"
},
"retryOnFail": true,
"typeVersion": 2.1,
"waitBetweenTries": 2000
},
{
"id": "b72a3a77-b10b-4cb8-9fa3-8a42deaf73f8",
"name": "Send Erasure Confirmation",
"type": "n8n-nodes-base.gmail",
"onError": "continueErrorOutput",
"maxTries": 3,
"position": [
25360,
7152
],
"parameters": {
"sendTo": "={{ $('Consolidate CRM Results').first().json.requester_email }}",
"message": "={{ $('Compile Data Report').first().json.output.email_body_html }}",
"options": {},
"subject": "={{ $('Compile Data Report').first().json.output.email_subject }}"
},
"retryOnFail": true,
"typeVersion": 2.1,
"waitBetweenTries": 2000
},
{
"id": "862503ff-b689-47c2-bb91-2dc2013ed77a",
"name": "Merge note",
"type": "n8n-nodes-base.stickyNote",
"position": [
25440,
6816
],
"parameters": {
"width": 260,
"height": 60,
"content": "Merges both paths back to a single flow for audit logging"
},
"typeVersion": 1
},
{
"id": "61adce98-8cac-441b-a785-e3664479ac4f",
"name": "Merge Paths",
"type": "n8n-nodes-base.merge",
"position": [
25488,
6928
],
"parameters": {
"mode": "chooseBranch"
},
"typeVersion": 3
},
{
"id": "b5f11bb5-88fb-4bc5-8417-eb3bc2b9bfc4",
"name": "Audit note",
"type": "n8n-nodes-base.stickyNote",
"position": [
25824,
6816
],
"parameters": {
"width": 260,
"height": 60,
"content": "Logs every DSR to Google Sheets for GDPR-required audit trail"
},
"typeVersion": 1
},
{
"id": "5ca6fe3f-4239-4ee8-9598-079ebf6e95fe",
"name": "Log Audit Trail",
"type": "n8n-nodes-base.googleSheets",
"onError": "continueErrorOutput",
"maxTries": 3,
"position": [
25872,
6928
],
"parameters": {
"columns": {
"value": {
"Status": "completed",
"Summary": "={{ $('Consolidate CRM Results').first().json.request_summary }}",
"Timestamp": "={{ DateTime.now().toISO() }}",
"Data Subject": "={{ $('Consolidate CRM Results').first().json.data_subject_email }}",
"Request Type": "={{ $('Consolidate CRM Results').first().json.request_type }}",
"Requester Email": "={{ $('Consolidate CRM Results').first().json.requester_email }}",
"DB Records Found": "={{ $('Consolidate CRM Results').first().json.db_record_count }}",
"CRM Records Found": "={{ $('Consolidate CRM Results').first().json.crm_record_count }}"
},
"mappingMode": "defineBelow"
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "DSR Audit Log"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_AUDIT_SHEET_ID"
}
},
"retryOnFail": true,
"typeVersion": 4.5,
"waitBetweenTries": 2000
}
],
"connections": {
"Merge Paths": {
"main": [
[
{
"node": "Log Audit Trail",
"type": "main",
"index": 0
}
]
]
},
"Report Schema": {
"ai_outputParser": [
[
{
"node": "Compile Data Report",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Query Supabase": {
"main": [
[
{
"node": "Consolidate DB Results",
"type": "main",
"index": 0
}
]
]
},
"Access or Erasure?": {
"main": [
[
{
"node": "Send Access Report",
"type": "main",
"index": 0
}
],
[
{
"node": "Delete from Supabase",
"type": "main",
"index": 0
}
]
]
},
"OpenAI \u2014 Compile": {
"ai_languageModel": [
[
{
"node": "Compile Data Report",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Query Airtable CRM": {
"main": [
[
{
"node": "Consolidate CRM Results",
"type": "main",
"index": 0
}
]
]
},
"Send Access Report": {
"main": [
[
{
"node": "Merge Paths",
"type": "main",
"index": 0
}
]
]
},
"Compile Data Report": {
"main": [
[
{
"node": "Access or Erasure?",
"type": "main",
"index": 0
}
]
]
},
"Gmail \u2014 DSR Inbox": {
"main": [
[
{
"node": "Classify DSR Request",
"type": "main",
"index": 0
}
]
]
},
"OpenAI \u2014 Classify": {
"ai_languageModel": [
[
{
"node": "Classify DSR Request",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Classify DSR Request": {
"main": [
[
{
"node": "Query Supabase",
"type": "main",
"index": 0
}
]
]
},
"Delete from Airtable": {
"main": [
[
{
"node": "Send Erasure Confirmation",
"type": "main",
"index": 0
}
]
]
},
"Delete from Supabase": {
"main": [
[
{
"node": "Delete from Airtable",
"type": "main",
"index": 0
}
]
]
},
"Consolidate DB Results": {
"main": [
[
{
"node": "Query Airtable CRM",
"type": "main",
"index": 0
}
]
]
},
"Consolidate CRM Results": {
"main": [
[
{
"node": "Compile Data Report",
"type": "main",
"index": 0
}
]
]
},
"DSR Classification Schema": {
"ai_outputParser": [
[
{
"node": "Classify DSR Request",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Send Erasure Confirmation": {
"main": [
[
{
"node": "Merge Paths",
"type": "main",
"index": 1
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Handles GDPR Article 15 (access) and Article 17 (erasure) requests end-to-end — from inbound email to legally-compliant response — with zero manual intervention and a full audit trail. 📬 Monitors Gmail inbox for incoming data subject requests 🤖 AI Agent classifies the request…
Source: https://n8n.io/workflows/14145/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
• Multi-Layer Message Analysis - Every customer interaction passes through three specialized AI classifiers: privacy detection (identifies sensitive data and security requirements), intent recognition
This n8n workflow automates the transformation of spreadsheet data into professional charts and graphs using AI-driven analysis. Triggered via Slack, it processes uploaded files (Excel, CSV, Google Sh
mails2notion V2. Uses lmChatOpenAi, toolCalculator, outputParserStructured, gmail. Event-driven trigger; 38 nodes.
Splitout Filter. Uses toolWorkflow, lmChatOpenAi, outputParserStructured, manualTrigger. Event-driven trigger; 38 nodes.
Xmind Sales Email v2. Uses gmailTrigger, notion, googleSheets, googleSheetsTrigger. Event-driven trigger; 37 nodes.