This workflow corresponds to n8n.io template #8420 — we link there as the canonical source.
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": "120c98f6-17fd-46e7-b449-539cf0e6eccd",
"name": "Low Quality Endpoint Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
4500,
-300
],
"parameters": {
"width": 400,
"height": 440,
"content": "## \ud83d\udeab Low Quality / Drop\n\n**When:** Confidence < 0.4 or unclear image\n\n**Response:**\n- Tell user file isn't a floorplan\n- Suggest uploading blueprint/CAD\n- List acceptable formats (JPG, PNG, PDF)\n\n**User sees:** \"Unable to Process Your Floorplan\""
},
"typeVersion": 1
},
{
"id": "fa9dc8cf-6eaa-4a65-b6d0-27d8da7b1a59",
"name": "Manual Review Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
4820,
520
],
"parameters": {
"color": 3,
"width": 400,
"height": 480,
"content": "## \u26a0\ufe0f Manual Review Needed\n\n**When:** Confidence 0.4-0.85 (uncertain)\n\n**Response:**\n- File needs human check\n- Promise 2-hour turnaround\n- Set expectation for email follow-up\n\n**User sees:** \"Manual Review Required\""
},
"typeVersion": 1
},
{
"id": "65ded5cd-8648-4eaa-a230-b5eb562df429",
"name": "Continue to JIG Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
5140,
20
],
"parameters": {
"color": 4,
"width": 380,
"height": 460,
"content": "## \u2705 Continue to Step 2\n\n**When:** Confidence \u2265 0.85 (from text analysis)\n\n**Response:**\n- Confirm successful validation\n- Explain next steps (OCR/measurement)\n- Set 30-60 second expectation\n\n**User sees:** \"Floorplan Accepted!\"\n\n*Continues to Jigsaw OCR*"
},
"typeVersion": 1
},
{
"id": "0016e3f6-0552-4cee-b59a-445129a3236a",
"name": "Classification Success Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
3280,
-520
],
"parameters": {
"color": 5,
"width": 580,
"height": 540,
"content": "## Image Classification\n\n**When:** Image files with high AI confidence\n\n**Response:**\n- Premium quality detected\n- Instant processing message\n- List what's being calculated\n\n**User sees:** \"Perfect Quality Floorplan\"\n\n*Fast track to measurements*"
},
"typeVersion": 1
},
{
"id": "c96745c9-5646-423a-98e9-239df792662e",
"name": "Flow Summary Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
2340,
-340
],
"parameters": {
"color": 6,
"width": 400,
"height": 360,
"content": "## \ud83d\udcca Flow Summary\n\n**PDF Path:**\nExtract text \u2192 Score confidence \u2192 Route by threshold\n\n**Image Path:**\nDirect to AI classification \u2192 Route by result\n\n**Thresholds:**\n- < 40%: Not a floorplan\n- 40-85%: Manual review\n- \u2265 85%: Auto-process\n\n**Goal:** Filter bad uploads early, save API costs"
},
"typeVersion": 1
},
{
"id": "e0bcf1b8-ee8e-4a88-afe8-23b9a7b7c4ac",
"name": "File Limit Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
3700,
480
],
"parameters": {
"color": 2,
"width": 440,
"height": 460,
"content": "## \ud83d\udccf File Size/Pages Limit\n\n**When:**\n- File > 10MB\n- PDF > 20 pages\n\n**Response:**\n- Explain size limits\n- Ask to split multi\u2011floor plans\n- Suggest extracting relevant pages\n\n**User sees:** \"File Too Large\""
},
"typeVersion": 1
},
{
"id": "67704d28-dbab-4e48-b0b6-1643e0dadc7e",
"name": "\ud83d\udcd8 Workflow Documentation",
"type": "n8n-nodes-base.stickyNote",
"position": [
1620,
-340
],
"parameters": {
"width": 600,
"height": 1560,
"content": "# \ud83c\udfe0 Floorplan Classifier & Measurement Extractor \n\n## \u2705 What This Workflow Does \n\nAutomatically validates uploaded files (**PDFs or images**) to check if they are genuine floorplans. It rejects non\u2011floorplans early, and prepares valid files for **room measurement & analysis**. \n\nThe workflow has **two phases**: \n1. **Classification (Step 1):** Smart filters & classifiers decide if the upload is usable. \n2. **Calculation (Step 2):** OCR + AI extract structured room measurements (area + wall surfaces) and compile results. \n\n---\n\n### Supported File Types \n- **PDFs** \u2192 text is extracted for keyword/measurement checks, then passed to AI. \n- **Images (JPG, PNG, etc.)** \u2192 sent directly to the classifier (can\u2019t extract metadata text). \n\n---\n\n### Quality Filtering (Step 1) \n1. **Heuristic checks** \u2192 detects floorplan indicators: \n - Room names (living room, keuken, slaapkamer, etc.) \n - Measurements (m\u00b2, mm) \n - Technical symbols (e.g., WCD, TH, WP). \n2. **AI classification (JigsawStack)** \u2192 robustly decides floorplan vs. not. \n\n---\n\n### Confidence Routing (Step 1) \n- **< 40% confidence** \u2192 \u274c Rejected (not a floorplan). \n- **40\u201385% confidence** \u2192 \u26a0\ufe0f Unclear \u2192 ask for better upload/manual review. \n- **> 85% confidence** \u2192 \u2705 Accepted floorplan \u2192 sent to **Measurement Extraction (Step 2)**. \n\n---\n\n### Measurement Extraction (Paid version ONLY) \n---\n\n## \u2692 Requirements \n- **JigsawStack API key** \u2192 File storage + classification \n- **Mistral Cloud API key** \u2192 OCR measurement extraction \n- **n8n instance** \u2192 Self\u2011hosted or Cloud \n- **Webhook endpoint** \u2192 for uploads & responses \n\n---\n\n## \ud83d\udd27 Customization \n- Adjust **heuristic rules** (keywords/symbols) to match your market. \n- Change **confidence thresholds** (strict vs. lenient filtering). \n- Set **wall height** or fallback ratio for wall area calculations. \n- Choose your OCR/AI provider (Mistral, AWS Textract, Azure Vision, etc.). \n- Extend workflows to **save results to DB, Notion, Slack, CRM**. \n\n---\n\n## \u26a0\ufe0f Notes \n- Never hardcode API keys \u2192 use **n8n credential manager**. \n- All nodes are **renamed by purpose** (easy to follow). \n- Sticky Notes document both phases clearly. \n- Designed as **plug\u2011and\u2011play end\u2011to\u2011end pipeline** for fast onboarding. \n"
},
"typeVersion": 1
},
{
"id": "30aee9c1-02f8-40b4-b431-8bc122bb08d6",
"name": "Check \u2013 GDPR Consent",
"type": "n8n-nodes-base.if",
"position": [
2560,
80
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "or",
"conditions": [
{
"id": "1e3d1d01-1b9e-45b5-9616-93335d2bc270",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.body.GDPR_check || $json.body.GDPR_check2}}",
"rightValue": ""
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.2
},
{
"id": "2e9797b2-9ce9-4628-b049-95b28bd43e4e",
"name": "Webhook \u2013 Receive Upload",
"type": "n8n-nodes-base.webhook",
"position": [
2320,
80
],
"parameters": {
"path": "fp-mvp",
"options": {
"ignoreBots": true,
"allowedOrigins": "*"
},
"httpMethod": "POST",
"responseMode": "responseNode",
"authentication": "basicAuth"
},
"credentials": {
"httpBasicAuth": {
"name": "<your credential>"
}
},
"typeVersion": 2
},
{
"id": "c2de825d-fd9b-4e42-a43c-ff570ea90068",
"name": "Respond \u2013 Consent Required",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
2860,
300
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={\n \"thankYouMessage\": \"<div style='text-align:center; padding:40px 20px; font-family:system-ui;'><h2 style='color:#FF5252;'>\u26a0\ufe0f Consent Required</h2><p>We need your permission to process your floorplan. Please check the privacy consent box and try again.</p><p style='font-size:12px; color:#999; margin-top:20px;'>Your data is deleted within 10 minutes \u2022 GDPR compliant</p></div>\"\n}"
},
"typeVersion": 1.1
},
{
"id": "d48a571b-0dac-48b2-b60e-d8485ad9f980",
"name": "Process \u2013 Multiple File Uploads",
"type": "n8n-nodes-base.code",
"position": [
2820,
60
],
"parameters": {
"jsCode": "const results = [];\n\nfor (const item of items) {\n if (!item.binary) continue;\n\n for (const [key, value] of Object.entries(item.binary)) {\n results.push({\n json: {\n fileKey: key,\n fileName: value.fileName,\n mimeType: value.mimeType,\n fileExtension: value.fileExtension,\n fileSize: value.fileSize\n },\n binary: {\n [key]: value // behoud originele binary key naam!\n }\n });\n }\n}\n\nreturn results;"
},
"typeVersion": 2
},
{
"id": "cb575124-245b-4d34-aa23-1d04fddfeea3",
"name": "Check \u2013 File Type (PDF/Image)",
"type": "n8n-nodes-base.if",
"position": [
3040,
60
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "or",
"conditions": [
{
"id": "837a00af-0c9d-4dde-a184-4d4c2d918005",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ [\"png\",\"jpg\",\"jpeg\",\"bmp\",\"tiff\",\"webp\",\"gif\"]\n .includes($json.fileExtension.toLowerCase()) }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "28353d44-0328-4407-b942-0a87b44c244f",
"name": "Extract \u2013 PDF Metadata/Text",
"type": "n8n-nodes-base.extractFromFile",
"position": [
3300,
80
],
"parameters": {
"options": {
"keepSource": "both"
},
"operation": "pdf",
"binaryPropertyName": "={{ $json.fileKey }}"
},
"typeVersion": 1
},
{
"id": "4023d030-c089-413a-864d-7a467ce63232",
"name": "Check \u2013 File Size & Pages",
"type": "n8n-nodes-base.if",
"position": [
3500,
80
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "d94826b9-a2fe-4af2-9c76-0d76fdb0c0d8",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ \n (() => {\n const raw = $json.fileSize || \"\";\n const val = parseFloat(raw);\n if (raw.toLowerCase().includes(\"mb\")) return val < 10;\n if (raw.toLowerCase().includes(\"kb\")) return val < 10000; // 10 MB = 10,000 KB\n if (raw.toLowerCase().includes(\"bytes\")) return val < 10485760; // 10 MB in bytes\n return false; // if unknown format\n })()\n}}",
"rightValue": ""
},
{
"id": "b58f8207-18c9-4e0a-a52d-6a3151f6ee57",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{$json.fileExtension.toLowerCase() !== \"pdf\"\n ? true \n : ($json.numpages && $json.numpages < 10)}}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "25d2a512-494a-4552-a6c6-e68714fd522d",
"name": "Analyze \u2013 Confidence Score (Heuristics)",
"type": "n8n-nodes-base.code",
"position": [
3740,
60
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// --- SAFER INPUT HANDLING ---\nconst text = ($json.text || \"\").toLowerCase();\nconst numpages = $json.numpages || 1;\n\nlet score = 0;\nlet reasons = []; \n\n// --- KEYWORD LISTS ---\nconst nlSpaces = [\"woonkamer\", \"keuken\", \"slaapkamer\", \"badkamer\", \"overloop\", \"entree\", \"hal\", \"toilet\", \"berging\", \"techniek\", \"meterkast\", \"mk\"];\nconst enSpaces = [\"living room\", \"kitchen\", \"bedroom\", \"bathroom\", \"landing\", \"entrance\", \"hall\", \"toilet\", \"storage\", \"utility room\"];\nconst floorWords = [\"verdieping\", \"begane grond\", \"zolder\", \"kelder\", \"vliering\", \"doorsnede\", \"gevel\", \"plattegrond\"];\nconst enFloorWords = [\"floor\", \"ground floor\", \"attic\", \"basement\", \"cross-section\", \"facade\", \"floor plan\"];\nconst symbols = [\"wcd\", \"th\", \"wp\", \"v.v.\", \"wm\", \"wd\", \"wtw\", \"pv\", \"rad.\", \"rm\", \"gr\"];\nconst projectWords = [\"bouwnummer\", \"opdrachtgever\", \"project\", \"schaal\", \"datum\", \"bladnummer\", \"formaat\"];\n\n// --- CHECKS ---\n// 1. Spaces\nconst foundNlSpaces = nlSpaces.filter(w => text.includes(w));\nconst foundEnSpaces = enSpaces.filter(w => text.includes(w));\nif ((foundNlSpaces.length + foundEnSpaces.length) >= 3) {\n score += 0.35;\n reasons.push(`Found ${foundNlSpaces.length + foundEnSpaces.length} room names`);\n}\n\n// 2. m\u00b2 matches\nconst m2Matches = text.match(/\\d+(?:[.,]\\d+)?\\s*m(?:\u00b2|2)/g) || [];\nif (m2Matches.length >= 3) {\n score += 0.25;\n reasons.push(`Found ${m2Matches.length} m\u00b2 measurements`);\n}\n\n// 3. mm matches (dimensions)\nconst mmMatches = text.match(/\\d{3,}\\s*mm/g) || [];\nif (mmMatches.length >= 3) {\n score += 0.15;\n reasons.push(`Found ${mmMatches.length} mm measurements`);\n}\n\n// 4. Symbols\nconst foundSymbols = symbols.filter(s => text.includes(s.toLowerCase()));\nif (foundSymbols.length >= 3) {\n score += 0.15;\n reasons.push(`Found ${foundSymbols.length} technical symbols`);\n}\n\n// 5. Floor/plan words\nconst foundFloors = [...floorWords, ...enFloorWords].filter(w => text.includes(w));\nif (foundFloors.length >= 2) {\n score += 0.10;\n reasons.push(`Found ${foundFloors.length} floor/drawing parts`);\n}\n\n// 6. Project words\nconst foundProjectWords = projectWords.filter(w => text.includes(w));\nif (foundProjectWords.length >= 3) {\n score += 0.10;\n reasons.push(`Found ${foundProjectWords.length} project info words`);\n}\n\n// --- NORMALIZE SCORE ---\nif (score > 1) score = 1;\n\n// \u2705 Return one item with JSON + preserve binary\nreturn {\n json: {\n ...$json,\n confidence: parseFloat(score.toFixed(2)),\n analysis: {\n reasons,\n foundNlSpaces,\n foundEnSpaces,\n m2Matches,\n mmMatches,\n foundSymbols,\n foundFloors,\n foundProjectWords,\n pages: numpages\n }\n },\n binary: item.binary // pass binary unchanged\n};"
},
"typeVersion": 2
},
{
"id": "87868e3c-e4eb-47ff-acf0-bb4072d38bbc",
"name": "Route \u2013 Confidence Levels",
"type": "n8n-nodes-base.switch",
"position": [
4020,
0
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "very_likely_not_floorplan",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"operator": {
"type": "number",
"operation": "lt"
},
"leftValue": "={{ $json.confidence }}",
"rightValue": 0.2
}
]
},
"renameOutput": true
},
{
"outputKey": "likely_not_floorplan",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"operator": {
"type": "number",
"operation": "lt"
},
"leftValue": "={{ $json.confidence }}",
"rightValue": 0.4
},
{
"operator": {
"type": "number",
"operation": "gte"
},
"leftValue": "={{ $json.confidence }}",
"rightValue": 0.2
}
]
},
"renameOutput": true
},
{
"outputKey": "uncertain_low_confidence",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"operator": {
"type": "number",
"operation": "lt"
},
"leftValue": "={{ $json.confidence }}",
"rightValue": 0.6
},
{
"operator": {
"type": "number",
"operation": "gte"
},
"leftValue": "={{ $json.confidence }}",
"rightValue": 0.4
}
]
},
"renameOutput": true
},
{
"outputKey": "=uncertain_high_confidence",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"operator": {
"type": "number",
"operation": "lt"
},
"leftValue": "={{ $json.confidence }}",
"rightValue": 0.85
},
{
"operator": {
"type": "number",
"operation": "gte"
},
"leftValue": "={{ $json.confidence }}",
"rightValue": 0.6
}
]
},
"renameOutput": true
},
{
"outputKey": "very_likely_floorplan",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"operator": {
"type": "number",
"operation": "gte"
},
"leftValue": "={{ $json.confidence }}",
"rightValue": 0.85
}
]
},
"renameOutput": true
}
]
},
"options": {
"fallbackOutput": "extra",
"allMatchingOutputs": true,
"renameFallbackOutput": "needs_review"
}
},
"typeVersion": 3.2
},
{
"id": "0a0bf7f3-0eb5-457a-b445-48111e7ac7d3",
"name": "Respond \u2013 Low Quality/Drop",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
4640,
-20
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{\n {\n \"thankYouMessage\":\n $json.confidence && $json.confidence[0] < 0.4\n ? \"\ud83d\udeab Unable to Process Your Floorplan. The image quality is too low or unclear. Please upload an architectural blueprint or CAD drawing instead. Accepted formats: JPG, PNG, PDF.\"\n : (\n $json.predictions[0] === \"floorplan\"\n ? \"SUCCESS: Floorplan detected! Processing your measurements now. This will take 15-30 seconds.\"\n : \"ERROR: Not a floorplan detected. Please upload an architectural blueprint or technical floor layout instead.\"\n )\n }\n}}"
},
"typeVersion": 1.1
},
{
"id": "cee2d67e-f07c-49b8-9018-e0753ff16d76",
"name": "Classify \u2013 Image Files",
"type": "n8n-nodes-base.httpRequest",
"position": [
3560,
-200
],
"parameters": {
"url": "https://api.jigsawstack.com/v1/classification",
"method": "POST",
"options": {},
"jsonBody": "={\n \"dataset\": [\n {\n \"type\": \"image\",\n \"value\": \"{{ $json.temp_public_url }}\"\n }\n ],\n \"labels\": [\n {\n \"type\": \"text\",\n \"value\": \"floorplan\"\n },\n {\n \"type\": \"text\",\n \"value\": \"not floorplan\"\n }\n ]\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"headerParameters": {
"parameters": [
{}
]
}
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
},
{
"id": "14201ed6-6613-4bfc-b8bd-d7434507036c",
"name": "Classify \u2013 PDF Text",
"type": "n8n-nodes-base.httpRequest",
"position": [
4880,
820
],
"parameters": {
"url": "https://api.jigsawstack.com/v1/classification",
"method": "POST",
"options": {},
"jsonBody": "={\n \"dataset\": [\n {\n \"type\": \"text\",\n \"value\": {{ JSON.stringify ($json.text) }}\n }\n ],\n \"labels\": [\n {\n \"type\": \"text\",\n \"value\": \"floorplan\"\n },\n {\n \"type\": \"text\",\n \"value\": \"not floorplan\"\n }\n ]\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
},
{
"id": "13aa840e-eb2c-42c5-a344-a1aab65d89d2",
"name": "Respond \u2013 Classification Result (Image)",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
3720,
-200
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{\n {\n \"thankYouMessage\": $json.predictions[0] === \"floorplan\" \n ? \"SUCCESS: Floorplan detected! Processing your measurements now. This will take 15-30 seconds.\"\n : \"ERROR: Not a floorplan detected. Please upload an architectural blueprint or technical floor layout instead.\"\n }\n}}"
},
"typeVersion": 1.1
},
{
"id": "988144cc-e416-440c-8fb6-2b445c0b398b",
"name": "Respond \u2013 Classification Result (PDF)",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
5040,
820
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{\n {\n \"thankYouMessage\": $json.predictions[0] === \"floorplan\" \n ? \"SUCCESS: Floorplan detected! Processing your measurements now. This will take 15-30 seconds.\"\n : \"ERROR: Not a floorplan detected. Please upload an architectural blueprint or technical floor layout instead.\"\n }\n}}"
},
"typeVersion": 1.1
},
{
"id": "38a92798-d6c2-4d46-b069-069c46ee6de4",
"name": "Respond \u2013 File Too Large",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
3740,
780
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ {\n \"thankYouMessage\": \"\ud83d\udccf File Too Large. The uploaded file exceeds our limits (max 10MB or PDFs with more than 20 pages). Please split multi\u2011floor plans into separate files or extract only the relevant pages, then try again.\"\n} }}"
},
"typeVersion": 1.1
},
{
"id": "2c4d4e53-59dd-4b47-8213-e86ff873d874",
"name": "Upload \u2013 JigsawStack (Storage)",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueErrorOutput",
"maxTries": 2,
"position": [
3340,
-180
],
"parameters": {
"url": "https://api.jigsawstack.com/v1/store/file",
"method": "POST",
"options": {},
"sendBody": true,
"sendQuery": true,
"contentType": "binaryData",
"sendHeaders": true,
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"queryParameters": {
"parameters": [
{
"name": "key",
"value": "={{ $json.fileName }}"
},
{
"name": "overwrite",
"value": "true"
},
{
"name": "temp_public_url",
"value": "true"
}
]
},
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "={{ $json.mimeType }}"
}
]
},
"inputDataFieldName": "={{ $json.fileKey }}"
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 4.2,
"waitBetweenTries": 3000
},
{
"id": "0b6380ad-d3e7-499d-a097-f5cde6031129",
"name": "No Operation, do nothing",
"type": "n8n-nodes-base.noOp",
"position": [
5260,
340
],
"parameters": {},
"typeVersion": 1
}
],
"connections": {
"Classify \u2013 PDF Text": {
"main": [
[
{
"node": "Respond \u2013 Classification Result (PDF)",
"type": "main",
"index": 0
}
]
]
},
"Check \u2013 GDPR Consent": {
"main": [
[
{
"node": "Process \u2013 Multiple File Uploads",
"type": "main",
"index": 0
}
],
[
{
"node": "Respond \u2013 Consent Required",
"type": "main",
"index": 0
}
]
]
},
"Classify \u2013 Image Files": {
"main": [
[
{
"node": "Respond \u2013 Classification Result (Image)",
"type": "main",
"index": 0
}
]
]
},
"No Operation, do nothing": {
"main": [
[]
]
},
"Webhook \u2013 Receive Upload": {
"main": [
[
{
"node": "Check \u2013 GDPR Consent",
"type": "main",
"index": 0
}
]
]
},
"Check \u2013 File Size & Pages": {
"main": [
[
{
"node": "Analyze \u2013 Confidence Score (Heuristics)",
"type": "main",
"index": 0
}
],
[
{
"node": "Respond \u2013 File Too Large",
"type": "main",
"index": 0
}
]
]
},
"Route \u2013 Confidence Levels": {
"main": [
[
{
"node": "Respond \u2013 Low Quality/Drop",
"type": "main",
"index": 0
}
],
[
{
"node": "Respond \u2013 Low Quality/Drop",
"type": "main",
"index": 0
}
],
[
{
"node": "Classify \u2013 PDF Text",
"type": "main",
"index": 0
}
],
[
{
"node": "Classify \u2013 PDF Text",
"type": "main",
"index": 0
}
],
[
{
"node": "No Operation, do nothing",
"type": "main",
"index": 0
}
]
]
},
"Extract \u2013 PDF Metadata/Text": {
"main": [
[
{
"node": "Check \u2013 File Size & Pages",
"type": "main",
"index": 0
}
]
]
},
"Check \u2013 File Type (PDF/Image)": {
"main": [
[
{
"node": "Upload \u2013 JigsawStack (Storage)",
"type": "main",
"index": 0
}
],
[
{
"node": "Extract \u2013 PDF Metadata/Text",
"type": "main",
"index": 0
}
]
]
},
"Upload \u2013 JigsawStack (Storage)": {
"main": [
[
{
"node": "Classify \u2013 Image Files",
"type": "main",
"index": 0
}
]
]
},
"Process \u2013 Multiple File Uploads": {
"main": [
[
{
"node": "Check \u2013 File Type (PDF/Image)",
"type": "main",
"index": 0
}
]
]
},
"Analyze \u2013 Confidence Score (Heuristics)": {
"main": [
[
{
"node": "Route \u2013 Confidence Levels",
"type": "main",
"index": 0
}
]
]
},
"Respond \u2013 Classification Result (Image)": {
"main": [
[]
]
}
}
}
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.
httpBasicAuthhttpHeaderAuth
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
<section> <h2>🌊 What it Does</h2> <p> This workflow <strong>automatically classifies uploaded files</strong> (PDFs or images) as <span>floorplans</span> or <span>non‑floorplans</span>. It filters out junk files, then analyzes valid floorplans to extract <em>room sizes</em> and…
Source: https://n8n.io/workflows/8420/ — 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.
This n8n workflow provides a ready-to-use API endpoint for extracting structured data from images. It processes an image URL using an AI-powered OCR model and returns the extracted details in a struct
AI Keyword & Entity Extractor (Ollama). Uses httpRequest. Webhook trigger; 7 nodes.
This workflow automates the process of extracting images from uploaded documents in Google Drive using the VLM Run Execute Agent, then downloads and saves those extracted images into a designated Driv
Who is this for? Event organizers, conference planners, and marketing teams fighting registration drop-off who want 4-field forms with LinkedIn-level attendee intelligence. What problem is this workfl
Use Case: Analyze images with multiple subjects. In this use case I have a bookshelf and am extracting and verifying book titles/authors from a bookshelf photo.