This workflow corresponds to n8n.io template #11065 — we link there as the canonical source.
This workflow follows the Form Trigger → Gmail 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
},
"name": "Sanitize JSON and Send Email Report_Final",
"tags": [],
"nodes": [
{
"id": "d0303f81-dfca-456c-8990-71d14d2da439",
"name": "Upload Workflow Json",
"type": "n8n-nodes-base.formTrigger",
"position": [
608,
384
],
"parameters": {
"options": {},
"formTitle": "Upload Json file to convert to Sanitized JSON version",
"formFields": {
"values": [
{
"fieldType": "email",
"fieldLabel": "Mailid"
},
{
"fieldType": "file",
"fieldLabel": "Upload JSON file"
}
]
},
"formDescription": "Upload Json file to convert to Sanitized JSON version"
},
"typeVersion": 2.3
},
{
"id": "a33e42f3-cc09-4752-9746-b144cc7d3925",
"name": "Extract JSON content",
"type": "n8n-nodes-base.extractFromFile",
"position": [
832,
464
],
"parameters": {
"options": {},
"operation": "fromJson",
"destinationKey": "workflowJson",
"binaryPropertyName": "Upload_JSON_file"
},
"typeVersion": 1
},
{
"id": "c40fbf1e-6796-4e9d-a4ce-7c167acf8e72",
"name": "Prepare Original Workflow Structure",
"type": "n8n-nodes-base.set",
"position": [
992,
464
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "46fbddbe-8795-40f8-a8f1-492c9aed2d61",
"name": "originalWorkflowJson",
"type": "object",
"value": "={{$json.workflowJson}}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "b99dd6eb-3bd2-4952-8afb-63fe48ee2546",
"name": "Format Original Workflow(JS)",
"type": "n8n-nodes-base.code",
"position": [
1168,
464
],
"parameters": {
"jsCode": "// Starting from the wrapped original workflow\nconst original = $json.originalWorkflowJson;\n\n// Recursively remove heavy fields that we *know* we don't need the AI for.\nfunction walk(value, depth = 0) {\n if (Array.isArray(value)) {\n return value.map(v => walk(v, depth + 1));\n }\n if (value && typeof value === 'object') {\n const out = {};\n for (const [key, val] of Object.entries(value)) {\n // Remove credentials everywhere\n if (key === 'credentials') continue;\n // Remove webhookId everywhere\n if (key === 'webhookId') continue;\n // Remove some top-level metadata\n if (depth === 0 && (key === 'meta' || key === 'versionId' || key === 'id')) continue;\n\n out[key] = walk(val, depth + 1);\n }\n return out;\n }\n return value;\n}\n\nconst preTrimmed = walk(original);\n\nreturn [{\n json: {\n originalWorkflowJson: original,\n preTrimmedWorkflowJson: preTrimmed,\n },\n}];\n"
},
"typeVersion": 2
},
{
"id": "c6c2b911-c74e-450a-856f-aeb5f4236844",
"name": "AI Sanitize Workflow JSON",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
1376,
336
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4.1-mini",
"cachedResultName": "GPT-4.1-MINI"
},
"options": {},
"responses": {
"values": [
{
"content": "=={{ JSON.stringify($json.preTrimmedWorkflowJson || $json.originalWorkflowJson) }}\n\n"
},
{
"role": "system",
"content": "=You are n8n Workflow Secret Sanitizer.\n\nYour only job is to receive one n8n workflow JSON and return a fully sanitized version that is safe to share and fully importable back into n8n.\n\nFollow these rules strictly:\n\n1. RETURN ONLY THE SANITIZED JSON OBJECT.\n - No explanations, no markdown, no code fences, no text outside the JSON.\n - Output must be valid JSON.\n\n2. REMOVE the following everywhere in the workflow:\n - Any key named \"credentials\"\n - Any key named \"webhookId\"\n - Root-level: \"meta\", \"versionId\", \"id\"\n\n3. STICKY NOTES (type: \"n8n-nodes-base.stickyNote\"):\n - Do not modify them in any way.\n - Do NOT sanitize emails, URLs, or text inside sticky notes.\n - Preserve their content, color, size, position, and metadata.\n\n4. DO NOT MODIFY:\n - Node id, name, type, typeVersion\n - Node positions\n - Connections\n - Any n8n expression syntax (for example, expressions that begin with \"=\" and use n8n-style placeholders).\n\n5. REPLACE secret-like values with placeholders:\n - clientId \u2192 \"YOUR_CLIENT_ID_HERE\"\n - clientSecret \u2192 \"YOUR_CLIENT_SECRET_HERE\"\n - API keys / tokens \u2192 \"YOUR_API_KEY_HERE\", \"YOUR_BEARER_TOKEN\", or \"REDACTED_TOKEN\"\n - Email addresses \u2192 \"YOUR_EMAIL@EXAMPLE.COM\"\n - Public document URLs \u2192 \"REPLACE_WITH_YOUR_URL\"\n\n6. SPECIAL RULES:\n - Google Translate (service account): remove credentials; keep authentication field; no other changes.\n - ConvertAPI URLs: replace Secret=... with Secret=YOUR_CONVERTAPI_SECRET or append if missing.\n - Gmail OAuth2 nodes: remove Gmail credentials object.\n - JavaScript nodes: only replace literal strings containing secrets; do not change code structure.\n\n7. The final output must be:\n - A single valid JSON object\n - Sanitized according to all rules\n - Directly importable into n8n.\n\nIf the workflow is very large, you may truncate fields like systemMessage or long descriptions only if needed to stay within the model\u2019s context limit, but keep structure and logic intact.\n"
}
]
},
"builtInTools": {}
},
"typeVersion": 2
},
{
"id": "ddbf4a83-92b9-41a1-9631-a674ff968a03",
"name": "Format Sanitized Workflow (JS)",
"type": "n8n-nodes-base.code",
"position": [
1712,
320
],
"parameters": {
"jsCode": "// 1) Get the text returned by the OpenAI node (Message a model \u2013 Sanitize)\nlet raw = $json.output?.[0]?.content?.[0]?.text;\n\nif (typeof raw !== 'string') {\n raw = JSON.stringify(raw ?? {});\n}\n\n// 2) Parse sanitized workflow JSON\nconst sanitized = JSON.parse(raw);\n\n// 3) Also create a pretty JSON string for file export\nconst sanitizedText = JSON.stringify(sanitized, null, 2);\n\n// 4) Return both\nreturn [{\n json: {\n sanitizedWorkflowJson: sanitized,\n sanitizedText\n }\n}];"
},
"typeVersion": 2
},
{
"id": "b53e5930-b0b2-44e9-b3b6-bde233add0c8",
"name": "Combine Original & Sanitized JSON",
"type": "n8n-nodes-base.merge",
"position": [
1952,
448
],
"parameters": {
"mode": "combine",
"options": {
"includeUnpaired": true
},
"combineBy": "combineByPosition"
},
"typeVersion": 3.2
},
{
"id": "e798efb9-1b3a-49bd-8910-dd0dc7070938",
"name": "Generate Workflow Change log (AI)",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
2176,
384
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4.1-mini",
"cachedResultName": "GPT-4.1-MINI"
},
"options": {},
"responses": {
"values": [
{
"content": "=Compare the following two n8n workflow JSONs and produce a structured change log.\n\nORIGINAL WORKFLOW:\n{{ JSON.stringify($json.originalWorkflowJson) }}\n\nSANITIZED WORKFLOW:\n{{ JSON.stringify($json.sanitizedWorkflowJson) }}\n\nReturn:\n\n1. Node-by-node list of changes\n2. Placeholders inserted\n3. Summary of removed secrets\n"
},
{
"role": "system",
"content": "=Output format rules (very important):\n\nReturn the change log as HTML, not Markdown.\n\nDo not wrap the result in <html> or <body> tags \u2013 just the inner HTML.\n\nUse this style for the main section headings (\u201c1. Node-by-node\u2026\u201d, \u201c2. Placeholders\u2026\u201d, \u201c3. Summary\u2026\u201d):\n\n<h2 style=\"font-size:18px;font-weight:bold;text-decoration:underline;color:#0052CC;margin-top:16px;margin-bottom:8px;\">\n 1. Node-by-node list of changes\n</h2>\n(18px \u2248 about 3pt bigger than normal body text.)\n\nFor node names inside section 1, use:\n\n<h3 style=\"font-size:15px;font-weight:bold;color:#0052CC;margin-top:12px;margin-bottom:4px;\">\n Node: When chat message received\n</h3>\nUse <ul><li>...</li></ul> for bullet lists.\nKeep the same wording you used before; just change the formatting.\nAt the end, include the overall summary in a <p> with bold text:\n\n<p><strong>Overall, the sanitized workflow preserves all functional logic but removes any secret credentials, webhook IDs, and user-specific metadata, replacing them with placeholders for user customization and security.</strong></p>\n\nDo not escape the HTML (no < / >); it must be real HTML tags.\n"
}
]
},
"builtInTools": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 2
},
{
"id": "d62264be-8ad5-4072-b075-70b8cf525328",
"name": "Assemble Email Content & Attachment",
"type": "n8n-nodes-base.merge",
"position": [
2592,
496
],
"parameters": {
"mode": "combine",
"options": {
"includeUnpaired": true
},
"combineBy": "combineByPosition"
},
"typeVersion": 3.2
},
{
"id": "98e5bb45-4442-4312-8855-bbebbc68e76b",
"name": "Create Sanitized JSON File",
"type": "n8n-nodes-base.convertToFile",
"position": [
2240,
688
],
"parameters": {
"options": {
"fileName": "=sanitized_workflow.json"
},
"operation": "toText",
"sourceProperty": "=sanitizedText",
"binaryPropertyName": "sanitizedFile"
},
"typeVersion": 1.1
},
{
"id": "cbf01f93-b29c-4564-8549-1cb9f552df5f",
"name": "Email Sanitized Workflow + Report",
"type": "n8n-nodes-base.gmail",
"position": [
2800,
496
],
"parameters": {
"sendTo": "={{ $node[\"Upload Workflow Json\"].json[\"Mailid\"] }}",
"message": "=<div style=\"font-family:system-ui,-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;font-size:13px;line-height:1.5;\">\n {{ $node[\"Generate Workflow Change log (AI)\"].json.output[0].content[0].text }}\n <hr style=\"margin-top:24px;border:none;border-top:1px solid #ddd;\" />\n <p style=\"font-size:11px;color:#888;\">\n This email was sent automatically by n8n.\n </p>\n</div>\n",
"options": {
"attachmentsUi": {
"attachmentsBinary": [
{
"property": "sanitizedFile"
}
]
},
"appendAttribution": false
},
"subject": "={{ 'Sanitized n8n workflow JSON: ' + $node[\"Upload Workflow Json\"].binary[\"Upload_JSON_file\"].fileName }}"
},
"typeVersion": 2.1
},
{
"id": "c2b1ee94-da1f-4174-946c-d8ade6539903",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
528,
224
],
"parameters": {
"color": 6,
"width": 256,
"height": 432,
"content": "## Input Collection\n\nForm node collects MailId and uploaded JSON."
},
"typeVersion": 1
},
{
"id": "594882b1-dd4a-4b5b-a0c5-97cc5a25d360",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
800,
224
],
"parameters": {
"color": 3,
"width": 528,
"height": 432,
"content": "## Extract + Prepare Original Workflow\n\nExtracts uploaded file into structured JSON.\nWraps parsed JSON into originalWorkflowJson.\nStringifies and prepares payload for sanitization."
},
"typeVersion": 1
},
{
"id": "ba023e6d-c16f-4e75-8a4f-a4ed43ebc4ff",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1344,
240
],
"parameters": {
"color": 4,
"width": 544,
"height": 416,
"content": "## AI Sanitization Engine\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nRemoves secrets & metadata while preserving structure. Outputs valid JSON.\nParses sanitized JSON into sanitizedWorkflowJson"
},
"typeVersion": 1
},
{
"id": "a776b7ec-b5e5-4151-9620-4c8b653ff743",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1904,
224
],
"parameters": {
"color": 5,
"width": 592,
"height": 416,
"content": "## Comparison Engine (Original vs Sanitized)\n\nMerge node pairs both versions for comparison.\nProduces Markdown/HTML-ready diff report.\n"
},
"typeVersion": 1
},
{
"id": "d70b3d7f-7fed-47ca-a306-b2be3a73d844",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
1904,
656
],
"parameters": {
"color": 2,
"width": 592,
"height": 256,
"content": "## Create Sanitized JSON File\n\nConverts sanitized JSON string into \nsanitized_workflow.json."
},
"typeVersion": 1
},
{
"id": "98dce538-0752-4d24-8448-eb5a6698a45c",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
2512,
224
],
"parameters": {
"color": 6,
"width": 480,
"height": 688,
"content": "## Assemble Email & Send\n\nMerges report and file.\nGmail node sends HTML email and attachment."
},
"typeVersion": 1
},
{
"id": "1d9f976d-4a6c-4d6d-93c4-af112343cfe7",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
1120,
80
],
"parameters": {
"width": 1056,
"height": 96,
"content": "\n\n ## Generate Sanitized workflow JSON file using AI Formatter + Merge nodes and email report"
},
"typeVersion": 1
},
{
"id": "8cd41002-88ec-485f-baf9-aba81808fb3b",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
0,
0
],
"parameters": {
"width": 512,
"height": 944,
"content": "# Try Out\n\n## Overview\n\nThis workflow sanitizes any uploaded n8n workflow JSON by removing credentials, webhook IDs, tokens, and sensitive metadata. It generates a clean, secure version, produces a detailed change-log, and emails both the sanitized file and report to the user.\n\n## How it Works\n\n\u2022\tUser uploads a workflow JSON + email.\n\u2022\tJSON is parsed, normalized, and pre-processed.\n\u2022\tAI removes secrets, credentials, webhook IDs, and sensitive metadata.\n\u2022\tOriginal vs sanitized versions are compared to create a structured change-log.\n\u2022\tSanitized JSON file is generated.\n\u2022\tEmail with formatted report + attachment is sent to the user.\n\n\n## Use Cases\n\n\u2022\tSharing workflows without exposing secrets\n\u2022\tPublishing workflows to the community securely\n\u2022\tAuditing workflow configurations\n\u2022\tInternal compliance and security checks\n\n\n## Setup Requirements\n\n\u2022\tOpenAI API credentials\n\u2022\tEmail credentials (Gmail or SMTP)\n\u2022\tJSON file exported from n8n\n\n\n## Need Help?\n\nJoin n8n Discord https://discord.com/invite/n8n\n or Community Forum https://community.n8n.io/\nREADME file available at https://bit.ly/GeneratesanitizedJSONfile"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "",
"connections": {
"Extract JSON content": {
"main": [
[
{
"node": "Prepare Original Workflow Structure",
"type": "main",
"index": 0
}
]
]
},
"Upload Workflow Json": {
"main": [
[
{
"node": "Extract JSON content",
"type": "main",
"index": 0
}
]
]
},
"AI Sanitize Workflow JSON": {
"main": [
[
{
"node": "Format Sanitized Workflow (JS)",
"type": "main",
"index": 0
}
]
]
},
"Create Sanitized JSON File": {
"main": [
[
{
"node": "Assemble Email Content & Attachment",
"type": "main",
"index": 1
}
]
]
},
"Format Original Workflow(JS)": {
"main": [
[
{
"node": "AI Sanitize Workflow JSON",
"type": "main",
"index": 0
},
{
"node": "Combine Original & Sanitized JSON",
"type": "main",
"index": 1
}
]
]
},
"Format Sanitized Workflow (JS)": {
"main": [
[
{
"node": "Combine Original & Sanitized JSON",
"type": "main",
"index": 0
}
]
]
},
"Generate Workflow Change log (AI)": {
"main": [
[
{
"node": "Assemble Email Content & Attachment",
"type": "main",
"index": 0
}
]
]
},
"Combine Original & Sanitized JSON": {
"main": [
[
{
"node": "Generate Workflow Change log (AI)",
"type": "main",
"index": 0
},
{
"node": "Create Sanitized JSON File",
"type": "main",
"index": 0
}
]
]
},
"Assemble Email Content & Attachment": {
"main": [
[
{
"node": "Email Sanitized Workflow + Report",
"type": "main",
"index": 0
}
]
]
},
"Prepare Original Workflow Structure": {
"main": [
[
{
"node": "Format Original Workflow(JS)",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
openAiApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow sanitizes any uploaded n8n workflow JSON by removing credentials, webhook IDs, and sensitive metadata. Using AI and structured comparison, it generates a clean, secure workflow version, creates a downloadable sanitized file, and emails a detailed change-log report…
Source: https://n8n.io/workflows/11065/ — 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.
What it is An automated LinkedIn content system that takes a simple form (idea + optional file), generates LinkedIn posts with OpenAI, stores them in Notion, builds Google Slides carousels, and auto-p
Automatically analyze your full sports performance evolution using your Strava activities, enriched with AI insights and delivered directly to your email — all powered by your own n8n instance.
This template is designed for content creators, podcasters, businesses, and researchers who need to transcribe long audio recordings that exceed OpenAI Whisper's 25 MB file size limit (~20 minutes of
An n8n-based automation that generates client proposals from a form, lets you review everything in one place, and sends the proposal only when you approve it.
Automatically gather hundreds of real customer reviews from five major platforms in one run using Thordata API and Proxy — Trustpilot, Capterra, Chrome Web Store, TrustRadius, and Product Hunt — then