DEV Community

Alex Kane
Alex Kane

Posted on

n8n for CleanTech & ClimateTech SaaS: 5 Automations That Scale Carbon Accounting and Clean Energy Platform Ops (Free Workflow JSON)

If you're building carbon accounting software and your automation stack sends Scope 2 emissions data through a third-party cloud platform, you just created a GDPR Art.28 sub-processor you didn't plan for.

And if you're on Zapier at scale — say, polling inverter APIs across a 500-site solar portfolio — you're paying $100K+/year in per-task fees. For a sustainability platform. The irony is not subtle.

This post covers five production-ready n8n workflows for CleanTech and ClimateTech SaaS companies: carbon accounting platforms, energy management software, ESG reporting tools, renewable energy monitoring systems, and sustainability analytics vendors.

Every workflow includes complete, import-ready JSON. No Zapier required.


Why CleanTech SaaS Vendors Are Moving to Self-Hosted n8n

1. Your data is commercially sensitive

Scope 3 supply chain emissions data reveals supplier relationships, production volumes, and logistics choices that competitors would pay for. Carbon credit portfolios are proprietary assets. SBTi target trajectories are IP. Routing any of this through Zapier or Make adds a cloud vendor to your data processing chain — one that may store workflow payloads for debugging.

2. The regulatory stack demands audit trails

  • EU CSRD/ESRS (mandatory for 50,000+ companies by 2026): requires documented, auditable data processing chains
  • SEC Climate Disclosure Rule: material climate risks must be reported with traceable data lineage
  • TCFD/SBTi: third-party verification requires defensible methodology documentation
  • ISO 14064: GHG inventories must have documented data collection and calculation procedures

Git-versioned n8n workflow JSON satisfies CM-3 configuration change control requirements better than any SaaS automation platform.

3. IoT sensor volume makes per-task pricing unviable

Scale Zapier cost/month n8n VPS cost/month
10K sensor readings/day ~$49 (Starter) ~$20 (all-in)
100K sensor readings/day ~$599 (Business) ~$20
1M sensor readings/day $2,000+ Enterprise ~$40 (larger VPS)
10M sensor readings/day Not viable ~$80 (scaled VPS)

A 500-site solar portfolio with 20 inverters each reporting every 5 minutes = 2.88M sensor readings/day. That is not a Zapier use case.

4. Self-hosting is the sustainable choice

Running automation on a single VPS uses a fraction of the energy of routing every task through multiple cloud data centers. For CleanTech SaaS, the Scope 2 footprint of your automation stack matters.


The 5 Workflows


Workflow 1: Energy Asset & IoT Sensor Health Monitor

Use case: Solar inverters, wind turbine sensors, EV charging stations, smart meters, and building management systems all expose health APIs. When a data feed goes silent, carbon calculations break and clients get wrong numbers. This workflow checks every asset endpoint every 5 minutes and pages your ops team before clients notice.

