If you build or sell manufacturing execution systems (MES), quality management SaaS (QMS), supply chain visibility platforms, or industrial IoT products, your clients have a compliance problem you can solve.
ISO 9001:2015, IATF 16949:2016, AS9100 Rev D, FDA QMSR (21 CFR Part 820), and OSHA PSM all require quality and safety records that are permanent and retrievable. Zapier logs tasks for 30 days. After that, the audit trail is gone.
That's not just a bad look. It's a documented nonconformance.
Self-hosted n8n fixes this. It runs inside your client's own network. Every execution is permanently logged. No data routes through third-party cloud servers. And at IIoT scale — millions of machine health checks per month — the cost difference is extreme.
Here are 5 automations built for ManufacturingTech SaaS vendors, with full import-ready JSON.
Why ManufacturingTech SaaS Vendors Deploy n8n On-Premise
Three compliance requirements that Zapier cannot satisfy:
ISO 9001:2015 §7.5 — Documented information must remain "available and suitable for use" for the product's lifetime plus regulatory retention periods. Zapier's 30-day task log deletes quality records automatically. That's a corrective action request waiting to happen during a CB surveillance audit.
IATF 16949:2016 §10.2.3-4 — Defect events and corrective actions must be traceable to the part level for automotive OEM supply chains. If the automation runs through Zapier, the traceability chain has a gap. Ford, GM, and Stellantis customer-specific requirements (CSRs) make this explicit.
OSHA 1910.119 (PSM) — Incident investigation records for processes with highly hazardous chemicals must be retained for 5 years (1910.119(m)). Missing this during an OSHA inspection = citation.
Self-hosted n8n on your client's own VPS or on-prem server: workflow JSON is version-controlled in git (itself an audit artifact), all executions write to an on-prem database, and no data leaves the client's network boundary.
1. New Manufacturer Client Onboarding Drip
Tier your onboarding sequence from day one. A 15-person job shop needs different Day-0 messaging than a 600-seat global OEM with 4 plants and an active AS9100 audit.
{
"name": "ManufacturingTech — New Manufacturer Client Onboarding Drip",
"nodes": [
{
"id": "n1",
"name": "Google Sheets Trigger",
"type": "n8n-nodes-base.googleSheetsTrigger",
"parameters": {
"sheetId": "YOUR_CLIENT_SHEET_ID",
"event": "rowAdded"
},
"position": [
240,
300
]
},
{
"id": "n2",
"name": "Classify Tier",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const r=$json;\nconst seats=parseInt(r.seats||0);\nconst tier=seats>=500?'TIER_1_GLOBAL_OEM':seats>=100?'TIER_2_MID_MANUFACTURER':seats>=20?'TIER_3_JOB_SHOP':'TIER_4_STARTUP_MAKER';\nreturn [{json:{...r,tier,standard:r.standard||'ISO_9001',onboardTs:new Date().toISOString()}}];"
},
"position": [
440,
300
]
},
{
"id": "n3",
"name": "Route by Tier",
"type": "n8n-nodes-base.switch",
"parameters": {
"dataPropertyName": "tier",
"rules": [
{
"value": "TIER_1_GLOBAL_OEM",
"output": 0
},
{
"value": "TIER_2_MID_MANUFACTURER",
"output": 1
},
{
"value": "TIER_3_JOB_SHOP",
"output": 2
},
{
"value": "TIER_4_STARTUP_MAKER",
"output": 3
}
]
},
"position": [
640,
300
]
},
{
"id": "n4",
"name": "Day 0 Welcome Email",
"type": "n8n-nodes-base.gmail",
"parameters": {
"toEmail": "={{$json.primary_contact_email}}",
"subject": "Welcome to [Your Platform] — {{$json.company_name}} onboarding starts today",
"message": "Hi {{$json.primary_contact_name}},\n\nWelcome aboard. Your {{$json.tier}} onboarding plan is active.\n\nNext: your dedicated CSM will reach out within 2 hours.\n\nISO {{$json.standard}} audit log — every action is permanently recorded on your infrastructure.\n\n[Your team]"
},
"position": [
840,
180
]
},
{
"id": "n5",
"name": "Notify CSM in Slack",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#customer-success",
"text": ":factory: New {{$json.tier}} client: *{{$json.company_name}}* ({{$json.seats}} seats, {{$json.standard}}). Contact: {{$json.primary_contact_email}}. Assign CSM + schedule kickoff within 2h."
},
"position": [
840,
300
]
},
{
"id": "n6",
"name": "Log to ISO 9001 Audit Sheet",
"type": "n8n-nodes-base.googleSheets",
"parameters": {
"operation": "append",
"sheetId": "YOUR_AUDIT_SHEET_ID",
"columns": {
"mappingMode": "autoMapInputData"
}
},
"position": [
840,
420
]
},
{
"id": "n7",
"name": "Wait 3 Days",
"type": "n8n-nodes-base.wait",
"parameters": {
"amount": 3,
"unit": "days"
},
"position": [
1040,
300
]
},
{
"id": "n8",
"name": "Day 3 Check-In Email",
"type": "n8n-nodes-base.gmail",
"parameters": {
"toEmail": "={{$json.primary_contact_email}}",
"subject": "Day 3 Check-In — {{$json.company_name}}",
"message": "Hi {{$json.primary_contact_name}},\n\nThree days in. Your first automated workflow should be running by now.\n\nNeed help? Reply here — your CSM responds within 4 hours.\n\n[Your team]"
},
"position": [
1240,
300
]
},
{
"id": "n9",
"name": "Wait 4 More Days",
"type": "n8n-nodes-base.wait",
"parameters": {
"amount": 4,
"unit": "days"
},
"position": [
1440,
300
]
},
{
"id": "n10",
"name": "Day 7 Value Email",
"type": "n8n-nodes-base.gmail",
"parameters": {
"toEmail": "={{$json.primary_contact_email}}",
"subject": "Week 1 Complete — What's Working at {{$json.company_name}}?",
"message": "Hi {{$json.primary_contact_name}},\n\nOne week in. ISO {{$json.standard}} records generated this week are permanently stored on your infrastructure — no 30-day log cliff.\n\nWhat's working? What isn't? Reply and tell us.\n\n[Your team]"
},
"position": [
1640,
300
]
}
],
"connections": {
"Google Sheets Trigger": {
"main": [
[
{
"node": "Classify Tier",
"type": "main",
"index": 0
}
]
]
},
"Classify Tier": {
"main": [
[
{
"node": "Route by Tier",
"type": "main",
"index": 0
}
]
]
},
"Route by Tier": {
"main": [
[
{
"node": "Day 0 Welcome Email",
"type": "main",
"index": 0
}
],
[
{
"node": "Day 0 Welcome Email",
"type": "main",
"index": 0
}
],
[
{
"node": "Day 0 Welcome Email",
"type": "main",
"index": 0
}
],
[
{
"node": "Day 0 Welcome Email",
"type": "main",
"index": 0
}
]
]
},
"Day 0 Welcome Email": {
"main": [
[
{
"node": "Notify CSM in Slack",
"type": "main",
"index": 0
}
]
]
},
"Notify CSM in Slack": {
"main": [
[
{
"node": "Log to ISO 9001 Audit Sheet",
"type": "main",
"index": 0
}
]
]
},
"Log to ISO 9001 Audit Sheet": {
"main": [
[
{
"node": "Wait 3 Days",
"type": "main",
"index": 0
}
]
]
},
"Wait 3 Days": {
"main": [
[
{
"node": "Day 3 Check-In Email",
"type": "main",
"index": 0
}
]
]
},
"Day 3 Check-In Email": {
"main": [
[
{
"node": "Wait 4 More Days",
"type": "main",
"index": 0
}
]
]
},
"Wait 4 More Days": {
"main": [
[
{
"node": "Day 7 Value Email",
"type": "main",
"index": 0
}
]
]
}
}
}
Replace: YOUR_CLIENT_SHEET_ID (sheet with new client rows), YOUR_AUDIT_SHEET_ID (permanent onboarding log), Gmail From address, Slack channel name.
Why it matters for ISO/IATF compliance: Every onboarding event writes to a permanent Google Sheet with timestamp. Your platform becomes part of the §7.5 documented information trail from the first contact. If a CB auditor asks for evidence of customer communication controls, this sheet is the answer.
2. Production Line & Machine Health Monitor
IIoT platforms polling Zapier: each health check = one task. At 3-minute intervals across 50 production lines, that's 720,000 tasks per month. Zapier Business ($799/mo) caps at 750K. n8n on a $30 VPS: zero marginal cost per check.
{
"name": "ManufacturingTech — Production Line & Machine Health Monitor",
"nodes": [
{
"id": "n1",
"name": "Every 3 Minutes",
"type": "n8n-nodes-base.scheduleTrigger",
"parameters": {
"rule": {
"interval": [
{
"field": "minutes",
"minutesInterval": 3
}
]
}
},
"position": [
240,
300
]
},
{
"id": "n2",
"name": "Get Machine Endpoints",
"type": "n8n-nodes-base.postgres",
"parameters": {
"operation": "executeQuery",
"query": "SELECT id, machine_id, endpoint_url, machine_type, plant_id, last_ok_ts FROM machine_endpoints WHERE active = true ORDER BY plant_id, machine_id"
},
"position": [
440,
300
]
},
{
"id": "n3",
"name": "HTTP Health Check",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "={{$json.endpoint_url}}/health",
"method": "GET",
"timeout": 5000,
"continueOnFail": true
},
"position": [
640,
300
]
},
{
"id": "n4",
"name": "Classify Status",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const item=$json;\nconst status=item.$response?.status;\nconst lastOk=new Date(item.last_ok_ts||0);\nconst staleMins=Math.round((Date.now()-lastOk)/60000);\nlet health='OK';\nif(!status||status>=500) health='DOWN';\nelse if(staleMins>=15) health='STALE_DATA';\nelse if(status>=400) health='DEGRADED';\nreturn [{json:{...item,health,staleMins,checkedAt:new Date().toISOString()}}];"
},
"position": [
840,
300
]
},
{
"id": "n5",
"name": "Skip if OK",
"type": "n8n-nodes-base.if",
"parameters": {
"conditions": {
"string": [
{
"value1": "={{$json.health}}",
"operation": "notEqual",
"value2": "OK"
}
]
}
},
"position": [
1040,
300
]
},
{
"id": "n6",
"name": "Dedup 30min",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const item=$json;\nconst state=$getWorkflowStaticData('global');\nconst key=`${item.machine_id}_${item.health}`;\nconst lastAlerted=state[key]||0;\nconst suppressed=(Date.now()-lastAlerted)<30*60*1000;\nif(!suppressed) state[key]=Date.now();\nreturn [{json:{...item,suppressed}}];"
},
"position": [
1240,
300
]
},
{
"id": "n7",
"name": "Alert if New",
"type": "n8n-nodes-base.if",
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{$json.suppressed}}",
"operation": "equal",
"value2": false
}
]
}
},
"position": [
1440,
300
]
},
{
"id": "n8",
"name": "Slack Production Ops",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#production-ops",
"text": ":rotating_light: *{{$json.health}}* | Machine: {{$json.machine_id}} ({{$json.machine_type}}) | Plant: {{$json.plant_id}} | Stale: {{$json.staleMins}}min | {{$json.checkedAt}}"
},
"position": [
1640,
180
]
},
{
"id": "n9",
"name": "Log Incident to Postgres",
"type": "n8n-nodes-base.postgres",
"parameters": {
"operation": "executeQuery",
"query": "INSERT INTO machine_incidents (machine_id, plant_id, health_status, stale_mins, detected_at) VALUES ('{{$json.machine_id}}','{{$json.plant_id}}','{{$json.health}}',{{$json.staleMins}},NOW()) ON CONFLICT DO NOTHING"
},
"position": [
1640,
420
]
}
],
"connections": {
"Every 3 Minutes": {
"main": [
[
{
"node": "Get Machine Endpoints",
"type": "main",
"index": 0
}
]
]
},
"Get Machine Endpoints": {
"main": [
[
{
"node": "HTTP Health Check",
"type": "main",
"index": 0
}
]
]
},
"HTTP Health Check": {
"main": [
[
{
"node": "Classify Status",
"type": "main",
"index": 0
}
]
]
},
"Classify Status": {
"main": [
[
{
"node": "Skip if OK",
"type": "main",
"index": 0
}
]
]
},
"Skip if OK": {
"main": [
[
{
"node": "Dedup 30min",
"type": "main",
"index": 0
}
],
[]
]
},
"Dedup 30min": {
"main": [
[
{
"node": "Alert if New",
"type": "main",
"index": 0
}
]
]
},
"Alert if New": {
"main": [
[
{
"node": "Slack Production Ops",
"type": "main",
"index": 0
}
],
[]
]
},
"Slack Production Ops": {
"main": [
[
{
"node": "Log Incident to Postgres",
"type": "main",
"index": 0
}
]
]
}
}
}
Replace: Machine endpoints Postgres table, Slack channel, plant/machine field names to match your schema.
The $getWorkflowStaticData pattern: The dedup node stores the last alert timestamp per machine in workflow static data. Same machine, same status — no repeat alert for 30 minutes. Prevents Slack flooding during extended downtime events.
The compliance math: ISO 13485 §6.4 (for medical device manufacturers) and IATF 16949 §7.1.3 require equipment monitoring records. The Postgres insert on every incident creates a permanent equipment health log — not a 30-day task log.
3. ISO/IATF/AS9100 Compliance Deadline Tracker
Missing an ISO 9001 surveillance audit by a day can suspend your client's certificate. Missing an IATF 16949 CSR update can trigger a customer-directed audit. Build a hard-deadline tracker that escalates well before the cliff.
{
"name": "ManufacturingTech — ISO/IATF/AS9100 Compliance Deadline Tracker",
"nodes": [
{
"id": "n1",
"name": "Weekdays at 8AM",
"type": "n8n-nodes-base.scheduleTrigger",
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 8 * * 1-5"
}
]
}
},
"position": [
240,
300
]
},
{
"id": "n2",
"name": "Get Compliance Items",
"type": "n8n-nodes-base.googleSheets",
"parameters": {
"operation": "getAll",
"sheetId": "YOUR_COMPLIANCE_TRACKER_SHEET_ID",
"options": {
"returnAllMatches": true
}
},
"position": [
440,
300
]
},
{
"id": "n3",
"name": "Classify Urgency",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const actionMap={\n ISO_9001_SURVEILLANCE:'Schedule internal audit + corrective action plan',\n ISO_9001_RECERT:'Initiate recertification with CB — 90-day lead time required',\n IATF_16949_SURV:'Prepare IATF customer-specific requirements (CSR) review',\n IATF_16949_RECERT:'Engage IATF CB + customer notification per §7.4',\n AS9100D_CERT:'Confirm AS9100 Rev D scope + first-article inspection records',\n FDA_QMSR_820:'Prepare Design History File + Device History Record review',\n OSHA_PSM_PHA:'Process Hazard Analysis revalidation — 5-year cycle (1910.119(e)(6))',\n REACH_SVHC:'Update SVHC declaration to current ECHA candidate list',\n ROHS_ANNUAL:'Refresh RoHS DoC + test reports for all product lines',\n SOC2_TYPE2:'Coordinate auditor review window + evidence collection package'\n};\nreturn $input.all().map(item=>{\n const d=item.json;\n const daysLeft=Math.round((new Date(d.deadline_date)-Date.now())/86400000);\n let urgency=daysLeft<0?'OVERDUE':daysLeft<=7?'CRITICAL':daysLeft<=21?'URGENT':daysLeft<=45?'WARNING':'NOTICE';\n return {json:{...d,daysLeft,urgency,action:actionMap[d.standard_code]||'Review and assign compliance owner'}};\n}).filter(i=>i.json.urgency!=='NOTICE');"
},
"position": [
640,
300
]
},
{
"id": "n4",
"name": "Route by Urgency",
"type": "n8n-nodes-base.switch",
"parameters": {
"dataPropertyName": "urgency",
"rules": [
{
"value": "OVERDUE",
"output": 0
},
{
"value": "CRITICAL",
"output": 1
},
{
"value": "URGENT",
"output": 2
},
{
"value": "WARNING",
"output": 3
}
]
},
"position": [
840,
300
]
},
{
"id": "n5",
"name": "Slack Compliance Ops",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#compliance-ops",
"text": ":red_circle: *{{$json.urgency}}* | {{$json.standard_code}} | Client: {{$json.client_name}} | Due: {{$json.deadline_date}} ({{$json.daysLeft}}d) | Action: {{$json.action}}"
},
"position": [
1040,
180
]
},
{
"id": "n6",
"name": "Email Compliance Owner",
"type": "n8n-nodes-base.gmail",
"parameters": {
"toEmail": "={{$json.owner_email}}",
"subject": "[{{$json.urgency}}] {{$json.standard_code}} — {{$json.client_name}} due {{$json.deadline_date}}",
"message": "{{$json.urgency}} compliance item requires immediate attention.\n\nClient: {{$json.client_name}}\nStandard: {{$json.standard_code}}\nDeadline: {{$json.deadline_date}} ({{$json.daysLeft}} days)\n\nRequired action: {{$json.action}}\n\nThis is an automated alert from [Your Platform]."
},
"position": [
1040,
420
]
}
],
"connections": {
"Weekdays at 8AM": {
"main": [
[
{
"node": "Get Compliance Items",
"type": "main",
"index": 0
}
]
]
},
"Get Compliance Items": {
"main": [
[
{
"node": "Classify Urgency",
"type": "main",
"index": 0
}
]
]
},
"Classify Urgency": {
"main": [
[
{
"node": "Route by Urgency",
"type": "main",
"index": 0
}
]
]
},
"Route by Urgency": {
"main": [
[
{
"node": "Slack Compliance Ops",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack Compliance Ops",
"type": "main",
"index": 0
}
],
[
{
"node": "Email Compliance Owner",
"type": "main",
"index": 0
}
],
[
{
"node": "Email Compliance Owner",
"type": "main",
"index": 0
}
]
]
},
"Slack Compliance Ops": {
"main": [
[
{
"node": "Email Compliance Owner",
"type": "main",
"index": 0
}
]
]
}
}
}
Replace: YOUR_COMPLIANCE_TRACKER_SHEET_ID (columns: client_name, standard_code, deadline_date, owner_email), add/remove rows from actionMap to match your standard coverage.
The standard codes this covers: ISO_9001_SURVEILLANCE, ISO_9001_RECERT, IATF_16949_SURV, IATF_16949_RECERT, AS9100D_CERT, FDA_QMSR_820, OSHA_PSM_PHA, REACH_SVHC, ROHS_ANNUAL, SOC2_TYPE2.
The OSHA PSM angle: Process Hazard Analyses (PHA) must be revalidated every 5 years under 1910.119(e)(6). Missing the window = citation. This tracker keeps your clients' PHAs on schedule without anyone remembering to look at a spreadsheet.
4. Production Defect & Quality Alert Pipeline
ISO 9001:2015 §8.7 requires documented control of nonconforming outputs. AS9100D §8.7 adds customer notification requirements for escape defects. Build a webhook pipeline that classifies, routes, and logs every defect event the moment it's detected.
{
"name": "ManufacturingTech — Production Defect & Quality Alert Pipeline",
"nodes": [
{
"id": "n1",
"name": "Webhook: Defect Event",
"type": "n8n-nodes-base.webhook",
"parameters": {
"path": "defect-event",
"method": "POST",
"responseMode": "responseNode"
},
"position": [
240,
300
]
},
{
"id": "n2",
"name": "Classify Defect Severity",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const e=$json.body||$json;\nconst count=e.defect_count||1;\nconst window=e.window_minutes||60;\nlet severity='INFO';\nif(count>=5&&window<=30) severity='CRITICAL_CONTAINMENT';\nelse if(count>=3) severity='QUALITY_HOLD';\nelse if(count>=2) severity='TREND_WARNING';\nconst corrDeadline=severity==='CRITICAL_CONTAINMENT'?'4 hours':severity==='QUALITY_HOLD'?'8 hours':severity==='TREND_WARNING'?'24 hours':'72 hours';\nreturn [{json:{...e,severity,corrective_action_deadline:corrDeadline,detectedAt:new Date().toISOString()}}];"
},
"position": [
440,
300
]
},
{
"id": "n3",
"name": "Route Severity",
"type": "n8n-nodes-base.switch",
"parameters": {
"dataPropertyName": "severity",
"rules": [
{
"value": "CRITICAL_CONTAINMENT",
"output": 0
},
{
"value": "QUALITY_HOLD",
"output": 1
},
{
"value": "TREND_WARNING",
"output": 2
},
{
"value": "INFO",
"output": 3
}
]
},
"position": [
640,
300
]
},
{
"id": "n4",
"name": "Slack Quality Emergency",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#quality-emergency",
"text": ":warning: *{{$json.severity}}* | Part: {{$json.part_number}} | Line: {{$json.production_line}} | Defects: {{$json.defect_count}} | CA deadline: {{$json.corrective_action_deadline}} | @here — CAPA required"
},
"position": [
840,
180
]
},
{
"id": "n5",
"name": "Slack Quality Ops",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#quality-ops",
"text": ":yellow_circle: *{{$json.severity}}* | Part: {{$json.part_number}} | Line: {{$json.production_line}} | Defects: {{$json.defect_count}} | CA deadline: {{$json.corrective_action_deadline}}"
},
"position": [
840,
300
]
},
{
"id": "n6",
"name": "Log ISO 9001 §8.7 Record",
"type": "n8n-nodes-base.postgres",
"parameters": {
"operation": "executeQuery",
"query": "INSERT INTO quality_defect_log (part_number, production_line, defect_type, defect_count, severity, corrective_action_deadline, detected_at, operator_id) VALUES ('{{$json.part_number}}','{{$json.production_line}}','{{$json.defect_type}}',{{$json.defect_count}},'{{$json.severity}}','{{$json.corrective_action_deadline}}',NOW(),'{{$json.operator_id}}') ON CONFLICT DO NOTHING"
},
"position": [
1040,
300
]
},
{
"id": "n7",
"name": "Respond 200 with Deadline",
"type": "n8n-nodes-base.respondToWebhook",
"parameters": {
"responseCode": 200,
"responseBody": "{\"received\":true,\"severity\":\"{{$json.severity}}\",\"corrective_action_deadline\":\"{{$json.corrective_action_deadline}}\"}"
},
"position": [
1240,
300
]
}
],
"connections": {
"Webhook: Defect Event": {
"main": [
[
{
"node": "Classify Defect Severity",
"type": "main",
"index": 0
}
]
]
},
"Classify Defect Severity": {
"main": [
[
{
"node": "Route Severity",
"type": "main",
"index": 0
}
]
]
},
"Route Severity": {
"main": [
[
{
"node": "Slack Quality Emergency",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack Quality Ops",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack Quality Ops",
"type": "main",
"index": 0
}
],
[
{
"node": "Log ISO 9001 §8.7 Record",
"type": "main",
"index": 0
}
]
]
},
"Slack Quality Emergency": {
"main": [
[
{
"node": "Log ISO 9001 §8.7 Record",
"type": "main",
"index": 0
}
]
]
},
"Slack Quality Ops": {
"main": [
[
{
"node": "Log ISO 9001 §8.7 Record",
"type": "main",
"index": 0
}
]
]
},
"Log ISO 9001 §8.7 Record": {
"main": [
[
{
"node": "Respond 200 with Deadline",
"type": "main",
"index": 0
}
]
]
}
}
}
Replace: Slack channel names (#quality-emergency, #quality-ops), Postgres table name (quality_defect_log), defect classification thresholds to match your clients' control plan requirements.
Why the Postgres log matters: IATF 16949:2016 §10.2.3 requires documented information to support customer 8D investigations. Your quality_defect_log table becomes the evidence base for CAPA reports. Zapier's task log is not a quality record — this Postgres table is.
The REACH/RoHS angle: If defect events include material composition data (restricted substances, SVHC flags), routing through Zapier's cloud servers may create an uncontrolled sub-processor under EU REACH §33. Self-hosted n8n keeps substance data inside the manufacturing network.
5. Weekly ManufacturingTech Platform KPI Dashboard
Monday 8AM before the ops review: total clients by tier, machine uptime across the fleet, MRR, at-risk accounts. All delivered as an HTML email to executives with a Slack one-liner.
{
"name": "ManufacturingTech — Weekly Platform KPI Dashboard",
"nodes": [
{
"id": "n1",
"name": "Monday at 8AM",
"type": "n8n-nodes-base.scheduleTrigger",
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 8 * * 1"
}
]
}
},
"position": [
240,
300
]
},
{
"id": "n2",
"name": "Get Platform Metrics",
"type": "n8n-nodes-base.postgres",
"parameters": {
"operation": "executeQuery",
"query": "SELECT COUNT(DISTINCT client_id) AS total_clients, COUNT(DISTINCT CASE WHEN tier='TIER_1_GLOBAL_OEM' THEN client_id END) AS t1_oem_count, COUNT(DISTINCT CASE WHEN last_login_ts>=NOW()-INTERVAL '7d' THEN client_id END) AS active_7d, ROUND(AVG(machine_uptime_pct),1) AS avg_machine_uptime, SUM(mrr_usd) AS total_mrr FROM platform_metrics WHERE week_start=date_trunc('week',NOW()-INTERVAL '7d')"
},
"position": [
440,
240
]
},
{
"id": "n3",
"name": "Get At-Risk Accounts",
"type": "n8n-nodes-base.postgres",
"parameters": {
"operation": "executeQuery",
"query": "SELECT client_id, client_name, tier, health_score, last_login_ts, open_support_tickets, compliance_gaps FROM account_health WHERE health_score < 70 ORDER BY health_score ASC LIMIT 10"
},
"position": [
440,
420
]
},
{
"id": "n4",
"name": "Merge",
"type": "n8n-nodes-base.merge",
"parameters": {
"mode": "combine",
"combinationMode": "multiplex"
},
"position": [
640,
300
]
},
{
"id": "n5",
"name": "Build KPI HTML",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const state=$getWorkflowStaticData('global');\nconst m=$input.first().json;\nconst prev=state.lastWeek||{};\nconst wow=(c,p)=>p&&p>0?` (${c>p?'+':''}${Math.round((c-p)/p*100)}% WoW)`:''\nconst uptime=parseFloat(m.avg_machine_uptime)||0;\nconst uptimeColor=uptime>=99?'#27ae60':uptime>=95?'#f39c12':'#e74c3c';\nstate.lastWeek=m;\nconst html=[\n '<h2>ManufacturingTech Weekly KPI — '+new Date().toISOString().slice(0,10)+'</h2>',\n '<table border=\"1\" cellpadding=\"8\" cellspacing=\"0\" style=\"border-collapse:collapse;font-family:sans-serif\">',\n '<tr style=\"background:#2c3e50;color:white\"><th>Metric</th><th>This Week</th><th>Trend</th></tr>',\n '<tr><td>Total Clients</td><td>'+m.total_clients+'</td><td>'+wow(m.total_clients,prev.total_clients)+'</td></tr>',\n '<tr><td>Tier 1 Global OEM</td><td>'+m.t1_oem_count+'</td><td>'+wow(m.t1_oem_count,prev.t1_oem_count)+'</td></tr>',\n '<tr><td>Active Last 7d</td><td>'+m.active_7d+'</td><td>'+wow(m.active_7d,prev.active_7d)+'</td></tr>',\n '<tr><td>Avg Machine Uptime</td><td style=\"color:'+uptimeColor+'\">'+uptime+'%</td><td>'+wow(uptime,prev.avg_machine_uptime)+'</td></tr>',\n '<tr><td>Total MRR</td><td>$'+Math.round(m.total_mrr||0).toLocaleString()+'</td><td>'+wow(m.total_mrr,prev.total_mrr)+'</td></tr>',\n '</table>'\n].join('');\nreturn [{json:{kpiHtml:html,metrics:m}}];"
},
"position": [
840,
300
]
},
{
"id": "n6",
"name": "Email Executives",
"type": "n8n-nodes-base.gmail",
"parameters": {
"toEmail": "ceo@yourcompany.com",
"bccEmail": "cto@yourcompany.com,vp-cs@yourcompany.com,vp-sales@yourcompany.com,coo@yourcompany.com",
"subject": "ManufacturingTech Weekly KPI — {{$now.format('YYYY-MM-DD')}}",
"message": "={{$json.kpiHtml}}",
"additionalFields": {
"emailType": "html"
}
},
"position": [
1040,
240
]
},
{
"id": "n7",
"name": "Slack Exec Summary",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#exec-kpis",
"text": ":bar_chart: *ManufacturingTech Weekly KPI* | Clients: {{$json.metrics.total_clients}} | Uptime: {{$json.metrics.avg_machine_uptime}}% | MRR: ${{$json.metrics.total_mrr}} | At-risk: see email"
},
"position": [
1040,
420
]
}
],
"connections": {
"Monday at 8AM": {
"main": [
[
{
"node": "Get Platform Metrics",
"type": "main",
"index": 0
},
{
"node": "Get At-Risk Accounts",
"type": "main",
"index": 0
}
]
]
},
"Get Platform Metrics": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
}
]
]
},
"Get At-Risk Accounts": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
}
]
]
},
"Merge": {
"main": [
[
{
"node": "Build KPI HTML",
"type": "main",
"index": 0
}
]
]
},
"Build KPI HTML": {
"main": [
[
{
"node": "Email Executives",
"type": "main",
"index": 0
}
]
]
},
"Email Executives": {
"main": [
[
{
"node": "Slack Exec Summary",
"type": "main",
"index": 0
}
]
]
}
}
}
Replace: Postgres table names (platform_metrics, account_health), executive email addresses, Slack channel.
$getWorkflowStaticData for WoW% trends: The Build KPI HTML node reads last week's metrics from static data, computes week-over-week percent changes inline, then overwrites with this week's data. No extra database table needed — the workflow remembers its own history.
Why ManufacturingTech SaaS Teams Self-Host n8n
| Requirement | Zapier / Make.com | n8n Self-Hosted |
|---|---|---|
| ISO 9001 §7.5 quality record retention | 30-day task log — NCR evidence | Permanent on-prem Postgres |
| IATF 16949 defect traceability | Task log not a quality record | Postgres CAPA evidence base |
| AS9100D §8.4 external provider control | Uncontrolled third-party processor | Internal VPC boundary |
| OSHA PSM 5-year incident records | Cannot guarantee retention | Self-hosted = permanent |
| FDA QMSR device history records | 30-day cliff | Device lifetime + 2yr on-prem |
| REACH/RoHS substance data routing | Routes through third-party cloud | Manufacturing VPC maintained |
| Cost at 10M machine events/month | $10,000+/mo (Zapier Business) | ~$100/mo VPS |
| Air-gapped plant deployment | Not possible | Yes — n8n runs fully offline |
The Workflow Files
All 5 workflows are available as import-ready JSON at stripeai.gumroad.com. The Webhook to Database workflow ($12) is the foundation for the defect pipeline. The Customer Feedback Analyzer ($29) covers quality alert triage for customer-facing defect reports. The Daily Report Generator ($19) pre-wires the KPI dashboard pattern.
Or grab the full bundle of 15 workflows at $97 — one JSON import per workflow, ready to deploy on your clients' infrastructure.
If your ManufacturingTech clients are asking about on-premise automation or ISO/IATF compliance traceability, the self-hosted n8n pitch writes itself. These 5 workflows are the starting point.
Have a ManufacturingTech use case I missed? Drop it in the comments.
Top comments (0)