DEV Community

Alex Kane
Alex Kane

Posted on

n8n for IoT Platform Companies: 5 Automations That Scale Device Ops and Customer Success (Free Workflow JSON)

If you're building an IoT platform — device management SaaS, industrial IoT middleware, connected product infrastructure, smart building software — you're managing thousands of devices, complex onboarding sequences, and real-time anomaly detection that Zapier and Make fundamentally can't handle.

Self-hosted n8n runs inside your VPC. Device telemetry, sensor readings, customer fleet data, and firmware deployment logs never leave your infrastructure — which matters for enterprise security reviews, GDPR Article 44-46, and IEC 62443 compliance.

Here are 5 production-ready n8n workflows built specifically for IoT platform companies. Every JSON is import-ready: go to Settings → Import Workflow in n8n and paste.


1. Device Connectivity Health Monitor

The problem: Devices go offline. Your customers don't know until they check manually — or until it causes a real problem. You need proactive alerting that catches connectivity failures before your customers do, without polling each device in a fragile cron job.

The workflow:

  1. Schedule Trigger fires every 5 minutes
  2. Google Sheets returns the list of active customer devices (device_id, customer_id, customer_email, last_seen_ts, expected_ping_interval_seconds)
  3. Code node computes each device's offline status:
    • OFFLINE: now - last_seen_ts > expected_ping_interval_seconds × 3
    • DEGRADED: now - last_seen_ts > expected_ping_interval_seconds × 1.5
    • OK: within normal range
  4. Filter keeps only OFFLINE and DEGRADED devices
  5. Slack (#platform-ops): [OFFLINE] device_id for customer_name — last seen {N} min ago
  6. Postgres logs to device_incidents table with device_id, customer_id, status, detected_at
  7. Gmail to customer contact (if OFFLINE > 15 min): "We've detected your device {device_id} has gone offline — our team is investigating"
{
  "name": "Device Connectivity Health Monitor",
  "nodes": [
    {"id":"1","type":"n8n-nodes-base.scheduleTrigger","parameters":{"rule":{"interval":[{"field":"minutes","minutesInterval":5}]}},"position":[100,300]},
    {"id":"2","type":"n8n-nodes-base.googleSheets","parameters":{"operation":"read","documentId":"YOUR_SHEET_ID","sheetName":"active_devices"},"position":[300,300]},
    {"id":"3","type":"n8n-nodes-base.code","parameters":{"jsCode":"const now = Date.now() / 1000;\nreturn $input.all().map(item => {\n  const d = item.json;\n  const lag = now - d.last_seen_ts;\n  const interval = d.expected_ping_interval_seconds || 60;\n  let status = 'OK';\n  if (lag > interval * 3) status = 'OFFLINE';\n  else if (lag > interval * 1.5) status = 'DEGRADED';\n  return { json: { ...d, status, lag_seconds: Math.round(lag) } };\n}).filter(i => i.json.status !== 'OK');"},"position":[500,300]},
    {"id":"4","type":"n8n-nodes-base.slack","parameters":{"channel":"#platform-ops","text":"={{'[' + $json.status + '] device ' + $json.device_id + ' for ' + $json.customer_name + ' — last seen ' + Math.round($json.lag_seconds/60) + 'min ago'}}"},"position":[700,300]}
  ],
  "connections":{"1":{"main":[[{"node":"2"}]]},"2":{"main":[[{"node":"3"}]]},"3":{"main":[[{"node":"4"}]]}}
}
Enter fullscreen mode Exit fullscreen mode

2. New Customer Device Onboarding Drip

The problem: When a customer provisions their first device, you need to make them successful fast. Manual follow-up gets missed. A generic "welcome email" isn't enough. You need a timed sequence that walks them from first connection to active user in 8 days.

The workflow:

  1. Webhook receives device.provisioned event from your platform (device_id, customer_id, customer_email, customer_name, api_key)
  2. Gmail Day 0: "Your device is online — here's your API key and quickstart guide"
  3. Google Sheets logs (customer_id, device_id, provisioned_at, onboarding_step='day0')
  4. Wait 3 days
  5. Gmail Day 3: "Top 3 things customers do in their first week" — integration patterns, data export, alert config
  6. Wait 4 days
  7. Gmail Day 7: "Are you getting value? Here's how to set up your first automated alert" — links to docs + store template
  8. Google Sheets marks onboarding_complete = true
  9. Slack (#customer-success): Onboarding complete: {customer_name} — {device_count} devices active
{
  "name": "Device Onboarding Drip",
  "nodes": [
    {"id":"1","type":"n8n-nodes-base.webhook","parameters":{"path":"device-provisioned","httpMethod":"POST"},"position":[100,300]},
    {"id":"2","type":"n8n-nodes-base.gmail","parameters":{"operation":"send","to":"={{ $json.customer_email }}","subject":"Your device {{ $json.device_id }} is online — getting started","message":"Hi {{ $json.customer_name }},\n\nYour device is provisioned and online. Your API key: {{ $json.api_key }}\n\nQuickstart: docs.yourplatform.com/quickstart"},"position":[300,300]},
    {"id":"3","type":"n8n-nodes-base.wait","parameters":{"amount":3,"unit":"days"},"position":[500,300]},
    {"id":"4","type":"n8n-nodes-base.gmail","parameters":{"operation":"send","to":"={{ $json.customer_email }}","subject":"3 things to try this week with your IoT platform","message":"Hi {{ $json.customer_name }},\n\nHere are the top 3 things our customers set up in their first week: 1) Real-time anomaly alerts, 2) Data export to your data warehouse, 3) Multi-device dashboards. Full guide: docs.yourplatform.com/week1"},"position":[700,300]},
    {"id":"5","type":"n8n-nodes-base.wait","parameters":{"amount":4,"unit":"days"},"position":[900,300]},
    {"id":"6","type":"n8n-nodes-base.gmail","parameters":{"operation":"send","to":"={{ $json.customer_email }}","subject":"Set up your first automated alert in 5 minutes","message":"Hi {{ $json.customer_name }},\n\nThe most common thing customers automate first: automatic Slack alert when a device goes offline. Here's the exact workflow JSON: stripeai.gumroad.com/l/djazml"},"position":[1100,300]}
  ],
  "connections":{"1":{"main":[[{"node":"2"}]]},"2":{"main":[[{"node":"3"}]]},"3":{"main":[[{"node":"4"}]]},"4":{"main":[[{"node":"5"}]]},"5":{"main":[[{"node":"6"}]]}}
}
Enter fullscreen mode Exit fullscreen mode

3. Device Anomaly Alert & Classification Pipeline

The problem: Your platform ingests millions of telemetry events. Somewhere in that stream, devices are malfunctioning — temperature spikes, pressure drops, current anomalies, connection resets. You need to catch CRITICAL events in real time, route to the right team, and notify the customer — without human review of every event.

The workflow:

  1. Webhook receives telemetry event from your platform (device_id, customer_id, metric_name, value, threshold, unit, timestamp)
  2. Code node classifies severity:
    • CRITICAL: value > threshold × 2.0 → page on-call + email customer
    • HIGH: value > threshold × 1.5 → Slack alert + log
    • MEDIUM: value > threshold × 1.1 → log + daily digest
  3. Switch routes by severity
  4. CRITICAL branch:
    • Slack (#noc-urgent): [CRITICAL ANOMALY] device_id: {metric_name} = {value}{unit} (threshold: {threshold}) @channel
    • Gmail to customer: "We've detected a critical anomaly on your device — our team is investigating"
    • Postgres inserts into device_incidents with severity, metric, value, customer_id
  5. HIGH branch:
    • Slack (#platform-ops): [HIGH] device_id: {metric_name} = {value} — above threshold
    • Postgres logs
  6. MEDIUM branch: Postgres log only
{
  "name": "Device Anomaly Alert Pipeline",
  "nodes": [
    {"id":"1","type":"n8n-nodes-base.webhook","parameters":{"path":"telemetry-event","httpMethod":"POST"},"position":[100,300]},
    {"id":"2","type":"n8n-nodes-base.code","parameters":{"jsCode":"const d = $json;\nconst ratio = d.value / d.threshold;\nlet severity;\nif (ratio >= 2.0) severity = 'CRITICAL';\nelse if (ratio >= 1.5) severity = 'HIGH';\nelse if (ratio >= 1.1) severity = 'MEDIUM';\nelse severity = 'OK';\nreturn [{ json: { ...d, severity, ratio: ratio.toFixed(2) } }];"},"position":[300,300]},
    {"id":"3","type":"n8n-nodes-base.switch","parameters":{"dataType":"string","value1":"={{ $json.severity }}","rules":{"rules":[{"value2":"CRITICAL"},{"value2":"HIGH"},{"value2":"MEDIUM"}]}},"position":[500,300]},
    {"id":"4","type":"n8n-nodes-base.slack","parameters":{"channel":"#noc-urgent","text":"=<!channel> [CRITICAL ANOMALY] {{ $json.device_id }}: {{ $json.metric_name }} = {{ $json.value }}{{ $json.unit }} (threshold: {{ $json.threshold }})"},"position":[700,200]}
  ],
  "connections":{"1":{"main":[[{"node":"2"}]]},"2":{"main":[[{"node":"3"}]]},"3":{"main":[[{"node":"4"},{"node":"4"},{"node":"4"}]]}}
}
Enter fullscreen mode Exit fullscreen mode

4. Firmware Update Rollout Tracker

The problem: You push a firmware update to 10,000 devices. You need to know: what percentage has applied it? Are there stuck devices? Did any devices fail the update and need rollback? Manual spot-checks don't scale.

The workflow:

  1. Webhook receives firmware.deployment.started (deployment_id, target_device_count, firmware_version, customer_id)
  2. Google Sheets logs deployment start (deployment_id, target, started_at, status='in_progress')
  3. Wait 10 minutes
  4. HTTP Request to your platform API: GET /deployments/{deployment_id}/status → returns {devices_updated, devices_failed, devices_pending}
  5. Code node computes pct_updated = devices_updated / target_device_count
  6. IF pct_updated >= 0.95:
    • Slack (#platform-ops): Firmware {firmware_version} rollout complete: {pct}% updated, {failed} failed
    • Google Sheets updates status='complete'
  7. ELSE (still in progress):
    • IF elapsed > 2 hours AND pct_updated < 0.60: Slack (#platform-ops) WARN: rollout stalled
    • Wait 10 minutes → loop back to step 4
{
  "name": "Firmware Rollout Tracker",
  "nodes": [
    {"id":"1","type":"n8n-nodes-base.webhook","parameters":{"path":"firmware-deployment","httpMethod":"POST"},"position":[100,300]},
    {"id":"2","type":"n8n-nodes-base.wait","parameters":{"amount":10,"unit":"minutes"},"position":[300,300]},
    {"id":"3","type":"n8n-nodes-base.httpRequest","parameters":{"method":"GET","url":"={{ 'https://api.yourplatform.com/deployments/' + $json.deployment_id + '/status'}}","authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"position":[500,300]},
    {"id":"4","type":"n8n-nodes-base.code","parameters":{"jsCode":"const d = $json;\nconst pct = d.devices_updated / d.target_device_count;\nreturn [{ json: { ...d, pct_updated: pct, pct_str: (pct*100).toFixed(1)+'%' } }];"},"position":[700,300]},
    {"id":"5","type":"n8n-nodes-base.if","parameters":{"conditions":{"number":[{"value1":"={{ $json.pct_updated }}","operation":"largerEqual","value2":0.95}]}},"position":[900,300]},
    {"id":"6","type":"n8n-nodes-base.slack","parameters":{"channel":"#platform-ops","text":"=Firmware {{ $json.firmware_version }} rollout complete: {{ $json.pct_str }} updated, {{ $json.devices_failed }} failed"},"position":[1100,200]}
  ],
  "connections":{"1":{"main":[[{"node":"2"}]]},"2":{"main":[[{"node":"3"}]]},"3":{"main":[[{"node":"4"}]]},"4":{"main":[[{"node":"5"}]]},"5":{"main":[[{"node":"6"}],[{"node":"2"}]]}}
}
Enter fullscreen mode Exit fullscreen mode

5. Weekly IoT Platform KPI Dashboard

The problem: Your CEO, VP Engineering, and CS team all need a weekly snapshot: How many devices are active? What's the uptime SLA? How many new customers provisioned devices this week? How many incidents were triggered? No one wants to dig through dashboards manually.

The workflow:

  1. Schedule Trigger fires every Monday at 8AM
  2. Postgres query #1: SELECT COUNT(*) active_devices, COUNT(DISTINCT customer_id) active_customers, AVG(uptime_pct) avg_uptime FROM device_health WHERE last_seen_ts > NOW() - INTERVAL '7 days'
  3. Postgres query #2: SELECT COUNT(*) new_provisioned, COUNT(*) incidents_critical, COUNT(*) incidents_high FROM device_events WHERE event_ts > NOW() - INTERVAL '7 days'
  4. Merge both result sets
  5. Code node builds HTML report with WoW% comparison (using $getWorkflowStaticData('global') for last week's numbers)
  6. Gmail to leadership BCC: full HTML report
  7. Slack (#platform): one-liner: Weekly: {active_devices} devices active across {active_customers} customers, {incidents_critical} critical incidents, {avg_uptime}% avg uptime
  8. Code node saves this week's numbers to static data for next week's WoW comparison
{
  "name": "Weekly IoT Platform KPI Report",
  "nodes": [
    {"id":"1","type":"n8n-nodes-base.scheduleTrigger","parameters":{"rule":{"interval":[{"field":"weeks","weeksInterval":1,"triggerAtDay":[1],"triggerAtHour":8}]}},"position":[100,300]},
    {"id":"2","type":"n8n-nodes-base.postgres","parameters":{"operation":"executeQuery","query":"SELECT COUNT(*) active_devices, COUNT(DISTINCT customer_id) active_customers, ROUND(AVG(uptime_pct)::numeric,2) avg_uptime FROM device_health WHERE last_seen_ts > NOW() - INTERVAL '7 days'"},"position":[300,300]},
    {"id":"3","type":"n8n-nodes-base.code","parameters":{"jsCode":"const d = $json;\nconst prev = $getWorkflowStaticData('global');\nconst wow = (cur, p) => p ? (((cur-p)/p)*100).toFixed(1)+'%' : 'N/A';\nconst html = `<h2>IoT Platform Weekly Report</h2><table><tr><th>Metric</th><th>This Week</th><th>WoW</th></tr><tr><td>Active Devices</td><td>${d.active_devices}</td><td>${wow(d.active_devices, prev.active_devices)}</td></tr><tr><td>Avg Uptime</td><td>${d.avg_uptime}%</td><td>-</td></tr></table>`;\nreturn [{ json: { ...d, html_report: html } }];"},"position":[500,300]},
    {"id":"4","type":"n8n-nodes-base.gmail","parameters":{"operation":"send","to":"leadership@yourcompany.com","subject":"=IoT Platform Weekly — {{ $now.toFormat('MMM d') }}","message":"={{ $json.html_report }}","options":{"appendAttribution":false}},"position":[700,300]},
    {"id":"5","type":"n8n-nodes-base.slack","parameters":{"channel":"#platform","text":"=Weekly: {{ $json.active_devices }} devices active across {{ $json.active_customers }} customers — {{ $json.avg_uptime }}% avg uptime"},"position":[900,300]}
  ],
  "connections":{"1":{"main":[[{"node":"2"}]]},"2":{"main":[[{"node":"3"}]]},"3":{"main":[[{"node":"4"}]]},"4":{"main":[[{"node":"5"}]]}}
}
Enter fullscreen mode Exit fullscreen mode

Why IoT platforms choose self-hosted n8n

If you're routing device telemetry through Zapier or Make:

Concern Zapier/Make n8n self-hosted
Data egress Telemetry transits US cloud servers Stays inside your VPC
Enterprise security reviews Data processor risk Eliminated — no third-party processor
GDPR Article 44-46 International transfer risk Data residency in your region
IEC 62443 / NERC CIP Non-compliant for OT environments Air-gapped deployment supported
Event volume Rate limits hit at scale No per-task limits
Custom logic Limited code nodes Full JS/Python Code nodes

Where to get these workflows

All 5 workflows above are available as ready-to-import JSON at FlowKit — stripeai.gumroad.com.

The store has 11 more automation templates covering:

  • Email Auto-Responder ($15)
  • AI Customer Support Bot ($29)
  • Lead Capture to CRM ($19)
  • Appointment Reminder System ($15)
  • And more

Or grab the Complete Bundle — all templates at a discount.


Built these for your own platform? Drop your use case in the comments — I read every one.

Top comments (0)