Nodes: Schedule Trigger (5min) → Google Sheets (asset inventory) → HTTP Request (health ping per asset) → Code (classify + dedup) → Filter (non-OK only) → Slack (#energy-ops-alerts) + Postgres (sla_events log)

{
  "name": "CleanTech - Energy Asset & IoT Sensor Health Monitor",
  "nodes": [
    { "id": "n1", "name": "Every 5 Minutes",
      "type": "n8n-nodes-base.scheduleTrigger",
      "parameters": { "rule": { "interval": [{ "field": "minutes", "minutesInterval": 5 }] } },
      "position": [250, 300] },
    { "id": "n2", "name": "Get Asset Inventory",
      "type": "n8n-nodes-base.googleSheets",
      "parameters": { "operation": "readRows", "documentId": "YOUR_SHEET_ID", "sheetName": "energy_assets" },
      "position": [450, 300] },
    { "id": "n3", "name": "Ping Asset Health API",
      "type": "n8n-nodes-base.httpRequest",
      "parameters": { "url": "={{ $json.api_endpoint }}/health", "method": "GET", "timeout": 10000, "onError": "continueErrorOutput" },
      "position": [650, 300] },
    { "id": "n4", "name": "Classify + Dedup",
      "type": "n8n-nodes-base.code",
      "parameters": { "jsCode": "const prev = $getWorkflowStaticData('global'); const results = []; for (const item of $input.all()) { const a = item.json; const key = 'alerted_' + a.asset_id; let status = 'OK'; if (a.error || (a.$response && a.$response.statusCode !== 200)) status = 'DOWN'; else if (a.response_time_ms > 5000) status = 'DEGRADED'; if (status !== 'OK') { const last = prev[key] || 0; if (Date.now() - last > 15*60*1000) { prev[key] = Date.now(); results.push({ json: { ...a, health_status: status } }); } } else { delete prev[key]; } } return results;" },
      "position": [850, 300] },
    { "id": "n5", "name": "Slack #energy-ops-alerts",
      "type": "n8n-nodes-base.slack",
      "parameters": { "channel": "#energy-ops-alerts", "text": "={{ $json.health_status === 'DOWN' ? '🚨 DOWN' : '⚠️ DEGRADED' }} *{{ $json.asset_name }}* | Type: {{ $json.asset_type }} | Region: {{ $json.region }}" },
      "position": [1050, 250] },
    { "id": "n6", "name": "Log to Postgres",
      "type": "n8n-nodes-base.postgres",
      "parameters": { "operation": "insert", "table": "asset_sla_events" },
      "position": [1050, 400] }
  ],
  "connections": {
    "Every 5 Minutes": { "main": [[{ "node": "Get Asset Inventory", "type": "main", "index": 0 }]] },
    "Get Asset Inventory": { "main": [[{ "node": "Ping Asset Health API", "type": "main", "index": 0 }]] },
    "Ping Asset Health API": { "main": [[{ "node": "Classify + Dedup", "type": "main", "index": 0 }]] },
    "Classify + Dedup": { "main": [[{ "node": "Slack #energy-ops-alerts", "type": "main", "index": 0 }, { "node": "Log to Postgres", "type": "main", "index": 0 }]] }
  }
}
Enter fullscreen mode Exit fullscreen mode

Key notes:

  • Sheets energy_assets tab: asset_id, asset_name, asset_type, api_endpoint, region
  • $getWorkflowStaticData dedup: suppresses repeat alerts per asset within 15-minute window
  • Postgres asset_sla_events table: ISO 14064 / FedRAMP POA&M audit evidence

Workflow 2: New CleanTech Client Onboarding & Activation Drip

Use case: When a carbon accounting client signs up, they need API credentials, a data mapping guide, and proactive check-ins to get their first GHG inventory running. Manual onboarding at scale breaks. This workflow automates the 3-touch sequence and notifies your CSM team when clients reach milestones.

Nodes: Google Sheets Trigger (new row) → Gmail (Day 0: credentials + quickstart) → Slack (CSM DM) → Wait 3d → Gmail (Day 3: integration check-in) → Wait 4d → Gmail (Day 7: first GHG inventory milestone) → Sheets (mark onboarding_complete)

{
  "name": "CleanTech - New Client Onboarding Drip",
  "nodes": [
    { "id": "n1", "name": "New Client in Sheets",
      "type": "n8n-nodes-base.googleSheetsTrigger",
      "parameters": { "documentId": "YOUR_SHEET_ID", "sheetName": "cleantech_clients", "triggerOn": "rowAdded" },
      "position": [250, 300] },
    { "id": "n2", "name": "Day 0 - API Credentials Email",
      "type": "n8n-nodes-base.gmail",
      "parameters": {
        "operation": "sendEmail",
        "toList": "={{ $json.contact_email }}",
        "subject": "Welcome to {{ $json.platform_name }} — Your API credentials and setup guide",
        "message": "<p>Hi {{ $json.contact_name }},</p><p>API key: <strong>{{ $json.api_key }}</strong></p><p>Webhook endpoint: <strong>{{ $json.webhook_url }}</strong></p><p>Setup guide: <a href='{{ $json.docs_url }}'>{{ $json.docs_url }}</a></p>",
        "emailType": "html" },
      "position": [450, 300] },
    { "id": "n3", "name": "Slack CSM DM",
      "type": "n8n-nodes-base.slack",
      "parameters": { "channel": "={{ $json.csm_slack_id }}", "text": "New client onboarded: *{{ $json.company_name }}* | {{ $json.contact_email }}" },
      "position": [450, 450] },
    { "id": "n4", "name": "Wait 3 Days", "type": "n8n-nodes-base.wait",
      "parameters": { "unit": "days", "amount": 3 }, "position": [650, 300] },
    { "id": "n5", "name": "Day 3 - Integration Check-In",
      "type": "n8n-nodes-base.gmail",
      "parameters": { "operation": "sendEmail", "toList": "={{ $json.contact_email }}",
        "subject": "Quick check-in — did you get your first data flowing?",
        "message": "<p>Hi {{ $json.contact_name }},</p><p>Just checking in — have you sent your first emission event to the API? Reply if you hit any snags with the data mapping guide.</p>" },
      "position": [850, 300] },
    { "id": "n6", "name": "Wait 4 Days", "type": "n8n-nodes-base.wait",
      "parameters": { "unit": "days", "amount": 4 }, "position": [1050, 300] },
    { "id": "n7", "name": "Day 7 - First GHG Inventory Guide",
      "type": "n8n-nodes-base.gmail",
      "parameters": { "operation": "sendEmail", "toList": "={{ $json.contact_email }}",
        "subject": "Your Week 1 milestone: run your first GHG inventory",
        "message": "<p>Hi {{ $json.contact_name }},</p><p>By now you should have Scope 1 and 2 data flowing. Here is how to generate your first GHG inventory report in the dashboard: [link]</p><p>Next: Scope 3 supply chain mapping.</p>" },
      "position": [1250, 300] },
    { "id": "n8", "name": "Mark Onboarded in Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "parameters": { "operation": "update", "documentId": "YOUR_SHEET_ID", "sheetName": "cleantech_clients" },
      "position": [1450, 300] }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Key notes:

  • Sheets cleantech_clients tab: client_id, company_name, contact_email, contact_name, api_key, webhook_url, csm_slack_id, platform_name, onboarding_complete
  • Customize the Day 7 email for your product's specific first-value milestone (first GHG report, first CSRD export, first carbon credit match)

Workflow 3: Carbon Reporting & Regulatory Deadline Tracker

Use case: EU CSRD filing deadlines, SEC Climate Disclosure submissions, SBTi target review dates, ISO 14064 audit windows, voluntary carbon registry reporting — missing any of these is a compliance failure that your clients pay for. This workflow tracks every deadline and escalates via the right channel at the right urgency tier.

Nodes: Schedule Trigger (weekdays 8AM) → Google Sheets (deadline list) → Code (classify OVERDUE/CRITICAL/URGENT/WARNING/NOTICE) → Filter → Switch (by urgency) → Slack (#compliance-critical) + Gmail (compliance officer with regulation-specific action items)

{
  "name": "CleanTech - Carbon Reporting & Regulatory Deadline Tracker",
  "nodes": [
    { "id": "n1", "name": "Weekdays 8AM",
      "type": "n8n-nodes-base.scheduleTrigger",
      "parameters": { "rule": { "interval": [{ "field": "cronExpression", "expression": "0 8 * * 1-5" }] } },
      "position": [250, 300] },
    { "id": "n2", "name": "Get Compliance Deadlines",
      "type": "n8n-nodes-base.googleSheets",
      "parameters": { "operation": "readRows", "documentId": "YOUR_SHEET_ID", "sheetName": "compliance_deadlines" },
      "position": [450, 300] },
    { "id": "n3", "name": "Classify Urgency + Action",
      "type": "n8n-nodes-base.code",
      "parameters": { "jsCode": "const today = new Date(); const actions = { EU_CSRD_ESRS: 'Prepare ESRS E1-E5 disclosures + engage external assurance provider.', SEC_CLIMATE_DISCLOSURE: 'Finalize 10-K climate risk section. Confirm Scope 1/2 data with CFO.', SBTI_TARGET_REVIEW: 'Run SBTi TARGET Tracker. Verify near-term vs net-zero trajectory.', ISO_14064_AUDIT: 'Prepare GHG inventory docs, calculation methodology, data sources.', VOLUNTARY_REGISTRY: 'Compile carbon credit issuance report. Submit via Verra/Gold Standard portal.', SOC2_EVIDENCE: 'Collect n8n workflow changelog (git log) + Postgres audit table for CC6.2.', GDPR_DPA_RENEWAL: 'Review and renew Data Processing Agreements with ESG data vendors.' }; const results = []; for (const item of $input.all()) { const d = item.json; const daysLeft = Math.ceil((new Date(d.deadline_date) - today) / 86400000); let urgency = 'NOTICE'; if (daysLeft < 0) urgency = 'OVERDUE'; else if (daysLeft <= 7) urgency = 'CRITICAL'; else if (daysLeft <= 21) urgency = 'URGENT'; else if (daysLeft <= 60) urgency = 'WARNING'; else if (daysLeft <= 90) urgency = 'NOTICE'; else continue; results.push({ json: { ...d, days_left: daysLeft, urgency, action_item: actions[d.regulation_type] || 'Review compliance requirements.' } }); } return results;" },
      "position": [650, 300] },
    { "id": "n4", "name": "Switch by Urgency",
      "type": "n8n-nodes-base.switch",
      "parameters": { "dataType": "string", "value1": "={{ $json.urgency }}", "rules": { "rules": [{ "value2": "OVERDUE", "output": 0 }, { "value2": "CRITICAL", "output": 0 }, { "value2": "URGENT", "output": 1 }, { "value2": "WARNING", "output": 2 }] } },
      "position": [850, 300] },
    { "id": "n5", "name": "Slack #compliance-critical",
      "type": "n8n-nodes-base.slack",
      "parameters": { "channel": "#compliance-critical", "text": "={{ $json.urgency === 'OVERDUE' ? '🚨 OVERDUE' : '🔴 CRITICAL' }} *{{ $json.regulation_type }}* deadline: {{ $json.deadline_date }} | *Action:* {{ $json.action_item }}" },
      "position": [1050, 200] },
    { "id": "n6", "name": "Gmail Compliance Officer",
      "type": "n8n-nodes-base.gmail",
      "parameters": { "operation": "sendEmail", "toList": "={{ $json.owner_email }}",
        "subject": "[{{ $json.urgency }}] {{ $json.regulation_type }} — {{ $json.days_left < 0 ? 'OVERDUE' : $json.days_left + ' days remaining' }}",
        "message": "<p><strong>Regulation:</strong> {{ $json.regulation_type }}</p><p><strong>Deadline:</strong> {{ $json.deadline_date }}</p><p><strong>Action:</strong> {{ $json.action_item }}</p>" },
      "position": [1050, 400] }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Sheets tab structure (compliance_deadlines): regulation_type, deadline_date (YYYY-MM-DD), client_name, owner_email, notes

Regulation types to track:

  • EU_CSRD_ESRS — mandatory ESG disclosure (50,000+ EU companies by 2026)
  • SEC_CLIMATE_DISCLOSURE — material climate risk (SEC Final Rule 2024)
  • SBTI_TARGET_REVIEW — annual near-term/net-zero target verification
  • ISO_14064_AUDIT — GHG inventory third-party verification window
  • VOLUNTARY_REGISTRY — Verra/Gold Standard/CAR carbon credit issuance reporting
  • GDPR_DPA_RENEWAL — annual Data Processing Agreement reviews with ESG data vendors

Workflow 4: GHG Emission Anomaly Alert

Use case: When a client's Scope 1 emissions spike 3x overnight, it usually means one of three things: a sensor malfunction, a data ingestion bug in your platform, or a real emission event that needs immediate attention. Your platform should catch it before the client does. This workflow runs a statistical z-score test against 7-day baselines and alerts your data ops team.

Nodes: Schedule Trigger (15min) → Postgres (7-day baseline per facility) → Postgres (last 1h actuals) → Merge → Code (z-score anomaly detect + dedup) → Slack (#emissions-ops)

{
  "name": "CleanTech - GHG Emission Anomaly Alert",
  "nodes": [
    { "id": "n1", "name": "Every 15 Minutes",
      "type": "n8n-nodes-base.scheduleTrigger",
      "parameters": { "rule": { "interval": [{ "field": "minutes", "minutesInterval": 15 }] } },
      "position": [250, 300] },
    { "id": "n2", "name": "7-Day Emission Baselines",
      "type": "n8n-nodes-base.postgres",
      "parameters": { "operation": "executeQuery", "query": "SELECT facility_id, emission_source, AVG(co2e_tonnes) as avg_co2e, STDDEV(co2e_tonnes) as std_co2e FROM emission_events WHERE recorded_at > NOW() - INTERVAL '7 days' GROUP BY facility_id, emission_source" },
      "position": [450, 200] },
    { "id": "n3", "name": "Last 1h Actual Readings",
      "type": "n8n-nodes-base.postgres",
      "parameters": { "operation": "executeQuery", "query": "SELECT facility_id, emission_source, SUM(co2e_tonnes) as actual_co2e FROM emission_events WHERE recorded_at > NOW() - INTERVAL '1 hour' GROUP BY facility_id, emission_source" },
      "position": [450, 400] },
    { "id": "n4", "name": "Merge Baseline + Actual",
      "type": "n8n-nodes-base.merge",
      "parameters": { "mode": "combine", "combineBy": "combineByFields", "fields": "facility_id,emission_source" },
      "position": [650, 300] },
    { "id": "n5", "name": "Z-Score Anomaly Detect",
      "type": "n8n-nodes-base.code",
      "parameters": { "jsCode": "const prev = $getWorkflowStaticData('global'); const results = []; for (const item of $input.all()) { const d = item.json; if (!d.std_co2e || d.std_co2e === 0) continue; const z = Math.abs((d.actual_co2e - d.avg_co2e) / d.std_co2e); let level = null; if (z >= 3) level = 'CRITICAL'; else if (z >= 2) level = 'HIGH'; else if (z >= 1.5) level = 'WATCH'; if (!level) continue; const key = 'anomaly_' + d.facility_id + '_' + d.emission_source; const last = prev[key] || 0; if (Date.now() - last < 60*60*1000) continue; prev[key] = Date.now(); results.push({ json: { ...d, z_score: z.toFixed(2), anomaly_level: level } }); } return results;" },
      "position": [850, 300] },
    { "id": "n6", "name": "Slack #emissions-ops",
      "type": "n8n-nodes-base.slack",
      "parameters": { "channel": "#emissions-ops", "text": "={{ $json.anomaly_level === 'CRITICAL' ? '🚨' : $json.anomaly_level === 'HIGH' ? '⚠️' : '👀' }} *{{ $json.anomaly_level }}* GHG anomaly | Facility: {{ $json.facility_id }} | Source: {{ $json.emission_source }} | Actual: {{ $json.actual_co2e }} vs baseline avg: {{ $json.avg_co2e }} tCO2e/h | Z-score: {{ $json.z_score }}sigma" },
      "position": [1050, 300] }
  ],
  "connections": {
    "Every 15 Minutes": { "main": [[{ "node": "7-Day Emission Baselines", "type": "main", "index": 0 }, { "node": "Last 1h Actual Readings", "type": "main", "index": 0 }]] },
    "7-Day Emission Baselines": { "main": [[{ "node": "Merge Baseline + Actual", "type": "main", "index": 0 }]] },
    "Last 1h Actual Readings": { "main": [[{ "node": "Merge Baseline + Actual", "type": "main", "index": 1 }]] },
    "Merge Baseline + Actual": { "main": [[{ "node": "Z-Score Anomaly Detect", "type": "main", "index": 0 }]] },
    "Z-Score Anomaly Detect": { "main": [[{ "node": "Slack #emissions-ops", "type": "main", "index": 0 }]] }
  }
}
Enter fullscreen mode Exit fullscreen mode

What this catches:

  • Faulty IoT sensor sending 100x normal readings (data quality bug in your ingestion pipeline)
  • Real emission spike from combustion equipment outside normal operating range
  • Missing data gap (zero readings where values expected — negative anomaly direction)

Threshold tuning: z >= 3sigma = CRITICAL (investigate immediately), z >= 2sigma = HIGH (same-day), z >= 1.5sigma = WATCH (log and trend).


Workflow 5: Weekly CleanTech Platform KPI Dashboard

Use case: Every Monday your VP of Customer Success, CTO, and CFO should get one email with WoW comparisons for the metrics that matter — active clients, carbon credits under management, total GHG inventory tonnage, integration health rate, MRR. No Metabase login required.

Nodes: Schedule Trigger (Monday 8AM) → Postgres x2 parallel (this week + last week) → Merge → Code (WoW% deltas + HTML table) → Gmail (leadership BCC) → Slack (#platform-metrics)

{
  "name": "CleanTech - Weekly Platform KPI Dashboard",
  "nodes": [
    { "id": "n1", "name": "Monday 8AM",
      "type": "n8n-nodes-base.scheduleTrigger",
      "parameters": { "rule": { "interval": [{ "field": "cronExpression", "expression": "0 8 * * 1" }] } },
      "position": [250, 300] },
    { "id": "n2", "name": "This Week Stats",
      "type": "n8n-nodes-base.postgres",
      "parameters": { "operation": "executeQuery", "query": "SELECT COUNT(DISTINCT client_id) as active_clients, SUM(carbon_credits_managed) as credits_managed, SUM(ghg_inventory_tonnes) as total_ghg_tonnes, ROUND(AVG(CASE WHEN integration_status='healthy' THEN 1.0 ELSE 0.0 END)*100,1) as integration_health_pct, SUM(mrr_usd) as mrr FROM cleantech_client_stats WHERE week_start = date_trunc('week', NOW())" },
      "position": [450, 200] },
    { "id": "n3", "name": "Last Week Stats",
      "type": "n8n-nodes-base.postgres",
      "parameters": { "operation": "executeQuery", "query": "SELECT COUNT(DISTINCT client_id) as active_clients, SUM(carbon_credits_managed) as credits_managed, SUM(ghg_inventory_tonnes) as total_ghg_tonnes, ROUND(AVG(CASE WHEN integration_status='healthy' THEN 1.0 ELSE 0.0 END)*100,1) as integration_health_pct, SUM(mrr_usd) as mrr FROM cleantech_client_stats WHERE week_start = date_trunc('week', NOW()) - INTERVAL '1 week'" },
      "position": [450, 400] },
    { "id": "n4", "name": "Merge This & Last Week",
      "type": "n8n-nodes-base.merge",
      "parameters": { "mode": "combine", "combineBy": "combineByPosition" },
      "position": [650, 300] },
    { "id": "n5", "name": "Compute WoW Deltas + HTML",
      "type": "n8n-nodes-base.code",
      "parameters": { "jsCode": "const items = $input.all(); const tw = items[0].json; const lw = items[1] ? items[1].json : {}; function delta(cur, prev) { if (!prev || prev === 0) return 'N/A'; const pct = ((cur - prev) / prev * 100).toFixed(1); return (pct > 0 ? '+' : '') + pct + '%'; } const html = '<h2>CleanTech Platform — Weekly KPIs</h2><table border=1 cellpadding=8><tr><th>Metric</th><th>This Week</th><th>Last Week</th><th>WoW</th></tr>' + '<tr><td>Active Clients</td><td>' + tw.active_clients + '</td><td>' + (lw.active_clients||'—') + '</td><td>' + delta(tw.active_clients,lw.active_clients) + '</td></tr>' + '<tr><td>Carbon Credits Managed (tCO2e)</td><td>' + Number(tw.credits_managed||0).toLocaleString() + '</td><td>' + Number(lw.credits_managed||0).toLocaleString() + '</td><td>' + delta(tw.credits_managed,lw.credits_managed) + '</td></tr>' + '<tr><td>GHG Inventory Processed (tCO2e)</td><td>' + Number(tw.total_ghg_tonnes||0).toLocaleString() + '</td><td>' + Number(lw.total_ghg_tonnes||0).toLocaleString() + '</td><td>' + delta(tw.total_ghg_tonnes,lw.total_ghg_tonnes) + '</td></tr>' + '<tr><td>Integration Health</td><td>' + tw.integration_health_pct + '%</td><td>' + (lw.integration_health_pct||'—') + '%</td><td>' + delta(tw.integration_health_pct,lw.integration_health_pct) + '</td></tr>' + '<tr><td>MRR</td><td>$' + Number(tw.mrr||0).toLocaleString() + '</td><td>$' + Number(lw.mrr||0).toLocaleString() + '</td><td>' + delta(tw.mrr,lw.mrr) + '</td></tr></table>'; return [{ json: { ...tw, html_report: html, wow_mrr: delta(tw.mrr,lw.mrr) } }];" },
      "position": [850, 300] },
    { "id": "n6", "name": "Gmail Leadership",
      "type": "n8n-nodes-base.gmail",
      "parameters": { "operation": "sendEmail", "toList": "vp-cs@yourcompany.com", "bccList": "cto@yourcompany.com,cfo@yourcompany.com", "subject": "CleanTech Platform — Weekly KPIs", "message": "={{ $json.html_report }}", "emailType": "html" },
      "position": [1050, 200] },
    { "id": "n7", "name": "Slack #platform-metrics",
      "type": "n8n-nodes-base.slack",
      "parameters": { "channel": "#platform-metrics", "text": "Weekly KPIs: {{ $json.active_clients }} clients | {{ $json.credits_managed }} tCO2e credits | Integration health: {{ $json.integration_health_pct }}% | MRR: ${{ $json.mrr }} ({{ $json.wow_mrr }} WoW)" },
      "position": [1050, 400] }
  ],
  "connections": {
    "Monday 8AM": { "main": [[{ "node": "This Week Stats", "type": "main", "index": 0 }, { "node": "Last Week Stats", "type": "main", "index": 0 }]] },
    "This Week Stats": { "main": [[{ "node": "Merge This & Last Week", "type": "main", "index": 0 }]] },
    "Last Week Stats": { "main": [[{ "node": "Merge This & Last Week", "type": "main", "index": 1 }]] },
    "Merge This & Last Week": { "main": [[{ "node": "Compute WoW Deltas + HTML", "type": "main", "index": 0 }]] },
    "Compute WoW Deltas + HTML": { "main": [[{ "node": "Gmail Leadership", "type": "main", "index": 0 }, { "node": "Slack #platform-metrics", "type": "main", "index": 0 }]] }
  }
}
Enter fullscreen mode Exit fullscreen mode

n8n vs Zapier vs Make for CleanTech SaaS

Factor n8n (self-hosted) Zapier Make
GHG/ESG data sovereignty Stays in your VPC Routes through Zapier servers Routes through Make EU/US servers
GDPR Art.28 sub-processor No additional vendor Zapier processes personal ESG data Make processes personal ESG data
EU CSRD audit trail Git-versioned JSON workflows No version control No version control
IoT sensor volume pricing $0 marginal cost Per-task billing (unviable at scale) Per-operation billing
On-prem / air-gapped deploy Docker/Kubernetes Cloud only Cloud only
Custom GHG calculation logic Full Code node (Node.js/Python) Limited code steps Limited code steps
Postgres/TimescaleDB native Yes Custom auth required Custom auth required
Cost at 1M events/day ~$40/mo VPS $2,000+/mo Enterprise $1,500+/mo

Getting Started

  1. Install n8n — local: npx n8n | production:
   docker run -it --rm --name n8n -p 5678:5678 -v ~/.n8n:/home/node/.n8n docker.n8n.io/n8nio/n8n
Enter fullscreen mode Exit fullscreen mode
  1. Import a workflow — copy the JSON above, open n8n, click Import Workflow

  2. Configure credentials — Google Sheets OAuth, Gmail OAuth, Postgres connection, Slack Bot Token

  3. Customize schema — update table names, sheet IDs, API endpoints, and Slack channels


13 Production-Ready n8n Templates for CleanTech & SaaS Teams

If you want to skip the build phase, I've packaged 13 complete n8n workflow templates at FlowKit on Gumroad.

Each template includes:

  • Complete import-ready JSON (paste into n8n, import, done)
  • Setup guide: which credentials to configure, which fields to customize
  • 3 workflow variants per use case

Pricing: $12-$29 per template, or $97 for the complete bundle.


Questions about any of these workflows for your CleanTech stack? Drop them in the comments.

Top comments (0)