If you're building software for biologics manufacturers, CROs, biosimilar developers, or cell & gene therapy companies, compliance automation isn't optional — it's your product's core value proposition.
Your customers live inside FDA 21 CFR Part 211 (biologics GMP), ICH Q7 (API GMP), EMA GMP Annex 2, and GCP ICH E6(R3). Every LIMS integration outage, missed BLA deadline, or untracked GCP deviation is a direct threat to their BLA approval and your NRR.
This post covers 5 production-ready n8n workflows built specifically for BioTech SaaS companies — covering customer onboarding, LIMS/ELN health monitoring, regulatory deadline tracking, FDA inspection alert routing, and weekly KPI dashboards. All import-ready JSON included.
Why BioTech SaaS Teams Are Moving Away from Zapier
Before the workflows, three critical reasons why biologics data cannot safely run through Zapier:
1. 21 CFR §211.68 requires audit trails — Zapier deletes them after 30 days
FDA 21 CFR §211.68 mandates that computerized laboratory systems maintain audit trails for the operational life of the system. A 30-day automatic deletion policy is a documented §211.68 compliance gap during any FDA inspection.
2. GCP ICH E6(R3) — clinical trial data egress creates multi-party HIPAA risk
Patient data flowing through Zapier's cloud infrastructure creates Art.28 GDPR DPA requirements and HIPAA BAA exposure that standard Zapier agreements don't cover for Phase I-III EDC integrations.
3. FDA BLA Warning Letter response window: 15 working days
A Zapier task queue delay on a BLA warning letter webhook means your customer's QA team gets notified 30 minutes late. Self-hosted n8n processes the webhook in milliseconds — no queue, no SLA breach.
Workflow 1: BioTech Customer GxP & BLA Onboarding Drip
Target: BioTech SaaS onboarding teams running multi-tier customer drips
Classifies incoming customers across 5 tiers (LARGE_PHARMA_BIOLOGICS / MID_MARKET_BIOTECH / CRO / CDMO_BIOLOGICS / STARTUP_BIOTECH) and applies 8 compliance flags (CFR_PART_211 / ICH_Q7 / ICH_Q5A / GCP_ICH_E6_R3 / FDA_BLA / EMA_MAA / CAR_T_HCT / DSCSA). Day 0 welcome → Day 3 integration check → Day 7 activation sequence with CSM escalation for enterprise CAR-T accounts.
{
"name": "BioTech Customer GxP & BLA Onboarding Drip",
"nodes": [
{
"id": "1",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
250,
300
],
"parameters": {
"path": "biotech-customer-onboarding",
"method": "POST",
"responseMode": "responseNode"
}
},
{
"id": "2",
"name": "Classify Customer Tier",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
470,
300
],
"parameters": {
"jsCode": "const d=items[0].json;\nconst tier=d.annual_revenue_usd>1e9?'LARGE_PHARMA_BIOLOGICS':d.annual_revenue_usd>100e6?'MID_MARKET_BIOTECH':d.company_type==='CRO'?'CRO':d.company_type==='CDMO_BIOLOGICS'?'CDMO_BIOLOGICS':'STARTUP_BIOTECH';\nconst flags=[];\nif(d.manufactures_biologics||d.api_biologics)flags.push('CFR_PART_211_APPLICABLE');\nif(d.api_manufacturing)flags.push('ICH_Q7_API_GMP');\nif(d.has_viral_vector||d.uses_bioreactors)flags.push('ICH_Q5A_VIRAL_SAFETY');\nif(d.runs_clinical_trials_phase1||d.runs_clinical_trials_phase2||d.runs_clinical_trials_phase3)flags.push('GCP_ICH_E6_R3');\nif(d.bla_filed||d.bla_in_progress)flags.push('FDA_BLA_REQUIRED');\nif(d.eu_maa_filed||d.eu_sites)flags.push('EMA_MAA_REQUIRED');\nif(d.car_t_product||d.gene_therapy||d.hct_product)flags.push('CAR_T_HCT_REQUIRED');\nif(d.serialization_required||d.us_commercial_biologics)flags.push('DSCSA_APPLICABLE');\nreturn[{json:{...d,customer_tier:tier,compliance_flags:flags,onboarding_ts:new Date().toISOString()}}];"
}
},
{
"id": "3",
"name": "Log to Postgres",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
690,
300
],
"parameters": {
"operation": "insert",
"table": "biotech_customer_onboarding",
"columns": "customer_id,company_name,customer_tier,compliance_flags,onboarding_ts",
"values": "={{$json.customer_id}},={{$json.company_name}},={{$json.customer_tier}},={{JSON.stringify($json.compliance_flags)}},={{$json.onboarding_ts}}"
}
},
{
"id": "4",
"name": "Day 0 Welcome Email",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"position": [
910,
200
],
"parameters": {
"operation": "send",
"to": "={{$json.contact_email}}",
"subject": "Welcome to FlowKit \u2014 Your Biologics GxP Automation Platform is Ready",
"message": "={{$json.customer_tier==='LARGE_PHARMA_BIOLOGICS'?'Your dedicated CSM will contact you within 2 business hours.':$json.customer_tier==='CDMO_BIOLOGICS'?'Your CDMO biologics workflow templates are pre-configured.':$json.compliance_flags.includes('CAR_T_HCT_REQUIRED')?'Your CAR-T/CGT workflow templates are pre-configured per 21 CFR Part 1271.':'Your onboarding checklist is attached.'}} Active compliance flags: {{$json.compliance_flags.join(', ')}}"
}
},
{
"id": "5",
"name": "Day 0 Slack CSM Alert",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
910,
380
],
"parameters": {
"channel": "#csm-biotech-onboarding",
"text": "New {{$json.customer_tier}} customer: *{{$json.company_name}}*. Flags: {{$json.compliance_flags.join(' | ')}}. {{$json.compliance_flags.includes('CAR_T_HCT_REQUIRED')?'\u26a0\ufe0f CAR-T/HCT/P scope \u2014 21 CFR Part 1271 validation required':''}} {{$json.compliance_flags.includes('GCP_ICH_E6_R3')?'\u26a0\ufe0f Clinical trial data \u2014 ICH E6(R3) audit trail required':''}}"
}
},
{
"id": "6",
"name": "Wait 3 Days",
"type": "n8n-nodes-base.wait",
"typeVersion": 1,
"position": [
1130,
300
],
"parameters": {
"amount": 3,
"unit": "days"
}
},
{
"id": "7",
"name": "Day 3 Integration Check",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
1350,
300
],
"parameters": {
"operation": "select",
"query": "SELECT integration_status FROM biotech_integration_status WHERE customer_id = '{{$json.customer_id}}'"
}
},
{
"id": "8",
"name": "Integration Connected?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1570,
300
],
"parameters": {
"conditions": {
"string": [
{
"value1": "={{$json.integration_status}}",
"operation": "notEqual",
"value2": "CONNECTED"
}
]
}
}
},
{
"id": "9",
"name": "Day 3 Reminder Email",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"position": [
1790,
200
],
"parameters": {
"operation": "send",
"to": "={{$json.contact_email}}",
"subject": "Your LIMS/ELN/MES integration \u2014 5-minute setup",
"message": "Hi {{$json.contact_name}}, your integration is pending. {{$json.compliance_flags.includes('CFR_PART_211_APPLICABLE')?'21 CFR \u00a7211.68 computer system validation requires confirmed integration before go-live.':''}} Book a 15-min setup call: calendly.com/flowkit-biotech"
}
},
{
"id": "10",
"name": "Wait 4 More Days",
"type": "n8n-nodes-base.wait",
"typeVersion": 1,
"position": [
2010,
300
],
"parameters": {
"amount": 4,
"unit": "days"
}
},
{
"id": "11",
"name": "Day 7 Check-In Email",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"position": [
2230,
300
],
"parameters": {
"operation": "send",
"to": "={{$json.contact_email}}",
"subject": "Week 1 \u2014 Are your biologics GxP workflows running?",
"message": "Hi {{$json.contact_name}}, it has been 7 days. {{$json.compliance_flags.includes('FDA_BLA_REQUIRED')?'Your BLA submission workflow tracker should be active.':''}} {{$json.compliance_flags.includes('GCP_ICH_E6_R3')?'Your clinical trial deviation monitor should be running.':''}} Anything blocking you? Reply to this email."
}
}
],
"connections": {
"Webhook": {
"main": [
[
{
"node": "Classify Customer Tier",
"type": "main",
"index": 0
}
]
]
},
"Classify Customer Tier": {
"main": [
[
{
"node": "Log to Postgres",
"type": "main",
"index": 0
}
]
]
},
"Log to Postgres": {
"main": [
[
{
"node": "Day 0 Welcome Email",
"type": "main",
"index": 0
},
{
"node": "Day 0 Slack CSM Alert",
"type": "main",
"index": 0
}
]
]
},
"Day 0 Welcome Email": {
"main": [
[
{
"node": "Wait 3 Days",
"type": "main",
"index": 0
}
]
]
},
"Wait 3 Days": {
"main": [
[
{
"node": "Day 3 Integration Check",
"type": "main",
"index": 0
}
]
]
},
"Day 3 Integration Check": {
"main": [
[
{
"node": "Integration Connected?",
"type": "main",
"index": 0
}
]
]
},
"Integration Connected?": {
"main": [
[
{
"node": "Day 3 Reminder Email",
"type": "main",
"index": 0
}
],
[
{
"node": "Wait 4 More Days",
"type": "main",
"index": 0
}
]
]
},
"Day 3 Reminder Email": {
"main": [
[
{
"node": "Wait 4 More Days",
"type": "main",
"index": 0
}
]
]
},
"Wait 4 More Days": {
"main": [
[
{
"node": "Day 7 Check-In Email",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 2: Bioprocess & LIMS Integration Health Monitor
Target: BioTech SaaS platform teams monitoring LIMS/ELN/MES/CTMS integrations for GxP customers
Polls all active integrations every 15 minutes. Fires OFFLINE (>2x expected interval) or DEGRADED (>1.5x) alerts to Slack #platform-biotech-ops. For GxP_CRITICAL integrations at LARGE_PHARMA_BIOLOGICS accounts: automatically sends a proactive customer email with 21 CFR §211.68 context. Logs all alerts to Postgres for FDA inspection audit trail.
{
"name": "Bioprocess & LIMS Integration Health Monitor",
"nodes": [
{
"id": "1",
"name": "Schedule 15min",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [
250,
300
],
"parameters": {
"rule": {
"interval": [
{
"field": "minutes",
"minutesInterval": 15
}
]
}
}
},
{
"id": "2",
"name": "Fetch Integration Status",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
470,
300
],
"parameters": {
"operation": "select",
"query": "SELECT customer_id, company_name, integration_type, last_sync_ts, expected_sync_interval_minutes, compliance_tier, open_deviations, validation_status FROM biotech_integrations WHERE active = true ORDER BY last_sync_ts ASC"
}
},
{
"id": "3",
"name": "Evaluate Health",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
690,
300
],
"parameters": {
"jsCode": "const alerts=[];\nconst now=Date.now();\nconst integrationLabels={\n 'LIMS':'Laboratory Information Management System',\n 'ELN':'Electronic Lab Notebook',\n 'MES':'Manufacturing Execution System',\n 'BIOPROCESS_CONTROLLER':'Bioprocess Control System',\n 'QMS':'Quality Management System',\n 'CTMS':'Clinical Trial Management System',\n 'EDC':'Electronic Data Capture (21 CFR \u00a711)'\n};\nfor(const s of items){\n const d=s.json;\n const minsSince=(now-new Date(d.last_sync_ts).getTime())/60000;\n const threshold=d.expected_sync_interval_minutes||60;\n const label=integrationLabels[d.integration_type]||d.integration_type;\n const isCritical=d.compliance_tier==='GxP_CRITICAL'||d.compliance_tier==='PART_11_REGULATED';\n if(minsSince>threshold*2){\n alerts.push({...d,alert_type:'OFFLINE',severity:'CRITICAL',label,mins_stale:Math.round(minsSince),message:`CRITICAL: ${d.company_name} ${label} OFFLINE ${Math.round(minsSince)}min${isCritical?' \u2014 21 CFR \u00a7211.68 computer system data gap':''}`,requires_proactive_email:d.compliance_tier==='GxP_CRITICAL'&&d.customer_tier==='LARGE_PHARMA_BIOLOGICS'});\n } else if(minsSince>threshold*1.5){\n alerts.push({...d,alert_type:'DEGRADED',severity:'HIGH',label,mins_stale:Math.round(minsSince),message:`HIGH: ${d.company_name} ${label} DEGRADED \u2014 ${Math.round(minsSince)}min since last sync`,requires_proactive_email:false});\n }\n if(d.validation_status==='OUT_OF_VALIDATION'){\n alerts.push({...d,alert_type:'VALIDATION_EXPIRED',severity:'CRITICAL',label,message:`CRITICAL: ${d.company_name} ${label} \u2014 validation expired, 21 CFR \u00a7211.68 use blocked`,requires_proactive_email:true});\n }\n if(d.open_deviations>3){\n alerts.push({...d,alert_type:'DEVIATION_BACKLOG',severity:'HIGH',label,message:`HIGH: ${d.company_name} has ${d.open_deviations} open GxP deviations in ${label}`,requires_proactive_email:false});\n }\n}\nreturn alerts.length?alerts.map(a=>({json:a})):[{json:{no_alerts:true,checked_at:new Date().toISOString()}}];"
}
},
{
"id": "4",
"name": "Has Alerts?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
910,
300
],
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{$json.no_alerts===true}}",
"operation": "equal",
"value2": true
}
]
}
}
},
{
"id": "5",
"name": "Log Alert",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
1130,
200
],
"parameters": {
"operation": "insert",
"table": "bioprocess_integration_alerts",
"columns": "customer_id,integration_type,alert_type,severity,message,detected_at",
"values": "={{$json.customer_id}},={{$json.integration_type}},={{$json.alert_type}},={{$json.severity}},={{$json.message}},={{new Date().toISOString()}}"
}
},
{
"id": "6",
"name": "Slack #platform-biotech-ops",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
1350,
200
],
"parameters": {
"channel": "#platform-biotech-ops",
"text": "{{$json.message}} | Customer: {{$json.company_name}} | {{new Date().toISOString()}}"
}
},
{
"id": "7",
"name": "Proactive Email?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1350,
380
],
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{$json.requires_proactive_email}}",
"operation": "equal",
"value2": true
}
]
}
}
},
{
"id": "8",
"name": "Proactive Customer Email",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"position": [
1570,
380
],
"parameters": {
"operation": "send",
"to": "={{$json.contact_email}}",
"subject": "[ACTION] {{$json.label}} connection issue \u2014 GxP data gap risk",
"message": "Hi {{$json.contact_name}}, we detected your {{$json.label}} has been offline for {{$json.mins_stale}} minutes. This may create a 21 CFR \u00a7211.68 audit trail gap. Our team is investigating. Reply to confirm your systems are operational."
}
}
],
"connections": {
"Schedule 15min": {
"main": [
[
{
"node": "Fetch Integration Status",
"type": "main",
"index": 0
}
]
]
},
"Fetch Integration Status": {
"main": [
[
{
"node": "Evaluate Health",
"type": "main",
"index": 0
}
]
]
},
"Evaluate Health": {
"main": [
[
{
"node": "Has Alerts?",
"type": "main",
"index": 0
}
]
]
},
"Has Alerts?": {
"main": [
[],
[
{
"node": "Log Alert",
"type": "main",
"index": 0
}
]
]
},
"Log Alert": {
"main": [
[
{
"node": "Slack #platform-biotech-ops",
"type": "main",
"index": 0
},
{
"node": "Proactive Email?",
"type": "main",
"index": 0
}
]
]
},
"Proactive Email?": {
"main": [
[
{
"node": "Proactive Customer Email",
"type": "main",
"index": 0
}
],
[]
]
}
}
}
Workflow 3: FDA 21 CFR 211 / BLA / GCP Compliance Deadline Tracker
Target: BioTech SaaS customer success and regulatory affairs teams
Tracks 12 deadline types per customer from a Google Sheet: FDA Annual Product Review (§211.192), BLA PDUFA dates, IND Annual Reports (§312.33), GCP site initiation visits, ICH Q10 management reviews, EMA MAA response deadlines, GMP Annex 2 annual reviews, BLA supplements, CAR-T FDA Part 1271 annual registration, DSCSA serialization audits, ICH Q5A viral safety reviews, and biosimilar 351(k) pathway milestones.
{
"name": "FDA 21 CFR 211 / BLA / GCP Compliance Deadline Tracker",
"nodes": [
{
"id": "1",
"name": "Schedule Weekdays 7AM",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [
250,
300
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 7 * * 1-5"
}
]
}
}
},
{
"id": "2",
"name": "Fetch Deadlines",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4,
"position": [
470,
300
],
"parameters": {
"operation": "read",
"sheetId": "YOUR_SHEET_ID",
"range": "A:J",
"keyRow": 1
}
},
{
"id": "3",
"name": "Classify Urgency",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
690,
300
],
"parameters": {
"jsCode": "const today=new Date();\nconst deadlineTypes={\n 'FDA_ANNUAL_PRODUCT_REVIEW_211':{'desc':'Annual Product Review \u2014 21 CFR \u00a7211.192','penalty':'FDA 483 observation \u2192 Warning Letter','notify_days':60},\n 'FDA_BLA_PDUFA_DATE':{'desc':'BLA PDUFA Action Date','penalty':'Complete Response Letter \u2192 12+ month delay','notify_days':90},\n 'FDA_IND_ANNUAL_REPORT':{'desc':'IND Annual Report (21 CFR \u00a7312.33)','penalty':'IND placed on clinical hold','notify_days':30},\n 'GCP_SITE_INITIATION_SIV':{'desc':'Clinical Site Initiation Visit (GCP ICH E6 R3)','penalty':'Protocol deviation \u2014 data excluded from BLA','notify_days':21},\n 'ICH_Q10_MGMT_REVIEW':{'desc':'ICH Q10 Management Review (annual PQS)','penalty':'GMP inspection finding','notify_days':30},\n 'EMA_MAA_RESPONSE_DEADLINE':{'desc':'EMA MAA Day 120/180 Response','penalty':'EMA withdrawal or refusal of marketing authorization','notify_days':60},\n 'EMA_GMP_ANNEX2_ANNUAL':{'desc':'EMA GMP Annex 2 Biologics Annual Review','penalty':'EMA GMP certificate suspension','notify_days':45},\n 'FDA_BLA_SUPPLEMENT':{'desc':'BLA Supplement (sBLA) PDUFA Response','penalty':'sBLA rejection \u2192 manufacturing change blocked','notify_days':30},\n 'CAR_T_FDA_1271_ANNUAL':{'desc':'FDA 21 CFR Part 1271 HCT/P Annual Registration','penalty':'CAR-T manufacturing operations suspended','notify_days':60},\n 'DSCSA_SERIALIZATION_AUDIT':{'desc':'DSCSA Track & Trace Audit (DSCSA 2023)','penalty':'Biologic product distribution halted','notify_days':30},\n 'ICH_Q5A_VIRAL_SAFETY_REVIEW':{'desc':'ICH Q5A Viral Safety Annual Assessment','penalty':'EMA/FDA batch release blocked','notify_days':45},\n 'FDA_BIOSIMILAR_351K_PATHWAY':{'desc':'FDA 351(k) Biosimilar Application PDUFA','penalty':'Biosimilar launch delayed 12+ months','notify_days':90}\n};\nconst results=[];\nfor(const row of items){\n const d=row.json;\n if(!d.due_date||!d.deadline_type)continue;\n const due=new Date(d.due_date);\n const daysLeft=Math.round((due-today)/86400000);\n const meta=deadlineTypes[d.deadline_type]||{desc:d.deadline_type,penalty:'Regulatory risk',notify_days:30};\n const urgency=daysLeft<0?'OVERDUE':daysLeft<=7?'CRITICAL':daysLeft<=14?'URGENT':daysLeft<=30?'WARNING':'NOTICE';\n if(urgency==='NOTICE')continue;\n results.push({json:{...d,...meta,days_left:daysLeft,urgency,due_date_fmt:d.due_date}});\n}\nreturn results;"
}
},
{
"id": "4",
"name": "Route by Urgency",
"type": "n8n-nodes-base.switch",
"typeVersion": 3,
"position": [
910,
300
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "critical",
"conditions": {
"string": [
{
"value1": "={{$json.urgency}}",
"operation": "equals",
"value2": "CRITICAL"
}
]
}
},
{
"outputKey": "overdue",
"conditions": {
"string": [
{
"value1": "={{$json.urgency}}",
"operation": "equals",
"value2": "OVERDUE"
}
]
}
},
{
"outputKey": "urgent",
"conditions": {
"string": [
{
"value1": "={{$json.urgency}}",
"operation": "equals",
"value2": "URGENT"
}
]
}
}
]
}
}
},
{
"id": "5",
"name": "Slack #regulatory-critical",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
1130,
150
],
"parameters": {
"channel": "#regulatory-critical",
"text": "\ud83d\udea8 {{$json.urgency}} ({{$json.days_left}}d): *{{$json.desc}}* | {{$json.customer_name}} | Risk: {{$json.penalty}}"
}
},
{
"id": "6",
"name": "Gmail Regulatory Owner",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"position": [
1130,
300
],
"parameters": {
"operation": "send",
"to": "={{$json.owner_email}}",
"subject": "[{{$json.urgency}}] {{$json.desc}} \u2014 {{$json.days_left}} days | {{$json.customer_name}}",
"message": "Regulatory deadline {{$json.urgency}}: {{$json.desc}} for {{$json.customer_name}}. Due: {{$json.due_date_fmt}} ({{$json.days_left}} days). Non-compliance risk: {{$json.penalty}}."
}
},
{
"id": "7",
"name": "Log to Regulatory Register",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
1130,
450
],
"parameters": {
"operation": "insert",
"table": "biotech_regulatory_deadline_log",
"columns": "customer_id,deadline_type,urgency,days_left,notified_at",
"values": "={{$json.customer_id}},={{$json.deadline_type}},={{$json.urgency}},={{$json.days_left}},={{new Date().toISOString()}}"
}
}
],
"connections": {
"Schedule Weekdays 7AM": {
"main": [
[
{
"node": "Fetch Deadlines",
"type": "main",
"index": 0
}
]
]
},
"Fetch Deadlines": {
"main": [
[
{
"node": "Classify Urgency",
"type": "main",
"index": 0
}
]
]
},
"Classify Urgency": {
"main": [
[
{
"node": "Route by Urgency",
"type": "main",
"index": 0
}
]
]
},
"Route by Urgency": {
"critical": [
[
{
"node": "Slack #regulatory-critical",
"type": "main",
"index": 0
},
{
"node": "Gmail Regulatory Owner",
"type": "main",
"index": 0
},
{
"node": "Log to Regulatory Register",
"type": "main",
"index": 0
}
]
],
"overdue": [
[
{
"node": "Slack #regulatory-critical",
"type": "main",
"index": 0
},
{
"node": "Gmail Regulatory Owner",
"type": "main",
"index": 0
},
{
"node": "Log to Regulatory Register",
"type": "main",
"index": 0
}
]
],
"urgent": [
[
{
"node": "Gmail Regulatory Owner",
"type": "main",
"index": 0
},
{
"node": "Log to Regulatory Register",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 4: FDA Biologics Inspection & GCP Deviation Alert Pipeline
Target: BioTech SaaS quality and clinical operations teams
Webhook-triggered with 30-minute deduplication using $getWorkflowStaticData. Routes 8 event types to appropriate channels: BLA Warning Letters (15wd response clock), OOS biologics results (§211.192 investigation), major GCP protocol deviations (ICH E6 R3 §4.5.1 IRB notification 7 days), CAR-T patient safety events (FDA 7-day expedited MedWatch), sterility failures, EMA Annex 2 GMP suspensions, DSCSA track & trace failures, and CRO data integrity flags.
{
"name": "FDA Biologics Inspection & GCP Deviation Alert Pipeline",
"nodes": [
{
"id": "1",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
250,
300
],
"parameters": {
"path": "biotech-regulatory-event",
"method": "POST",
"responseMode": "responseNode"
}
},
{
"id": "2",
"name": "Deduplicate & Classify",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
470,
300
],
"parameters": {
"jsCode": "const d=items[0].json;\nconst key=`${d.event_type}_${d.customer_id}_${d.batch_id||d.study_id||'global'}`;\nconst state=$getWorkflowStaticData('global');\nconst now=Date.now();\nif(state[key]&&(now-state[key])<30*60*1000){return[];}\nstate[key]=now;\nconst classmap={\n 'FDA_BLA_WARNING_LETTER':{'severity':'CRITICAL','channel':'#regulatory-critical','deadline':'15 working days response (21 CFR \u00a7558.8)','cite':'FD&C Act \u00a7351'},\n 'FDA_OOS_BIOLOGICS':{'severity':'CRITICAL','channel':'#quality-systems-critical','deadline':'21 CFR \u00a7211.192 \u2014 full OOS investigation required','cite':'FDA OOS Guidance 2006 + ICH Q5A'},\n 'GCP_PROTOCOL_DEVIATION_MAJOR':{'severity':'CRITICAL','channel':'#clinical-ops-critical','deadline':'IRB/IEC notification within 7 days (ICH E6 R3 \u00a75.17)','cite':'ICH E6(R3) \u00a74.5.1'},\n 'CAR_T_PATIENT_SAFETY_EVENT':{'severity':'CRITICAL','channel':'#clinical-ops-critical','deadline':'FDA MedWatch 7-day expedited report (21 CFR \u00a7312.32)','cite':'21 CFR \u00a7312.32(c)'},\n 'STERILITY_FAILURE_BIOLOGIC':{'severity':'CRITICAL','channel':'#quality-systems-critical','deadline':'21 CFR \u00a7211.192 investigation + potential recall notification','cite':'21 CFR Part 600 + ICH Q5A'},\n 'EMA_GMP_ANNEX2_SUSPENSION':{'severity':'CRITICAL','channel':'#regulatory-critical','deadline':'30 days EMA response \u2014 manufacturing may halt','cite':'EMA/189422/2014 Annex 2'},\n 'DSCSA_TRACK_TRACE_FAILURE':{'severity':'HIGH','channel':'#supply-chain-compliance','deadline':'24h DSCSA trading partner notification','cite':'DSCSA \u00a7582(e)'},\n 'CRO_DATA_INTEGRITY_FLAG':{'severity':'CRITICAL','channel':'#clinical-ops-critical','deadline':'72h for data lock audit \u2014 clinical hold risk','cite':'FDA Data Integrity Guidance 2018'}\n};\nconst meta=classmap[d.event_type]||{severity:'MEDIUM',channel:'#quality-systems',deadline:'Assess within 24h',cite:'SOP-QS-001'};\nreturn[{json:{...d,...meta,detected_at:new Date().toISOString()}}];"
}
},
{
"id": "3",
"name": "Respond 200",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
470,
450
],
"parameters": {
"responseCode": 200,
"responseBody": "{\"status\":\"received\"}"
}
},
{
"id": "4",
"name": "Log to Postgres",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
690,
300
],
"parameters": {
"operation": "insert",
"table": "biotech_regulatory_events",
"columns": "customer_id,event_type,severity,batch_id,study_id,detected_at,deadline,cite",
"values": "={{$json.customer_id}},={{$json.event_type}},={{$json.severity}},={{$json.batch_id||''}},={{$json.study_id||''}},={{$json.detected_at}},={{$json.deadline}},={{$json.cite}}"
}
},
{
"id": "5",
"name": "Slack Alert",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
910,
200
],
"parameters": {
"channel": "={{$json.channel}}",
"text": "\ud83d\udea8 {{$json.severity}}: {{$json.event_type}} | {{$json.company_name}} | Deadline: {{$json.deadline}} | Cite: {{$json.cite}} | {{$json.detected_at}}"
}
},
{
"id": "6",
"name": "Gmail QA Director",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"position": [
910,
380
],
"parameters": {
"operation": "send",
"to": "={{$json.qa_director_email}}",
"subject": "[{{$json.severity}}] {{$json.event_type}} \u2014 {{$json.company_name}} | {{$json.detected_at}}",
"message": "Regulatory event detected:\n\nType: {{$json.event_type}}\nCustomer: {{$json.company_name}}\nSeverity: {{$json.severity}}\nDeadline: {{$json.deadline}}\nRegulatory Cite: {{$json.cite}}\nBatch/Study: {{$json.batch_id||$json.study_id||'N/A'}}\nDetected: {{$json.detected_at}}\n\nImmediate action required."
}
}
],
"connections": {
"Webhook": {
"main": [
[
{
"node": "Deduplicate & Classify",
"type": "main",
"index": 0
}
],
[
{
"node": "Respond 200",
"type": "main",
"index": 0
}
]
]
},
"Deduplicate & Classify": {
"main": [
[
{
"node": "Log to Postgres",
"type": "main",
"index": 0
}
]
]
},
"Log to Postgres": {
"main": [
[
{
"node": "Slack Alert",
"type": "main",
"index": 0
},
{
"node": "Gmail QA Director",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 5: Weekly BioTech SaaS KPI Dashboard
Target: BioTech SaaS CEO, VP Quality, CTO, CMO
Monday 8AM: pulls platform metrics (total customers, large pharma tier, active this week, avg open deviations) and business metrics (total MRR WoW%, churn risk count, expired validations, integrations offline) from two Postgres views. Builds an HTML table with conditional alert flags for expired §211.68 validations, offline integrations, and high-deviation accounts. Emails CEO with BCC to VP Quality/CTO/CMO, posts one-liner to Slack #exec-biotech-kpis.
{
"name": "Weekly BioTech SaaS KPI Dashboard",
"nodes": [
{
"id": "1",
"name": "Schedule Monday 8AM",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [
250,
300
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 8 * * 1"
}
]
}
}
},
{
"id": "2",
"name": "Fetch Platform Metrics",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
470,
300
],
"parameters": {
"operation": "select",
"query": "SELECT COUNT(*) AS total_customers, COUNT(*) FILTER (WHERE customer_tier='LARGE_PHARMA_BIOLOGICS') AS large_pharma, COUNT(*) FILTER (WHERE last_activity_ts > NOW()-INTERVAL '7 days') AS active_this_week, AVG(open_deviations) AS avg_open_deviations, COUNT(*) FILTER (WHERE open_deviations>5) AS customers_high_deviations FROM biotech_customer_onboarding"
}
},
{
"id": "3",
"name": "Fetch Business Metrics",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
470,
480
],
"parameters": {
"operation": "select",
"query": "SELECT SUM(mrr_usd) AS total_mrr, COUNT(*) FILTER (WHERE health_score<40) AS churn_risk_count, COUNT(*) FILTER (WHERE validation_status='OUT_OF_VALIDATION') AS expired_validations, COUNT(*) FILTER (WHERE last_sync_ts < NOW()-INTERVAL '2 hours') AS integration_offline_count FROM biotech_customer_health_view"
}
},
{
"id": "4",
"name": "Merge",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [
690,
390
],
"parameters": {
"mode": "combine",
"combinationMode": "multiplex"
}
},
{
"id": "5",
"name": "Build KPI Report",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
910,
390
],
"parameters": {
"jsCode": "const prev=$getWorkflowStaticData('global');\nconst d=items[0].json;\nconst mrrWoW=prev.last_mrr?((d.total_mrr-prev.last_mrr)/prev.last_mrr*100).toFixed(1):null;\nprev.last_mrr=d.total_mrr;\nconst alerts=[];\nif(d.expired_validations>0)alerts.push(`\u26a0\ufe0f ${d.expired_validations} customer(s) with expired 21 CFR \u00a7211.68 validation`);\nif(d.integration_offline_count>0)alerts.push(`\u26a0\ufe0f ${d.integration_offline_count} LIMS/ELN/MES integration(s) offline`);\nif(d.customers_high_deviations>0)alerts.push(`\u26a0\ufe0f ${d.customers_high_deviations} customer(s) with >5 open GxP deviations`);\nconst subject=`[BioTech KPI${alerts.length?' \u2014 '+alerts.length+' ALERT'+( alerts.length>1?'S':''):''}] Week of ${new Date().toISOString().slice(0,10)}`;\nconst html=`<h2>BioTech SaaS Weekly KPI Report</h2><table border='1' cellpadding='6'><tr><th>Metric</th><th>Value</th><th>WoW</th></tr><tr><td>Total MRR</td><td>$${d.total_mrr?.toLocaleString()||'\u2014'}</td><td>${mrrWoW?mrrWoW+'%':'first run'}</td></tr><tr><td>Total Customers</td><td>${d.total_customers}</td><td>\u2014</td></tr><tr><td>Large Pharma Biologics</td><td>${d.large_pharma}</td><td>\u2014</td></tr><tr><td>Active This Week</td><td>${d.active_this_week}</td><td>\u2014</td></tr><tr><td>Churn Risk Accounts</td><td>${d.churn_risk_count}</td><td>\u2014</td></tr><tr><td>Integrations Offline</td><td>${d.integration_offline_count}</td><td>\u2014</td></tr><tr><td>Expired Validations</td><td>${d.expired_validations}</td><td>\u2014</td></tr></table>${alerts.length?'<h3>Alerts</h3><ul>'+alerts.map(a=>`<li>${a}</li>`).join('')+'</ul>':'<p>\u2705 No critical GxP alerts this week.</p>'}`;\nreturn[{json:{subject,html,slack_summary:`BioTech KPI: MRR $${d.total_mrr?.toLocaleString()||'\u2014'} | ${d.total_customers} customers | ${d.churn_risk_count} churn risk | ${d.expired_validations} expired validations | ${d.integration_offline_count} integrations offline`}}];"
}
},
{
"id": "6",
"name": "Gmail CEO Report",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"position": [
1130,
300
],
"parameters": {
"operation": "send",
"to": "CEO@yourcompany.com",
"bcc": "vp-quality@yourcompany.com,cto@yourcompany.com,cmo@yourcompany.com",
"subject": "={{$json.subject}}",
"message": "={{$json.html}}"
}
},
{
"id": "7",
"name": "Slack #exec-biotech-kpis",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
1130,
480
],
"parameters": {
"channel": "#exec-biotech-kpis",
"text": "={{$json.slack_summary}}"
}
}
],
"connections": {
"Schedule Monday 8AM": {
"main": [
[
{
"node": "Fetch Platform Metrics",
"type": "main",
"index": 0
},
{
"node": "Fetch Business Metrics",
"type": "main",
"index": 0
}
]
]
},
"Fetch Platform Metrics": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
}
]
]
},
"Fetch Business Metrics": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
}
]
]
},
"Merge": {
"main": [
[
{
"node": "Build KPI Report",
"type": "main",
"index": 0
}
]
]
},
"Build KPI Report": {
"main": [
[
{
"node": "Gmail CEO Report",
"type": "main",
"index": 0
},
{
"node": "Slack #exec-biotech-kpis",
"type": "main",
"index": 0
}
]
]
}
}
}
Self-Hosted n8n: The Only Compliant Choice for Biologics Data
| Requirement | Zapier | Self-Hosted n8n |
|---|---|---|
| 21 CFR §211.68 audit trail retention | 30-day auto-delete ❌ | Indefinite, git-versioned ✅ |
| GCP ICH E6(R3) EDC data egress | Multi-tenant cloud ❌ | Air-gapped on-prem ✅ |
| HIPAA BAA for clinical trial data | Standard terms only ❌ | Self-hosted, no BAA needed ✅ |
| EMA Annex 2 record retention | 30 days ❌ | System lifetime ✅ |
| DSCSA track & trace event log | 30-day history ❌ | Full serialization history ✅ |
| FDA inspection audit evidence | Black-box task history ❌ | Git commit + workflow version history ✅ |
| CAR-T 21 CFR Part 1271 chain of identity | Not configurable ❌ | Custom audit node ✅ |
Get These Workflows Pre-Built
All 5 workflows are available as import-ready JSON files at stripeai.gumroad.com — the FlowKit n8n automation template library. Individual templates from $12, bundle of 14+ workflows for $97.
The bundle includes templates for LIMS integration monitoring, GCP deviation routing, BLA deadline tracking, customer health scoring, and executive KPI dashboards — all pre-tested with real n8n instances.
What's your biggest compliance automation challenge in BioTech SaaS? Drop it in the comments — I may already have a workflow for it.
Top comments (0)