If you're building physical risk analytics software — climate scenario modeling, TCFD reporting tools, catastrophe exposure platforms, or nature-related risk products — you already know the data problem.
TCFD wants scenario analysis documented and reproducible. SEC Rule 33-11275 wants climate-related disclosures that are material and accurate. The EU Taxonomy wants climate adaptation activity evidence chains. TNFD wants LEAP framework compliance.
Every time your customer's physical risk data flows through a cloud iPaaS — Zapier, Make, even Workato — you're creating a chain-of-custody problem that TCFD auditors, SEC examiners, and EU taxonomy supervisors will ask about.
The TCFD audit trail question: "Show me every transformation applied to your physical risk scenario data from ingestion to disclosure." If the answer includes "it passed through Zapier's cloud," the auditor writes a finding.
Self-hosted n8n solves this: every workflow transformation is a git commit, every run is logged in your infrastructure, every data flow stays inside your compliance boundary.
Here are 5 production-ready workflows for ClimateRisk and Physical Risk Analytics SaaS vendors.
Workflow 1: Customer Onboarding Drip — 7-Tier Segmented with Compliance Flags
ClimateRisk SaaS customers range from insurance underwriters who need Swiss Re sigma calibration to municipal climate planners who need FEMA NFIP flood zone integration. One generic onboarding email fails all of them.
This workflow segments across 7 customer tiers and injects relevant compliance framing on Day 0:
| Tier | Day 3 Onboarding Hook |
|---|---|
INSURANCE_UNDERWRITING_SAAS |
FEMA flood zone ingestion + Swiss Re sigma calibration |
REAL_ESTATE_CLIMATE_RISK_SAAS |
FEMA FIRM integration + IPCC AR6 sea-level pathways |
FINANCIAL_PORTFOLIO_RISK_SAAS |
NGFS scenario ingestion + SEC Rule 33-11275 disclosure workflow |
INFRASTRUCTURE_RESILIENCE_SAAS |
TNFD LEAP framework + FEMA hazard layer API |
MUNICIPAL_CLIMATE_ADAPTATION_SAAS |
NOAA NWS API + FEMA NFIP Community Rating System |
SUPPLY_CHAIN_PHYSICAL_RISK_SAAS |
TCFD value-chain scenario analysis |
CLIMATERISK_STARTUP_SAAS |
EU Taxonomy Art.10 climate adaptation documentation |
Import-ready workflow JSON:
{
"name": "ClimateRisk SaaS \u2014 Customer Onboarding Drip",
"nodes": [
{
"id": "1",
"name": "Sheets Trigger \u2014 New Customer",
"type": "n8n-nodes-base.googleSheetsTrigger",
"parameters": {
"sheetId": "{{YOUR_SHEET_ID}}",
"range": "customers!A:Z",
"event": "rowAdded"
},
"position": [
240,
300
]
},
{
"id": "2",
"name": "Code \u2014 Segment & Flags",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const r=$input.first().json;const tier=r.customer_tier||'CLIMATERISK_STARTUP_SAAS';const flags={TCFD_PHYSICAL_RISK_REQUIRED:tier==='INSURANCE_UNDERWRITING_SAAS'||tier==='FINANCIAL_PORTFOLIO_RISK_SAAS',SEC_33_11275_APPLICABLE:tier==='FINANCIAL_PORTFOLIO_RISK_SAAS'||tier==='REAL_ESTATE_CLIMATE_RISK_SAAS',EU_TAXONOMY_CLIMATE_ADAPTATION:r.region==='EU',TNFD_LEAP_APPLICABLE:tier==='FINANCIAL_PORTFOLIO_RISK_SAAS'||tier==='INFRASTRUCTURE_RESILIENCE_SAAS',FEMA_NFIP_INTEGRATED:tier==='REAL_ESTATE_CLIMATE_RISK_SAAS'||tier==='MUNICIPAL_CLIMATE_ADAPTATION_SAAS'};const complianceNote=Object.entries(flags).filter(([,v])=>v).map(([k])=>k).join(', ')||'Standard';const msgs={INSURANCE_UNDERWRITING_SAAS:'Your TCFD physical risk model feeds directly into your loss ratio calculations \u2014 Day 3 we walk through FEMA flood zone ingestion and Swiss Re sigma calibration.',REAL_ESTATE_CLIMATE_RISK_SAAS:'Your physical risk scores become NAR disclosure inputs and lender underwriting data \u2014 Day 3 we walk through FEMA FIRM integration and IPCC AR6 sea-level pathways.',FINANCIAL_PORTFOLIO_RISK_SAAS:'Your TCFD portfolio alignment reports go to the SEC and the board \u2014 Day 3 we walk through NGFS scenario ingestion and SEC Rule 33-11275 disclosure workflow.',INFRASTRUCTURE_RESILIENCE_SAAS:'Your physical risk layers inform utility rate cases and bond covenants \u2014 Day 3 we walk through TNFD LEAP framework and FEMA hazard layer API.',MUNICIPAL_CLIMATE_ADAPTATION_SAAS:'Your risk assessments feed state HAZMAT plans and FEMA BRIC grants \u2014 Day 3 we walk through NOAA NWS API and FEMA NFIP Community Rating System.',SUPPLY_CHAIN_PHYSICAL_RISK_SAAS:'Your exposure scores feed SEC material event disclosures and supplier ESG audits \u2014 Day 3 we walk through TCFD value-chain scenario analysis.',CLIMATERISK_STARTUP_SAAS:'Your platform is at the center of the fastest-growing ESG data category \u2014 Day 3 we walk through TCFD alignment and EU Taxonomy Art.10 documentation.'};return [{json:{...r,tier,flags,complianceNote,tierMsg:msgs[tier]||msgs.CLIMATERISK_STARTUP_SAAS}}];"
},
"position": [
460,
300
]
},
{
"id": "3",
"name": "Gmail \u2014 Day 0 Welcome",
"type": "n8n-nodes-base.gmail",
"parameters": {
"to": "={{$json.email}}",
"subject": "Welcome to {{YOUR_PLATFORM}} \u2014 your physical risk data environment is ready",
"message": "Hi {{$json.name}},\n\nYour account is live. {{$json.tierMsg}}\n\nCompliance scope: {{$json.complianceNote}}\n\nDay 3 we schedule your onboarding call.\n\nTeam FlowKit"
},
"position": [
680,
200
]
},
{
"id": "4",
"name": "Sheets \u2014 Log Onboarding",
"type": "n8n-nodes-base.googleSheets",
"parameters": {
"operation": "append",
"sheetId": "{{ONBOARDING_LOG_SHEET}}",
"data": {
"customer_id": "={{$json.customer_id}}",
"tier": "={{$json.tier}}",
"compliance_scope": "={{$json.complianceNote}}",
"started": "={{new Date().toISOString()}}"
}
},
"position": [
680,
380
]
},
{
"id": "5",
"name": "Wait \u2014 3 Days",
"type": "n8n-nodes-base.wait",
"parameters": {
"resume": "timeInterval",
"amount": 3,
"unit": "days"
},
"position": [
900,
300
]
},
{
"id": "6",
"name": "Gmail \u2014 Day 3 Setup Call",
"type": "n8n-nodes-base.gmail",
"parameters": {
"to": "={{$json.email}}",
"subject": "Your Day 3 onboarding call \u2014 {{YOUR_PLATFORM}}",
"message": "Hi {{$json.name}},\n\nTime to connect your first physical risk data feeds.\n\nBook your 30-min setup call: {{YOUR_CALENDLY_LINK}}\n\nTeam FlowKit"
},
"position": [
1120,
300
]
},
{
"id": "7",
"name": "Wait \u2014 4 Days",
"type": "n8n-nodes-base.wait",
"parameters": {
"resume": "timeInterval",
"amount": 4,
"unit": "days"
},
"position": [
1340,
300
]
},
{
"id": "8",
"name": "Gmail \u2014 Day 7 First Report",
"type": "n8n-nodes-base.gmail",
"parameters": {
"to": "={{$json.email}}",
"subject": "Your first TCFD physical risk summary is ready",
"message": "Hi {{$json.name}},\n\nYour platform has been ingesting physical risk data for 7 days.\n\nLog in to view your first TCFD scenario report: {{YOUR_APP_URL}}/reports/tcfd\n\nTeam FlowKit"
},
"position": [
1560,
300
]
}
],
"connections": {
"Sheets Trigger \u2014 New Customer": {
"main": [
[
{
"node": "Code \u2014 Segment & Flags",
"type": "main",
"index": 0
}
]
]
},
"Code \u2014 Segment & Flags": {
"main": [
[
{
"node": "Gmail \u2014 Day 0 Welcome",
"type": "main",
"index": 0
},
{
"node": "Sheets \u2014 Log Onboarding",
"type": "main",
"index": 0
}
]
]
},
"Gmail \u2014 Day 0 Welcome": {
"main": [
[
{
"node": "Wait \u2014 3 Days",
"type": "main",
"index": 0
}
]
]
},
"Wait \u2014 3 Days": {
"main": [
[
{
"node": "Gmail \u2014 Day 3 Setup Call",
"type": "main",
"index": 0
}
]
]
},
"Gmail \u2014 Day 3 Setup Call": {
"main": [
[
{
"node": "Wait \u2014 4 Days",
"type": "main",
"index": 0
}
]
]
},
"Wait \u2014 4 Days": {
"main": [
[
{
"node": "Gmail \u2014 Day 7 First Report",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 2: Physical Risk Data Feed & Model API Health Monitor
Physical risk analytics depend on live data feeds: NOAA NWS hazard forecasts, FEMA FIRM map updates, SEC EDGAR comparable disclosures, EU Taxonomy activity codes. A 15-minute NOAA feed outage during an active hurricane advisory cycle is a TCFD scenario accuracy gap.
This workflow polls 5 critical API endpoints every 15 minutes with SLA-based deduplication:
| API | Regulation | SLA |
|---|---|---|
tcfd_scenario_api |
TCFD 2021 §D Physical Risk | 30 min |
fema_flood_api |
FEMA NFIP FIRM accuracy | 60 min |
noaa_hazard_api |
NOAA NWS hurricane/flood feeds | 15 min |
sec_edgar_api |
SEC 33-11275 benchmarking | 120 min |
eu_taxonomy_api |
EU Taxonomy Art.10 activity codes | 120 min |
Import-ready workflow JSON:
{
"name": "ClimateRisk SaaS \u2014 Physical Risk Data Feed API Monitor",
"nodes": [
{
"id": "1",
"name": "Schedule \u2014 Every 15 Min",
"type": "n8n-nodes-base.scheduleTrigger",
"parameters": {
"rule": {
"interval": [
{
"field": "minutes",
"minutesInterval": 15
}
]
}
},
"position": [
240,
300
]
},
{
"id": "2",
"name": "Code \u2014 API Endpoints",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "return [{json:{name:'tcfd_scenario_api',url:'{{TCFD_MODEL_ENDPOINT}}/health',regulation:'TCFD 2021 \u00a7D Physical Risk Scenario Analysis',sla_minutes:30,tier:'CRITICAL'}},{json:{name:'fema_flood_api',url:'{{FEMA_NFIP_ENDPOINT}}/status',regulation:'FEMA NFIP FIRM map data feed \u2014 60-min stale = flood zone accuracy gap',sla_minutes:60,tier:'HIGH'}},{json:{name:'noaa_hazard_api',url:'{{NOAA_ENDPOINT}}/health',regulation:'NOAA NWS API \u2014 hurricane/flood forecasts feed TCFD scenario models',sla_minutes:15,tier:'CRITICAL'}},{json:{name:'sec_edgar_api',url:'{{SEC_EDGAR_PROXY}}/status',regulation:'SEC EDGAR API \u2014 33-11275 comparable disclosures benchmarking',sla_minutes:120,tier:'MEDIUM'}},{json:{name:'eu_taxonomy_api',url:'{{EU_TAXONOMY_ENDPOINT}}/health',regulation:'EU Taxonomy 2020/852 Art.10 climate adaptation activity codes',sla_minutes:120,tier:'MEDIUM'}}];"
},
"position": [
460,
300
]
},
{
"id": "3",
"name": "HTTP \u2014 Ping Each API",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "={{$json.url}}",
"method": "GET",
"timeout": 10000,
"continueOnFail": true
},
"position": [
680,
300
]
},
{
"id": "4",
"name": "Code \u2014 Evaluate Status",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const r=$input.first().json;const status=r.statusCode===200?'OK':'DOWN';const now=new Date();const state=$getWorkflowStaticData('global');const key=r.name+'_last_alert';const lastAlert=state[key]?new Date(state[key]):null;const dedup=lastAlert&&(now-lastAlert)<r.sla_minutes*60*1000;if(status==='DOWN'&&!dedup){state[key]=now.toISOString();return [{json:{...r,status,alert:true,msg:`PHYSICAL RISK DATA FEED DOWN: ${r.name} | Regulation: ${r.regulation} | Tier: ${r.tier}`}}];}return [{json:{...r,status,alert:false}}];"
},
"position": [
900,
300
]
},
{
"id": "5",
"name": "IF \u2014 Alert Needed",
"type": "n8n-nodes-base.if",
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{$json.alert}}",
"value2": true
}
]
}
},
"position": [
1120,
300
]
},
{
"id": "6",
"name": "Slack \u2014 Data Feed Alert",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#climate-data-ops",
"text": "={{$json.msg}}"
},
"position": [
1340,
200
]
},
{
"id": "7",
"name": "Sheets \u2014 Incident Log",
"type": "n8n-nodes-base.googleSheets",
"parameters": {
"operation": "append",
"sheetId": "{{INCIDENT_LOG_SHEET}}",
"data": {
"api": "={{$json.name}}",
"status": "={{$json.status}}",
"regulation": "={{$json.regulation}}",
"ts": "={{new Date().toISOString()}}"
}
},
"position": [
1340,
380
]
}
],
"connections": {
"Schedule \u2014 Every 15 Min": {
"main": [
[
{
"node": "Code \u2014 API Endpoints",
"type": "main",
"index": 0
}
]
]
},
"Code \u2014 API Endpoints": {
"main": [
[
{
"node": "HTTP \u2014 Ping Each API",
"type": "main",
"index": 0
}
]
]
},
"HTTP \u2014 Ping Each API": {
"main": [
[
{
"node": "Code \u2014 Evaluate Status",
"type": "main",
"index": 0
}
]
]
},
"Code \u2014 Evaluate Status": {
"main": [
[
{
"node": "IF \u2014 Alert Needed",
"type": "main",
"index": 0
}
]
]
},
"IF \u2014 Alert Needed": {
"main": [
[
{
"node": "Slack \u2014 Data Feed Alert",
"type": "main",
"index": 0
}
],
[
{
"node": "Sheets \u2014 Incident Log",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 3: TCFD / SEC / EU Taxonomy / TNFD Compliance Deadline Tracker
Physical risk analytics vendors face 12 distinct compliance deadlines. The one that catches vendors off guard: SEC Rule 33-11275 is in effect for accelerated filers for FY2025. If your platform doesn't yet generate SEC 33-11275-formatted physical risk disclosures, your customers are discovering that gap during annual report filing — not during onboarding.
| Deadline Type | Regulation | Hard Date |
|---|---|---|
TCFD_ANNUAL_PHYSICAL_RISK_REPORT |
TCFD 2021 §D.2 | With annual report |
SEC_33_11275_CLIMATE_DISCLOSURE |
SEC Final Rule 33-11275 | Form 10-K filing date |
EU_TAXONOMY_CLIMATE_ADAPTATION_REPORT |
EU Taxonomy 2020/852 Art.10 | Annual |
TNFD_ANNUAL_NATURE_RISK_DISCLOSURE |
TNFD v1.0 LEAP Pillar D | Annual |
FEMA_NFIP_CRS_ANNUAL_RECERTIFICATION |
FEMA NFIP CRS §73.7 | Annual |
EU_SFDR_ARTICLE_9_ANNUAL_REPORT |
EU SFDR 2019/2088 Art.9 | Annual |
IPCC_SCENARIO_MODEL_RECALIBRATION |
TCFD 2021 §D.1 | On IPCC AR6 update |
SOC2_TYPE2_RENEWAL |
AICPA SOC 2 CC6 | 12-month window |
ANNUAL_PENTEST |
SOC 2 CC7.2 | Annual |
SWISS_RE_SIGMA_DATA_LICENSE_RENEWAL |
Swiss Re sigma license | Annual |
NGFS_PORTFOLIO_ALIGNMENT_REVIEW |
NGFS 2023 Scenarios | On NGFS update |
GDPR_DPIA_REVIEW |
GDPR Art.35 | Annual |
Import-ready workflow JSON:
{
"name": "ClimateRisk SaaS \u2014 TCFD/SEC/EU Taxonomy/TNFD Compliance Deadline Tracker",
"nodes": [
{
"id": "1",
"name": "Schedule \u2014 Weekdays 8 AM",
"type": "n8n-nodes-base.scheduleTrigger",
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 8 * * 1-5"
}
]
}
},
"position": [
240,
300
]
},
{
"id": "2",
"name": "Sheets \u2014 Load Deadlines",
"type": "n8n-nodes-base.googleSheets",
"parameters": {
"operation": "read",
"sheetId": "{{COMPLIANCE_DEADLINES_SHEET}}",
"range": "deadlines!A:G"
},
"position": [
460,
300
]
},
{
"id": "3",
"name": "Code \u2014 Evaluate Urgency",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const deadlineTypes={TCFD_ANNUAL_PHYSICAL_RISK_REPORT:{label:'TCFD Annual Physical Risk Scenario Report',regulation:'TCFD 2021 Recommendations \u00a7D.2 \u2014 physical risk disclosure due with annual report'},SEC_33_11275_CLIMATE_DISCLOSURE:{label:'SEC Rule 33-11275 Annual Climate Disclosure',regulation:'SEC Final Rule 33-11275 \u2014 climate-related disclosures in Form 10-K (accelerated filers FY2025)'},EU_TAXONOMY_CLIMATE_ADAPTATION_REPORT:{label:'EU Taxonomy Climate Adaptation KPI Report',regulation:'EU Taxonomy 2020/852 Art.10 \u2014 annual climate adaptation activity reporting'},TNFD_ANNUAL_NATURE_RISK_DISCLOSURE:{label:'TNFD Annual Nature-Related Risk Disclosure',regulation:'TNFD v1.0 LEAP Framework Pillar D \u2014 annual metrics and targets disclosure'},FEMA_NFIP_CRS_ANNUAL_RECERTIFICATION:{label:'FEMA NFIP CRS Annual Recertification',regulation:'FEMA NFIP Community Rating System \u2014 annual recertification to maintain flood insurance discount'},EU_SFDR_ARTICLE_9_ANNUAL_REPORT:{label:'EU SFDR Article 9 Annual Sustainability Report',regulation:'EU SFDR 2019/2088 Art.9 \u2014 annual principal adverse impact report'},IPCC_SCENARIO_MODEL_RECALIBRATION:{label:'IPCC AR6 Scenario Model Annual Recalibration',regulation:'TCFD 2021 \u00a7D.1 \u2014 physical risk scenario analysis must use IPCC AR6 RCP/SSP pathways'},SOC2_TYPE2_RENEWAL:{label:'SOC 2 Type II Annual Audit Renewal',regulation:'AICPA SOC 2 \u2014 12-month continuous evidence window'},ANNUAL_PENTEST:{label:'Annual Penetration Test',regulation:'SOC 2 CC7.2 \u2014 annual pentest of physical risk model APIs'},SWISS_RE_SIGMA_DATA_LICENSE_RENEWAL:{label:'Swiss Re Sigma Data License Renewal',regulation:'Swiss Re sigma NatCat database license \u2014 annual renewal for catastrophe model calibration'},NGFS_PORTFOLIO_ALIGNMENT_REVIEW:{label:'NGFS Climate Scenario Annual Portfolio Alignment Review',regulation:'NGFS 2023 Scenarios \u2014 annual review for TCFD transition/physical pathway consistency'},GDPR_DPIA_REVIEW:{label:'GDPR DPIA Annual Review',regulation:'GDPR Art.35 \u2014 annual Data Protection Impact Assessment for high-risk location + financial risk data processing'}};const rows=$input.all().map(i=>i.json);const now=new Date();const alerts=[];for(const row of rows){if(!row.deadline_date||!row.deadline_type)continue;const deadline=new Date(row.deadline_date);const daysLeft=Math.ceil((deadline-now)/(1000*60*60*24));let urgency=null;if(daysLeft<0)urgency='OVERDUE';else if(daysLeft<=14)urgency='CRITICAL';else if(daysLeft<=30)urgency='URGENT';else if(daysLeft<=60)urgency='WARNING';else if(daysLeft<=90)urgency='NOTICE';if(!urgency)continue;const meta=deadlineTypes[row.deadline_type]||{label:row.deadline_type,regulation:'See compliance sheet'};alerts.push({json:{...row,urgency,daysLeft,...meta,msg:`[${urgency}] ${meta.label} \u2014 ${daysLeft<0?'OVERDUE by '+Math.abs(daysLeft)+' days':daysLeft+' days remaining'} | ${meta.regulation}`}});}return alerts.length?alerts:[{json:{urgency:null,msg:'No compliance deadlines require attention today'}}];"
},
"position": [
680,
300
]
},
{
"id": "4",
"name": "IF \u2014 Has Alerts",
"type": "n8n-nodes-base.if",
"parameters": {
"conditions": {
"string": [
{
"value1": "={{$json.urgency}}",
"operation": "isNotEmpty"
}
]
}
},
"position": [
900,
300
]
},
{
"id": "5",
"name": "Switch \u2014 Route by Urgency",
"type": "n8n-nodes-base.switch",
"parameters": {
"dataType": "string",
"value1": "={{$json.urgency}}",
"rules": {
"rules": [
{
"value2": "OVERDUE"
},
{
"value2": "CRITICAL"
},
{
"value2": "URGENT"
},
{
"value2": "WARNING"
}
]
}
},
"position": [
1120,
300
]
},
{
"id": "6",
"name": "Slack \u2014 OVERDUE/CRITICAL",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#compliance-critical",
"text": "={{$json.msg}}"
},
"position": [
1340,
160
]
},
{
"id": "7",
"name": "Gmail \u2014 Owner Notification",
"type": "n8n-nodes-base.gmail",
"parameters": {
"to": "={{$json.owner_email}}",
"subject": "=[COMPLIANCE {{$json.urgency}}] {{$json.label}} \u2014 action required",
"message": "={{$json.msg}}"
},
"position": [
1340,
300
]
},
{
"id": "8",
"name": "Slack \u2014 WARNING/NOTICE",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#compliance-watch",
"text": "={{$json.msg}}"
},
"position": [
1340,
440
]
}
],
"connections": {
"Schedule \u2014 Weekdays 8 AM": {
"main": [
[
{
"node": "Sheets \u2014 Load Deadlines",
"type": "main",
"index": 0
}
]
]
},
"Sheets \u2014 Load Deadlines": {
"main": [
[
{
"node": "Code \u2014 Evaluate Urgency",
"type": "main",
"index": 0
}
]
]
},
"Code \u2014 Evaluate Urgency": {
"main": [
[
{
"node": "IF \u2014 Has Alerts",
"type": "main",
"index": 0
}
]
]
},
"IF \u2014 Has Alerts": {
"main": [
[
{
"node": "Switch \u2014 Route by Urgency",
"type": "main",
"index": 0
}
],
[]
]
},
"Switch \u2014 Route by Urgency": {
"main": [
[
{
"node": "Slack \u2014 OVERDUE/CRITICAL",
"type": "main",
"index": 0
}
],
[
{
"node": "Gmail \u2014 Owner Notification",
"type": "main",
"index": 0
}
],
[
{
"node": "Gmail \u2014 Owner Notification",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack \u2014 WARNING/NOTICE",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 4: Climate Physical Risk Event Alert Pipeline
When a major hurricane makes landfall, a flash flood warning is issued, or a wildfire evacuation zone changes, your customers need to know — with context about which regulatory clocks just started.
This webhook pipeline handles 8 physical risk event types and maps each to its compliance clock:
| Event Type | Compliance Clock | Key Regulation |
|---|---|---|
MAJOR_HURRICANE_TRACK_UPDATE |
6h NHC advisory cycle | TCFD 2021 §D.1 scenario refresh |
FLASH_FLOOD_WARNING_ISSUED |
1-6h NWS action window | FEMA NFIP CRS §73.7 accuracy |
WILDFIRE_EVACUATION_ZONE_CHANGE |
Immediate / SEC material | SEC 33-11275 8-K 4 biz days |
EXTREME_HEAT_EVENT_THRESHOLD |
72h NOAA forecast | TCFD §D.2 chronic risk logging |
COASTAL_FLOOD_MODEL_UPDATE |
12h NOAA NOS cycle | FEMA FIRM reconciliation |
SUPPLY_CHAIN_PHYSICAL_DISRUPTION |
72h SEC evaluation window | SEC 33-11275 material event |
INSURANCE_LOSS_EVENT_TRIGGER |
Immediate sigma classification | TCFD §D.1 model response |
DATA_BREACH_CLIMATE_MODEL |
72h GDPR Art.33 clock | GDPR Art.33-34 notification |
Import-ready workflow JSON:
{
"name": "ClimateRisk SaaS \u2014 Physical Risk Event Alert Pipeline",
"nodes": [
{
"id": "1",
"name": "Webhook \u2014 Receive Risk Event",
"type": "n8n-nodes-base.webhook",
"parameters": {
"path": "climate-risk-event",
"method": "POST"
},
"position": [
240,
300
]
},
{
"id": "2",
"name": "Code \u2014 Classify & Route Event",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const event=$input.first().json;const eventType=event.event_type||'UNKNOWN';const now=new Date();const clockMap={MAJOR_HURRICANE_TRACK_UPDATE:{clock:'6h NHC advisory update cycle',urgency:'CRITICAL',note:'NHC issues advisories every 6h \u2014 TCFD physical risk scenario refresh required before next advisory cycle',regulation:'TCFD 2021 \u00a7D.1 scenario analysis must reflect current NHC track data'},FLASH_FLOOD_WARNING_ISSUED:{clock:'1-6h NWS action window',urgency:'CRITICAL',note:'FEMA NFIP CRS requires flood exposure updates within 6h of NWS flash flood warning for portfolio properties',regulation:'FEMA NFIP \u00a773.7 CRS crediting \u2014 flood map accuracy window'},WILDFIRE_EVACUATION_ZONE_CHANGE:{clock:'Immediate \u2014 Cal OES/state emergency order',urgency:'CRITICAL',note:'Real estate and infrastructure models must reflect evacuation zone changes immediately for SEC material event evaluation',regulation:'SEC 33-11275 \u2014 material physical risk event may require 8-K within 4 business days'},EXTREME_HEAT_EVENT_THRESHOLD:{clock:'72h NOAA forecast window',urgency:'HIGH',note:'Extreme heat crossing IPCC RCP8.5 threshold triggers TCFD scenario boundary condition review',regulation:'TCFD 2021 \u00a7D.2 chronic physical risk \u2014 heat stress threshold exceedance to be logged in scenario documentation'},COASTAL_FLOOD_MODEL_UPDATE:{clock:'12h NOAA NOS tide gauge cycle',urgency:'HIGH',note:'NOAA NOS coastal flood model update requires FEMA FIRM reconciliation for affected portfolio properties',regulation:'FEMA NFIP FIRM accuracy \u2014 coastal flood baseline must track NOS updated models'},SUPPLY_CHAIN_PHYSICAL_DISRUPTION:{clock:'72h SEC material event evaluation window',urgency:'HIGH',note:'Physical disruption to supply chain facility may constitute material physical risk event under SEC 33-11275',regulation:'SEC Rule 33-11275 \u2014 material supply chain disruption; 8-K within 4 business days if material'},INSURANCE_LOSS_EVENT_TRIGGER:{clock:'Immediate Swiss Re sigma classification',urgency:'HIGH',note:'NatCat loss event triggers Swiss Re sigma loss threshold check \u2014 insured exposure recalculation required',regulation:'TCFD 2021 \u00a7D.1 \u2014 insurance underwriters must document physical risk model response to sigma-classified events'},DATA_BREACH_CLIMATE_MODEL:{clock:'72h GDPR Art.33 notification clock',urgency:'CRITICAL',note:'Breach of proprietary physical risk model data or customer geospatial exposure data triggers GDPR 72h clock',regulation:'GDPR Art.33 \u2014 supervisory authority notification within 72h; Art.34 \u2014 customer notification if high risk to rights'}};const meta=clockMap[eventType]||{clock:'Review required',urgency:'MEDIUM',note:'Unclassified physical risk event',regulation:'TCFD 2021 general disclosure requirements'};const deadline=new Date(now.getTime()+(meta.urgency==='CRITICAL'?6*3600000:72*3600000));return [{json:{...event,...meta,eventType,detected_at:now.toISOString(),action_deadline:deadline.toISOString(),slack_msg:`[${meta.urgency}] CLIMATE RISK EVENT: ${eventType} | Clock: ${meta.clock} | ${meta.note} | Regulation: ${meta.regulation} | Action by: ${deadline.toISOString()}`}}];"
},
"position": [
460,
300
]
},
{
"id": "3",
"name": "Slack \u2014 #climate-risk-ops",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#climate-risk-ops",
"text": "={{$json.slack_msg}}"
},
"position": [
680,
200
]
},
{
"id": "4",
"name": "Postgres \u2014 Audit Log",
"type": "n8n-nodes-base.postgres",
"parameters": {
"operation": "executeQuery",
"query": "INSERT INTO climate_risk_events (event_type, urgency, detected_at, action_deadline, regulation, notes) VALUES ($1,$2,$3,$4,$5,$6)",
"additionalFields": {
"queryParams": "={{[$json.eventType, $json.urgency, $json.detected_at, $json.action_deadline, $json.regulation, $json.note]}}"
}
},
"position": [
680,
380
]
},
{
"id": "5",
"name": "IF \u2014 CRITICAL",
"type": "n8n-nodes-base.if",
"parameters": {
"conditions": {
"string": [
{
"value1": "={{$json.urgency}}",
"value2": "CRITICAL",
"operation": "equal"
}
]
}
},
"position": [
900,
300
]
},
{
"id": "6",
"name": "Gmail \u2014 Risk Officer Immediate",
"type": "n8n-nodes-base.gmail",
"parameters": {
"to": "={{$env.CHIEF_RISK_OFFICER_EMAIL}}",
"cc": "={{$env.CTO_EMAIL}}",
"subject": "=[CRITICAL] Physical Risk Event Requires Immediate Action: {{$json.eventType}}",
"message": "={{$json.slack_msg}}\n\nAction deadline: {{$json.action_deadline}}\n\nLog in to review: {{YOUR_APP_URL}}/events/{{$json.event_id}}"
},
"position": [
1120,
200
]
}
],
"connections": {
"Webhook \u2014 Receive Risk Event": {
"main": [
[
{
"node": "Code \u2014 Classify & Route Event",
"type": "main",
"index": 0
}
]
]
},
"Code \u2014 Classify & Route Event": {
"main": [
[
{
"node": "Slack \u2014 #climate-risk-ops",
"type": "main",
"index": 0
},
{
"node": "Postgres \u2014 Audit Log",
"type": "main",
"index": 0
}
]
]
},
"Slack \u2014 #climate-risk-ops": {
"main": [
[
{
"node": "IF \u2014 CRITICAL",
"type": "main",
"index": 0
}
]
]
},
"IF \u2014 CRITICAL": {
"main": [
[
{
"node": "Gmail \u2014 Risk Officer Immediate",
"type": "main",
"index": 0
}
],
[]
]
}
}
}
Workflow 5: Weekly ClimateRisk Platform KPI Dashboard
Monday 8 AM: your CEO gets a full-stack report — customer counts by tier, MRR, physical risk events processed, TCFD reports auto-triggered, and on-time resolution rate. The Chief Risk Officer is BCC'd.
The TCFD disclosure chain argument is embedded in the footer: every transformation logged, every data flow on-premise.
Import-ready workflow JSON:
{
"name": "ClimateRisk SaaS \u2014 Weekly Platform KPI Dashboard",
"nodes": [
{
"id": "1",
"name": "Schedule \u2014 Monday 8 AM",
"type": "n8n-nodes-base.scheduleTrigger",
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 8 * * 1"
}
]
}
},
"position": [
240,
300
]
},
{
"id": "2",
"name": "Postgres \u2014 Platform KPIs",
"type": "n8n-nodes-base.postgres",
"parameters": {
"operation": "executeQuery",
"query": "SELECT COUNT(DISTINCT customer_id) AS active_customers, COUNT(DISTINCT customer_id) FILTER (WHERE created_at >= NOW() - INTERVAL '7 days') AS new_this_week, SUM(mrr_usd) AS total_mrr, AVG(tcfd_reports_generated) AS avg_tcfd_reports_per_customer, COUNT(*) FILTER (WHERE tier = 'INSURANCE_UNDERWRITING_SAAS') AS insurance_customers, COUNT(*) FILTER (WHERE tier = 'FINANCIAL_PORTFOLIO_RISK_SAAS') AS portfolio_customers, COUNT(*) FILTER (WHERE tier = 'REAL_ESTATE_CLIMATE_RISK_SAAS') AS realestate_customers FROM customers WHERE status = 'active'"
},
"position": [
460,
220
]
},
{
"id": "3",
"name": "Postgres \u2014 Risk Events This Week",
"type": "n8n-nodes-base.postgres",
"parameters": {
"operation": "executeQuery",
"query": "SELECT COUNT(*) AS total_risk_events, COUNT(*) FILTER (WHERE urgency = 'CRITICAL') AS critical_events, COUNT(*) FILTER (WHERE tcfd_report_triggered = true) AS tcfd_reports_triggered, COUNT(*) FILTER (WHERE deadline_met = true) AS events_resolved_on_time FROM climate_risk_events WHERE detected_at >= NOW() - INTERVAL '7 days'"
},
"position": [
460,
420
]
},
{
"id": "4",
"name": "Merge",
"type": "n8n-nodes-base.merge",
"parameters": {
"mode": "mergeByIndex"
},
"position": [
680,
320
]
},
{
"id": "5",
"name": "Code \u2014 Build HTML Report",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const d=$input.first().json;const state=$getWorkflowStaticData('global');const lastMrr=state.last_mrr_usd||d.total_mrr;const mrrWoW=lastMrr?(((d.total_mrr-lastMrr)/lastMrr)*100).toFixed(1):'0.0';state.last_mrr_usd=d.total_mrr;const html=`<h2>ClimateRisk Platform \u2014 Weekly KPI Report</h2><table border='1' cellpadding='6' style='border-collapse:collapse'><tr><th>Metric</th><th>This Week</th><th>WoW</th></tr><tr><td>Active Customers</td><td>${d.active_customers}</td><td>+${d.new_this_week} new</td></tr><tr><td>Total MRR</td><td>$${Number(d.total_mrr).toLocaleString()}</td><td>${mrrWoW}%</td></tr><tr><td>Insurance Underwriting Customers</td><td>${d.insurance_customers}</td><td>\u2014</td></tr><tr><td>Financial Portfolio Customers</td><td>${d.portfolio_customers}</td><td>\u2014</td></tr><tr><td>Real Estate Risk Customers</td><td>${d.realestate_customers}</td><td>\u2014</td></tr><tr><td>Avg TCFD Reports/Customer</td><td>${Number(d.avg_tcfd_reports_per_customer).toFixed(1)}</td><td>\u2014</td></tr><tr><td>Physical Risk Events This Week</td><td>${d.total_risk_events}</td><td>${d.critical_events} CRITICAL</td></tr><tr><td>TCFD Reports Auto-Triggered</td><td>${d.tcfd_reports_triggered}</td><td>\u2014</td></tr><tr><td>Events Resolved On Time</td><td>${d.events_resolved_on_time}/${d.total_risk_events}</td><td>\u2014</td></tr></table><p style='color:#666;font-size:12px'>ClimateRisk Platform KPI \u2014 n8n self-hosted. TCFD audit trail: every metric transformation is git-versioned. Routing climate risk data through Zapier/Make creates SEC 33-11275 material information disclosure risk via third-party cloud processing.</p>`;return [{json:{...d,html_report:html,mrrWoW,subject:`ClimateRisk Platform Weekly KPI \u2014 MRR $${Number(d.total_mrr).toLocaleString()} | ${d.active_customers} customers | ${d.total_risk_events} risk events`}}];"
},
"position": [
900,
320
]
},
{
"id": "6",
"name": "Gmail \u2014 CEO + CRO BCC",
"type": "n8n-nodes-base.gmail",
"parameters": {
"to": "={{$env.CEO_EMAIL}}",
"bcc": "={{$env.CRO_EMAIL}}",
"subject": "={{$json.subject}}",
"message": "={{$json.html_report}}",
"options": {
"bodyContentType": "html"
}
},
"position": [
1120,
320
]
}
],
"connections": {
"Schedule \u2014 Monday 8 AM": {
"main": [
[
{
"node": "Postgres \u2014 Platform KPIs",
"type": "main",
"index": 0
},
{
"node": "Postgres \u2014 Risk Events This Week",
"type": "main",
"index": 0
}
]
]
},
"Postgres \u2014 Platform KPIs": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
}
]
]
},
"Postgres \u2014 Risk Events This Week": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
}
]
]
},
"Merge": {
"main": [
[
{
"node": "Code \u2014 Build HTML Report",
"type": "main",
"index": 0
}
]
]
},
"Code \u2014 Build HTML Report": {
"main": [
[
{
"node": "Gmail \u2014 CEO + CRO BCC",
"type": "main",
"index": 0
}
]
]
}
}
}
Why Self-Hosted n8n for Physical Risk Analytics
| Risk | Cloud iPaaS | Self-Hosted n8n |
|---|---|---|
| TCFD audit trail | Data passes through vendor cloud — chain of custody break | Every transformation in your git repo — full TCFD documentation |
| SEC 33-11275 material information | Physical risk data flows through third-party servers | Stays in your infrastructure — no third-party disclosure risk |
| EU Taxonomy climate adaptation | Processing in US cloud may fail EU data sovereignty | Deploy in EU VPC — GDPR Art.44-46 compliant |
| TNFD LEAP framework evidence | Vendor timestamps not in your LEAP documentation | n8n run logs become TNFD evidence artifacts |
| FEMA NFIP data licensing | License restricts redistribution — cloud routes may violate | Data never leaves your licensed environment |
Get All 5 Workflows
These workflows are available as import-ready JSON at stripeai.gumroad.com.
The full FlowKit bundle (15 workflows + setup guides) is available for $97.
Have questions about adapting these for your physical risk analytics stack? Drop a comment below.
Top comments (0)