If you're building an IoT platform — device management SaaS, fleet telematics, industrial IoT, smart building software — you're dealing with data volumes and latency requirements that make Zapier and Make.com non-starters.
A single IoT deployment can generate millions of webhook events per day. Zapier Pro gives you 2,000 tasks/month. The math doesn't work.
The compliance story is worse: device telemetry includes GPS location data (CCPA/GDPR), industrial sensor readings (NIST 800-82 for critical infrastructure), and patient vitals in health monitoring (HIPAA). Routing any of that through a third-party cloud automation tool creates a new GDPR Art.28 sub-processor relationship — and for government or defense IoT, it may violate data handling regulations entirely.
n8n self-hosted is the only automation layer that makes sense for IoT SaaS vendors: it runs inside your VPC, processes events at sub-100ms latency, handles millions of messages per day at zero marginal cost, and you control where every byte lands.
Here are 5 workflows every IoT platform vendor should automate — with full import-ready JSON.
Why IoT SaaS Teams Self-Host n8n
| Factor | n8n (self-hosted) | Zapier | Make.com |
|---|---|---|---|
| Data hosting | Your VPC — telemetry stays inside | Zapier US cloud | Make EU/US cloud |
| Pricing at 1M events/day | ~$20/mo VPS | Enterprise (contact sales) | Enterprise (contact sales) |
| Webhook latency | <100ms in-VPC | 2–15s polling/queue | 2–10s polling/queue |
| Edge deployment | Runs on Raspberry Pi, K3s, Jetson | Cloud only | Cloud only |
| GDPR Art.28 sub-processor | None added | Zapier becomes sub-processor | Make becomes sub-processor |
| ITAR/NIST 800-82 compliance | Achievable on-prem | Not achievable | Not achievable |
Workflow 1: Device Fleet Health Monitor & Offline Alert
The problem: Thousands of devices. Some go offline or degrade. You need to know immediately — before your customer files a support ticket.
The workflow:
- Trigger: Schedule node — every 5 minutes
-
Fetch devices: HTTP Request node — GET your device management API
/api/devices?status=all - Classify & dedup: Code node
const devices = $input.all().map(i => i.json);
const now = Date.now();
const seen = $getWorkflowStaticData("node");
const issues = [];
for (const device of devices) {
const minsSince = (now - new Date(device.last_seen_at).getTime()) / 60000;
let status = "OK", severity = null;
if (!device.connected && minsSince > 60) { status = "OFFLINE"; severity = "CRITICAL"; }
else if (!device.connected && minsSince > 15) { status = "OFFLINE"; severity = "HIGH"; }
else if (device.error_rate_pct > 5) { status = "ERROR"; severity = "HIGH"; }
else if (device.error_rate_pct > 1 || device.latency_ms > 2000) { status = "DEGRADED"; severity = "MEDIUM"; }
if (status !== "OK" && !seen[device.device_id]) {
seen[device.device_id] = Date.now();
issues.push({ ...device, status, severity });
}
if (status === "OK") delete seen[device.device_id];
}
return issues.map(d => ({ json: d }));
-
Alert: Slack node — CRITICAL devices to
#device-ops-critical, others to#device-ops -
Log: Postgres node —
INSERT INTO device_health_events (device_id, customer_id, status, severity, ts)
Workflow 2: New Customer Device Onboarding Drip
The problem: New IoT customers need to get their first device online fast. Time-to-first-device is your most important activation metric — every day of delay is churn risk.
The workflow:
-
Trigger: Google Sheets Trigger — new row added to
new_customerssheet (or CRM webhook) - Day 0: Gmail — API credentials + SDK quickstart guide
-
Day 0: Slack DM to CSM —
New IoT customer: {{company_name}} ({{device_type}}). Target: first device online within 48h. - Wait: 3 days
- Day 3: Gmail — check-in: "Have you connected your first device? Reply if you hit any issues."
- Wait: 4 days
- Day 7: Gmail — "Here's how to set up fleet dashboards, OTA firmware updates, and device alerting."
-
Complete: Google Sheets — mark
onboarding_status = 'drip_complete'
Import-ready JSON:
{
"name": "IoT Customer Onboarding Drip",
"nodes": [
{"id":"1","name":"Sheets Trigger","type":"n8n-nodes-base.googleSheetsTrigger","position":[240,300],"parameters":{"sheetId":"YOUR_SHEET_ID","range":"new_customers!A:Z"}},
{"id":"2","name":"Gmail Day0","type":"n8n-nodes-base.gmail","position":[460,300],"parameters":{"to":"={{$json.customer_email}}","subject":"Your IoT Platform API credentials + quickstart","message":"Hi {{$json.contact_name}},\n\nYour API key: {{$json.api_key}}\nSDK docs: https://docs.yourplatform.io/sdk\n\nConnect your first device in 10 min.\n\nTeam"}},
{"id":"3","name":"Slack CSM","type":"n8n-nodes-base.slack","position":[460,420],"parameters":{"channel":"={{$json.csm_slack_id}}","text":"New IoT customer: {{$json.company_name}} ({{$json.device_type}}). Target: first device online 48h."}},
{"id":"4","name":"Wait 3d","type":"n8n-nodes-base.wait","position":[680,300],"parameters":{"amount":3,"unit":"days"}},
{"id":"5","name":"Gmail Day3","type":"n8n-nodes-base.gmail","position":[900,300],"parameters":{"to":"={{$json.customer_email}}","subject":"Have you connected your first device?","message":"Hi {{$json.contact_name}},\n\nChecking in — first device connected yet? Reply if you need help, we respond in < 2h.\n\nTeam"}},
{"id":"6","name":"Wait 4d","type":"n8n-nodes-base.wait","position":[1120,300],"parameters":{"amount":4,"unit":"days"}},
{"id":"7","name":"Gmail Day7","type":"n8n-nodes-base.gmail","position":[1340,300],"parameters":{"to":"={{$json.customer_email}}","subject":"Day 7: fleet dashboards, OTA updates, alerting","message":"Hi {{$json.contact_name}},\n\nBy now you should have telemetry flowing. Next steps:\n- Fleet dashboards\n- OTA firmware pipelines\n- Device health alerting\n\nGuide: https://docs.yourplatform.io/fleet-ops\n\nTeam"}},
{"id":"8","name":"Mark Complete","type":"n8n-nodes-base.googleSheets","position":[1560,300],"parameters":{"operation":"update","sheetId":"YOUR_SHEET_ID","range":"new_customers","data":{"onboarding_status":"drip_complete"}}}
],
"connections":{"Sheets Trigger":{"main":[[{"node":"Gmail Day0","type":"main","index":0},{"node":"Slack CSM","type":"main","index":0}]]},"Gmail Day0":{"main":[[{"node":"Wait 3d","type":"main","index":0}]]},"Wait 3d":{"main":[[{"node":"Gmail Day3","type":"main","index":0}]]},"Gmail Day3":{"main":[[{"node":"Wait 4d","type":"main","index":0}]]},"Wait 4d":{"main":[[{"node":"Gmail Day7","type":"main","index":0}]]},"Gmail Day7":{"main":[[{"node":"Mark Complete","type":"main","index":0}]]}}
}
Workflow 3: Device Telemetry Anomaly Alert
The problem: A sensor starts reading out of range. Battery draining 3x faster than normal. You need to catch this before your customer sees it in their dashboard.
The workflow:
- Trigger: Schedule node — every 15 minutes
-
Baseline query: Postgres —
SELECT device_id, metric_name, AVG(value) as avg_7d, STDDEV(value) as stddev_7d FROM telemetry_readings WHERE ts > NOW() - INTERVAL '7 days' GROUP BY device_id, metric_name - Recent query: Postgres — last 1-hour average per device/metric
- Classify: Code node — z-score anomaly detection
const baseline = $input.all()[0].json;
const recent = $input.all()[1].json;
const bMap = {};
for (const b of baseline) bMap[`${b.device_id}:${b.metric_name}`] = b;
const anomalies = [];
for (const r of recent) {
const b = bMap[`${r.device_id}:${r.metric_name}`];
if (!b || b.stddev_7d === 0) continue;
const z = Math.abs(r.avg_1h - b.avg_7d) / b.stddev_7d;
let severity = z >= 3 ? "CRITICAL" : z >= 2 ? "HIGH" : z >= 1.5 ? "WATCH" : null;
if (severity) anomalies.push({ ...r, baseline_avg: b.avg_7d, zscore: z.toFixed(2), severity });
}
const seen = $getWorkflowStaticData("node");
const newAnomalies = anomalies.filter(a => !seen[`${a.device_id}:${a.metric_name}`]);
anomalies.forEach(a => { seen[`${a.device_id}:${a.metric_name}`] = Date.now(); });
return newAnomalies.map(a => ({ json: a }));
-
Alert: Slack — CRITICAL to
#iot-ops-critical, others to#iot-ops -
Log: Postgres —
INSERT INTO device_anomaly_log
Workflow 4: OTA Firmware Update Pipeline Monitor
The problem: You push firmware to 50,000 devices. Three hours in, 8% are failing to update. You need to know before it becomes a mass support incident.
The workflow:
- Trigger: Schedule node — every 5 minutes
-
Fetch active rollouts: HTTP Request node — GET
/api/firmware/rollouts?status=in_progress - Classify: Code node
const rollouts = $input.first().json.rollouts || [];
const issues = [];
for (const r of rollouts) {
const failPct = (r.failed_devices / r.total_devices) * 100;
const completePct = (r.completed_devices / r.total_devices) * 100;
const elapsedH = (Date.now() - new Date(r.started_at).getTime()) / 3600000;
let status = "PROGRESSING";
if (failPct > 10) status = "ROLLOUT_FAILED";
else if (failPct > 3) status = "DEGRADED";
else if (elapsedH > r.expected_hours * 1.5 && completePct < 50) status = "STALLED";
if (status !== "PROGRESSING") {
issues.push({ ...r, status, failPct: failPct.toFixed(1), completePct: completePct.toFixed(1) });
}
}
return issues.map(i => ({ json: i }));
-
Alert: Switch node —
ROLLOUT_FAILED→#firmware-ops-critical,DEGRADED/STALLED→#firmware-updates -
Log: Postgres —
INSERT INTO ota_events
Workflow 5: Weekly IoT Platform KPI Dashboard
The problem: Leadership needs a Monday morning report on connected devices, message volume, uptime, and customer growth. No one should be pulling this manually.
The workflow:
- Trigger: Schedule node — Monday 8:00 AM
- Query: Postgres node
SELECT
COUNT(DISTINCT device_id) AS connected_devices,
COUNT(DISTINCT customer_id) AS active_accounts,
SUM(messages_count) AS messages_this_week,
ROUND(AVG(uptime_pct), 2) AS avg_uptime_pct,
COUNT(DISTINCT CASE WHEN enrolled_at > NOW() - INTERVAL '7 days'
THEN device_id END) AS new_devices_7d
FROM device_weekly_stats
WHERE week_ending = DATE_TRUNC('week', NOW())
-
WoW comparison: Code node using
$getWorkflowStaticData("global")to store last week's values and compute deltas - Build HTML: Code node — professional email with metrics table, color-coded WoW indicators
- Email: Gmail node — BCC CTO, VP Eng, Head of Customer Success
-
Slack: One-liner to
#platform-metrics:Weekly IoT KPIs: 127,420 devices (+3.1%), 2.1B messages (+8.4%), 99.97% uptime. Full report in your inbox.
Getting Started
Import any of these workflows via Settings → Import Workflow in your n8n instance. Replace Slack channel names, Postgres connection strings, and API endpoints with yours.
These templates are available as ready-made, import-ready packs on FlowKit:
→ Browse FlowKit n8n automation templates — pre-built, documented, zero configuration headaches.
Tags: n8n, iot, automation, programming
Top comments (0)