{"workflow":{"id":14211,"name":"Optimize Cold Email Copy with Claude, Instantly, and Google Sheets","views":53,"recentViews":1,"totalViews":53,"createdAt":"2026-03-21T01:36:16.845Z","description":"## Optimize Cold Email Copy with Claude, Instantly, and Google Sheets\n\nInspired by [Karpathy's Autoresearch](https://github.com/karpathy/autoresearch), this workflow treats your cold email campaigns as continuous experiments. Instead of writing copy once and hoping for the best, it runs an automated optimization loop that evolves your emails based on real performance data.\n\n### How it works\n1. Runs on a schedule (every 6 hours)\n2. Pulls live campaign stats (open rate, reply rate) from Instantly\n3. Reads the current champion and challenger variants from Google Sheets\n4. Reads the full experiment history (last 10 rounds)\n5. Checks if both variants have enough data (200+ sends each)\n6. If below threshold, exits and waits for the next run\n7. If above threshold, feeds everything to Claude: both variants, metrics, experiment history, and the cold email program rules\n8. Claude declares a winner, explains why, and generates a new challenger with a specific hypothesis\n9. Safety check: if reply rate drops below the floor threshold, pauses and sends a Telegram alert instead of continuing\n10. Logs the full experiment (variants, metrics, winner, reasoning, change type) to Google Sheets\n11. Promotes winner, deploys new challenger to Instantly\n\n### What makes it different\n- **Learns across rounds, not just the current test.** Claude sees the last 10 experiments and identifies patterns over time.\n- **Program doc driven.** Brand voice, hard rules, and constraints live in a Google Sheet, not hardcoded in prompts. Update the rules without touching the workflow.\n- **Structured change tracking.** Every experiment logs what specifically changed (subject, CTA, tone, length, opener style) so you can filter by change type.\n- **Safety floor.** If reply rate drops below your minimum, the system pauses and alerts you instead of running bad copy.\n\n### What you need\n- Instantly account with active campaign\n- Claude API key (Anthropic)\n- Google Sheets (two tabs: Active, Experiments + one tab: Program)\n- Telegram bot (for safety alerts)\n- Enough send volume for meaningful data (200+ sends per variant)\n\n### Google Sheets setup\n**Active tab** (A:F): Variant | Subject Line | Email Body | Sends | Open Rate | Reply Rate\n\n**Experiments tab** (A:M): Experiment ID | Date | Champion Copy | Challenger Copy | Champion Subject | Challenger Subject | Champion Sends | Challenger Sends | Champion Reply Rate | Challenger Reply Rate | Winner | Change Type | Reasoning\n\n**Program tab** (A:B): Rule Name | Rule Content (brand voice, constraints, off-limits topics, max word count, required variables, etc.)\n\n### Environment variables\n- OPTIMIZER_SHEET_ID\n- REMOVEFAST_CAMPAIGN_ID\n- INSTANTLY_API_KEY\n- ANTHROPIC_API_KEY\n- TELEGRAM_BOT_TOKEN\n- TELEGRAM_CHAT_ID\n- REPLY_RATE_FLOOR (default: 1.0)","workflow":{"id":"GI5LxfZwce2F9838","meta":{"instanceId":"7fbdaefe02dd3fb2e07e324f7d336f4e2dd6566cd7a7046b2677903bf88524bf"},"name":"Self-Improving Cold Email Copy Optimizer","tags":[],"nodes":[{"id":"sticky-overview","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-784,0],"parameters":{"width":700,"height":1262,"content":"## Self-Improving Cold Email Copy Optimizer\n\nInspired by [Karpathy's Autoresearch](https://github.com/karpathy/autoresearch), this workflow treats your cold email campaigns as continuous experiments. Instead of writing copy once and hoping for the best, it runs an automated optimization loop that evolves your emails based on real performance data.\n\n### How it works\n1. Runs on a schedule (every 6 hours)\n2. Pulls live campaign stats (open rate, reply rate) from Instantly\n3. Reads the current champion and challenger variants from Google Sheets\n4. Reads the full experiment history (last 10 rounds)\n5. Checks if both variants have enough data (200+ sends each)\n6. If below threshold, exits and waits for the next run\n7. If above threshold, feeds everything to Claude: both variants, metrics, experiment history, and the cold email program rules\n8. Claude declares a winner, explains why, and generates a new challenger with a specific hypothesis\n9. Safety check: if reply rate drops below the floor threshold, pauses and sends a Telegram alert instead of continuing\n10. Logs the full experiment (variants, metrics, winner, reasoning, change type) to Google Sheets\n11. Promotes winner, deploys new challenger to Instantly\n\n### What makes it different\n- **Learns across rounds, not just the current test.** Claude sees the last 10 experiments and identifies patterns over time.\n- **Program doc driven.** Brand voice, hard rules, and constraints live in a Google Sheet, not hardcoded in prompts. Update the rules without touching the workflow.\n- **Structured change tracking.** Every experiment logs what specifically changed (subject, CTA, tone, length, opener style) so you can filter by change type.\n- **Safety floor.** If reply rate drops below your minimum, the system pauses and alerts you instead of running bad copy.\n\n### What you need\n- Instantly account with active campaign\n- Claude API key (Anthropic)\n- Google Sheets (two tabs: Active, Experiments + one tab: Program)\n- Telegram bot (for safety alerts)\n- Enough send volume for meaningful data (200+ sends per variant)\n\n### Google Sheets setup\n**Active tab** (A:F): Variant | Subject Line | Email Body | Sends | Open Rate | Reply Rate\n\n**Experiments tab** (A:M): Experiment ID | Date | Champion Copy | Challenger Copy | Champion Subject | Challenger Subject | Champion Sends | Challenger Sends | Champion Reply Rate | Challenger Reply Rate | Winner | Change Type | Reasoning\n\n**Program tab** (A:B): Rule Name | Rule Content (brand voice, constraints, off-limits topics, max word count, required variables, etc.)\n\n### Environment variables\n- OPTIMIZER_SHEET_ID\n- REMOVEFAST_CAMPAIGN_ID\n- INSTANTLY_API_KEY\n- ANTHROPIC_API_KEY\n- TELEGRAM_BOT_TOKEN\n- TELEGRAM_CHAT_ID\n- REPLY_RATE_FLOOR (default: 1.0)"},"typeVersion":1},{"id":"sticky-data","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[192,160],"parameters":{"width":550,"height":100,"content":"### Data Collection\nPulls live stats from Instantly and reads current variants + experiment history from Google Sheets. Also reads the Program doc for Claude's rules."},"typeVersion":1},{"id":"sticky-evaluate","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[896,160],"parameters":{"width":400,"height":116,"content":"### Threshold Check + Routing\nNeeds 200+ sends per variant before evaluating. If not enough data, the workflow exits cleanly. Three paths: first run, evaluate, or wait."},"typeVersion":1},{"id":"sticky-claude","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[1392,160],"parameters":{"width":400,"height":116,"content":"### AI Evaluation + Safety\nClaude analyzes both variants against 10 rounds of history. Generates new challenger with a hypothesis. Safety floor check pauses the loop if reply rate tanks."},"typeVersion":1},{"id":"sticky-deploy","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[1872,160],"parameters":{"width":450,"height":116,"content":"### Log + Deploy\nLogs full experiment to history sheet, promotes winner, deploys new challenger to Instantly. Every round compounds the knowledge base."},"typeVersion":1},{"id":"trigger-1","name":"Run Every 6 Hours","type":"n8n-nodes-base.scheduleTrigger","notes":"Runs the optimization loop every 6 hours. At 2,400 sends/week you get meaningful data every 24-48 hours, but polling frequently catches the threshold faster.","position":[0,496],"parameters":{"rule":{"interval":[{"field":"hours","hoursInterval":6}]}},"typeVersion":1.2,"alwaysOutputData":true},{"id":"instantly-stats","name":"Pull Instantly Campaign Stats","type":"n8n-nodes-base.httpRequest","notes":"Pulls open rate, reply rate, click rate from the active Instantly campaign.","position":[224,496],"parameters":{"url":"=https://api.instantly.ai/api/v2/campaigns/{{ $env.REMOVEFAST_CAMPAIGN_ID }}/analytics","options":{},"sendHeaders":true,"headerParameters":{"parameters":[{"name":"Authorization","value":"=Bearer {{ $env.INSTANTLY_API_KEY }}"}]}},"typeVersion":4.2,"alwaysOutputData":true},{"id":"sheets-read-experiments","name":"Read Experiment History","type":"n8n-nodes-base.httpRequest","notes":"Reads full experiment history. Now includes Change Type column (M) for structured tracking.","position":[448,304],"parameters":{"url":"=https://sheets.googleapis.com/v4/spreadsheets/{{ $env.OPTIMIZER_SHEET_ID }}/values/Experiments!A:M","options":{},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"Fzpsut9akLL5grlP","name":"Header Auth account"}},"typeVersion":4.2,"alwaysOutputData":true},{"id":"sheets-read-active","name":"Read Active Variants","type":"n8n-nodes-base.httpRequest","notes":"Reads currently active champion and challenger variants.","position":[448,496],"parameters":{"url":"=https://sheets.googleapis.com/v4/spreadsheets/{{ $env.OPTIMIZER_SHEET_ID }}/values/Active!A:F","options":{},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"Fzpsut9akLL5grlP","name":"Header Auth account"}},"typeVersion":4.2,"alwaysOutputData":true},{"id":"sheets-read-program","name":"Read Program Doc","type":"n8n-nodes-base.httpRequest","notes":"Reads the cold email program rules. Brand voice, constraints, off-limits topics, required variables, max word count. Update this sheet to change Claude's behavior without touching the workflow.","position":[448,688],"parameters":{"url":"=https://sheets.googleapis.com/v4/spreadsheets/{{ $env.OPTIMIZER_SHEET_ID }}/values/Program!A:B","options":{},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"Fzpsut9akLL5grlP","name":"Header Auth account"}},"typeVersion":4.2,"alwaysOutputData":true},{"id":"code-merge","name":"Merge Stats and History","type":"n8n-nodes-base.code","notes":"Merges all data sources. Now includes program rules and reply rate floor check. Flags if both variants are performing below the safety threshold.","position":[672,496],"parameters":{"jsCode":"// Merge Instantly stats, active variants, experiment history, and program rules\nconst stats = $('Pull Instantly Campaign Stats').first().json;\nconst activeSheet = $('Read Active Variants').first().json;\nconst historySheet = $('Read Experiment History').first().json;\nconst programSheet = $('Read Program Doc').first().json;\n\n// Parse active variants\nconst activeRows = (activeSheet.values || []).slice(1);\nconst champion = activeRows.find(r => r[0] === 'champion') || [];\nconst challenger = activeRows.find(r => r[0] === 'challenger') || [];\n\n// Parse experiment history (last 10 rounds)\nconst historyRows = (historySheet.values || []).slice(1);\nconst recentHistory = historyRows.slice(-10).map(r => ({\n  experimentId: r[0],\n  date: r[1],\n  championCopy: r[2],\n  challengerCopy: r[3],\n  championSubject: r[4],\n  challengerSubject: r[5],\n  championSends: parseInt(r[6]) || 0,\n  challengerSends: parseInt(r[7]) || 0,\n  championReplyRate: parseFloat(r[8]) || 0,\n  challengerReplyRate: parseFloat(r[9]) || 0,\n  winner: r[10],\n  changeType: r[11] || '',\n  reasoning: r[12] || ''\n}));\n\n// Parse program rules\nconst programRows = (programSheet.values || []).slice(1);\nconst programRules = programRows.map(r => `${r[0]}: ${r[1]}`).join('\\n');\n\n// Current variant data\nconst championData = {\n  subject: champion[1] || '',\n  body: champion[2] || '',\n  sends: parseInt(champion[3]) || 0,\n  openRate: parseFloat(champion[4]) || 0,\n  replyRate: parseFloat(champion[5]) || 0\n};\n\nconst challengerData = {\n  subject: challenger[1] || '',\n  body: challenger[2] || '',\n  sends: parseInt(challenger[3]) || 0,\n  openRate: parseFloat(challenger[4]) || 0,\n  replyRate: parseFloat(challenger[5]) || 0\n};\n\n// Reply rate floor from env (default 1.0%)\nconst replyRateFloor = parseFloat($env.REPLY_RATE_FLOOR) || 1.0;\n\nreturn [{\n  json: {\n    campaignStats: stats,\n    champion: championData,\n    challenger: challengerData,\n    experimentHistory: recentHistory,\n    totalExperiments: historyRows.length,\n    programRules: programRules,\n    replyRateFloor: replyRateFloor,\n    bothHaveEnoughData: championData.sends >= 200 && challengerData.sends >= 200,\n    hasChallenger: challengerData.body.length > 0,\n    belowFloor: championData.replyRate < replyRateFloor && challengerData.replyRate < replyRateFloor && championData.sends >= 200\n  }\n}];"},"executeOnce":false,"typeVersion":2,"alwaysOutputData":true},{"id":"code-check-threshold","name":"Check Data Threshold","type":"n8n-nodes-base.code","notes":"Four paths now: safety pause (reply rate below floor), generate first challenger, evaluate and generate, or wait.","position":[896,496],"parameters":{"jsCode":"// Route based on data readiness and safety\nconst data = $input.first().json;\n\n// Safety floor: if both variants are below minimum reply rate, pause\nif (data.belowFloor) {\n  return [{ json: { ...data, action: 'safety_pause' } }];\n}\n\n// First run with no challenger, generate one\nif (!data.hasChallenger) {\n  return [{ json: { ...data, action: 'generate_first_challenger' } }];\n}\n\n// Enough data to evaluate\nif (data.bothHaveEnoughData) {\n  return [{ json: { ...data, action: 'evaluate_and_generate' } }];\n}\n\n// Not enough data, exit\nreturn [{ json: { ...data, action: 'wait' } }];"},"typeVersion":2,"alwaysOutputData":true},{"id":"code-route","name":"Route by Action","type":"n8n-nodes-base.code","notes":"Stops workflow if not enough data. Passes safety pauses and evaluation actions through.","position":[1120,496],"parameters":{"jsCode":"// Route: wait exits, safety_pause goes to Telegram, everything else goes to Claude\nconst data = $input.first().json;\n\nif (data.action === 'wait') {\n  return [];\n}\n\nreturn [$input.first()];"},"typeVersion":2,"alwaysOutputData":true},{"id":"code-safety-check","name":"Safety Floor Check","type":"n8n-nodes-base.code","notes":"Routes safety pauses to Telegram alert. Normal evaluations continue to Claude.","position":[1344,496],"parameters":{"jsCode":"// Split: safety_pause goes to Telegram, everything else goes to Claude\nconst data = $input.first().json;\n\nif (data.action === 'safety_pause') {\n  return [{ json: { ...data, _route: 'telegram' } }];\n}\n\nreturn [{ json: { ...data, _route: 'claude' } }];"},"typeVersion":2,"alwaysOutputData":true},{"id":"telegram-alert","name":"Telegram Safety Alert","type":"n8n-nodes-base.httpRequest","notes":"Sends Telegram alert when reply rate drops below floor. Workflow stops experimenting until you manually review and update the Active sheet.","position":[1568,592],"parameters":{"url":"=https://api.telegram.org/bot{{ $env.TELEGRAM_BOT_TOKEN }}/sendMessage","method":"POST","options":{},"jsonBody":"={\n  \"chat_id\": \"{{ $env.TELEGRAM_CHAT_ID }}\",\n  \"text\": \"COPY OPTIMIZER PAUSED\\n\\nBoth variants are below the {{ $json.replyRateFloor }}% reply rate floor.\\n\\nChampion: {{ $json.champion.replyRate }}% ({{ $json.champion.sends }} sends)\\nChallenger: {{ $json.challenger.replyRate }}% ({{ $json.challenger.sends }} sends)\\n\\nThe optimizer has stopped experimenting. Review your copy manually and update the Active sheet to resume.\",\n  \"parse_mode\": \"HTML\"\n}","sendBody":true,"specifyBody":"json"},"typeVersion":4.2,"alwaysOutputData":true},{"id":"claude-evaluate","name":"Claude Evaluate and Generate","type":"n8n-nodes-base.httpRequest","notes":"Core optimization engine. Now receives program rules from Google Sheets and outputs a change_type field for structured experiment tracking.","position":[1568,400],"parameters":{"url":"https://api.anthropic.com/v1/messages","method":"POST","options":{},"jsonBody":"={\n  \"model\": \"claude-sonnet-4-6\",\n  \"max_tokens\": 2000,\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"You are a cold email optimization engine. Your job is to analyze performance data and generate better email copy.\\n\\nPROGRAM RULES (follow these strictly):\\n{{ $json.programRules }}\\n\\nACTION: {{ $json.action }}\\n\\nCURRENT CHAMPION:\\nSubject: {{ $json.champion.subject }}\\nBody: {{ $json.champion.body }}\\nSends: {{ $json.champion.sends }}\\nOpen Rate: {{ $json.champion.openRate }}%\\nReply Rate: {{ $json.champion.replyRate }}%\\n\\nCURRENT CHALLENGER:\\nSubject: {{ $json.challenger.subject }}\\nBody: {{ $json.challenger.body }}\\nSends: {{ $json.challenger.sends }}\\nOpen Rate: {{ $json.challenger.openRate }}%\\nReply Rate: {{ $json.challenger.replyRate }}%\\n\\nEXPERIMENT HISTORY (last 10 rounds):\\n{{ JSON.stringify($json.experimentHistory) }}\\n\\nTotal experiments run so far: {{ $json.totalExperiments }}\\n\\nINSTRUCTIONS:\\n1. If action is 'evaluate_and_generate': Declare a winner based on reply rate (primary) and open rate (secondary). Explain WHY the winner performed better, referencing patterns from experiment history. Then generate ONE new challenger that tests a specific hypothesis.\\n\\n2. If action is 'generate_first_challenger': Generate the first challenger variant based on the program rules and cold email best practices.\\n\\nRESPOND IN THIS EXACT JSON FORMAT:\\n{\\n  \\\"winner\\\": \\\"champion\\\" or \\\"challenger\\\" or \\\"none\\\",\\n  \\\"analysis\\\": \\\"2-3 sentences on what the data shows and patterns across rounds\\\",\\n  \\\"hypothesis\\\": \\\"what this new challenger is testing and why\\\",\\n  \\\"change_type\\\": \\\"subject_line\\\" or \\\"opener_style\\\" or \\\"cta\\\" or \\\"tone\\\" or \\\"length\\\" or \\\"social_proof\\\" or \\\"personalization_angle\\\",\\n  \\\"new_challenger_subject\\\": \\\"subject line\\\",\\n  \\\"new_challenger_body\\\": \\\"email body with {{personalization}} variable\\\",\\n  \\\"confidence\\\": \\\"high/medium/low\\\"\\n}\"\n    }\n  ]\n}","sendBody":true,"sendHeaders":true,"specifyBody":"json","headerParameters":{"parameters":[{"name":"x-api-key","value":"={{ $env.ANTHROPIC_API_KEY }}"},{"name":"anthropic-version","value":"2023-06-01"},{"name":"Content-Type","value":"application/json"}]}},"typeVersion":4.2,"alwaysOutputData":true},{"id":"code-parse","name":"Parse Claude Response","type":"n8n-nodes-base.code","notes":"Parses Claude output. Now extracts change_type for structured tracking.","position":[1792,400],"parameters":{"jsCode":"// Parse Claude's JSON response\nconst data = $input.first().json;\nconst raw = data.content?.[0]?.text || '';\n\nlet parsed;\ntry {\n  const jsonMatch = raw.match(/\\{[\\s\\S]*\\}/);\n  parsed = JSON.parse(jsonMatch[0]);\n} catch (e) {\n  throw new Error('Failed to parse Claude response: ' + raw.substring(0, 200));\n}\n\nconst previousData = $('Check Data Threshold').first().json;\n\nreturn [{\n  json: {\n    winner: parsed.winner,\n    analysis: parsed.analysis,\n    hypothesis: parsed.hypothesis,\n    changeType: parsed.change_type || 'unknown',\n    newChallengerSubject: parsed.new_challenger_subject,\n    newChallengerBody: parsed.new_challenger_body,\n    confidence: parsed.confidence,\n    previousChampion: previousData.champion,\n    previousChallenger: previousData.challenger,\n    experimentNumber: (previousData.totalExperiments || 0) + 1,\n    timestamp: new Date().toISOString()\n  }\n}];"},"typeVersion":2,"alwaysOutputData":true},{"id":"sheets-log","name":"Log Experiment to History","type":"n8n-nodes-base.httpRequest","notes":"Logs full experiment with change type. Column L tracks what specifically changed (subject, CTA, tone, etc.) so you can filter patterns by change type.","position":[2016,304],"parameters":{"url":"=https://sheets.googleapis.com/v4/spreadsheets/{{ $env.OPTIMIZER_SHEET_ID }}/values/Experiments!A:M:append?valueInputOption=USER_ENTERED","method":"POST","options":{},"jsonBody":"={\n  \"values\": [\n    [\n      \"{{ $json.experimentNumber }}\",\n      \"{{ $json.timestamp }}\",\n      \"{{ $json.previousChampion.body }}\",\n      \"{{ $json.previousChallenger.body }}\",\n      \"{{ $json.previousChampion.subject }}\",\n      \"{{ $json.previousChallenger.subject }}\",\n      \"{{ $json.previousChampion.sends }}\",\n      \"{{ $json.previousChallenger.sends }}\",\n      \"{{ $json.previousChampion.replyRate }}\",\n      \"{{ $json.previousChallenger.replyRate }}\",\n      \"{{ $json.winner }}\",\n      \"{{ $json.changeType }}\",\n      \"{{ $json.analysis }} | Hypothesis: {{ $json.hypothesis }}\"\n    ]\n  ]\n}","sendBody":true,"specifyBody":"json","authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"Fzpsut9akLL5grlP","name":"Header Auth account"}},"typeVersion":4.2,"alwaysOutputData":true},{"id":"sheets-update-active","name":"Update Active Variants","type":"n8n-nodes-base.httpRequest","notes":"Promotes winner, deploys new challenger. Resets counters for next round.","position":[2016,496],"parameters":{"url":"=https://sheets.googleapis.com/v4/spreadsheets/{{ $env.OPTIMIZER_SHEET_ID }}/values/Active!A2:F3?valueInputOption=USER_ENTERED","method":"PUT","options":{},"jsonBody":"={\n  \"values\": [\n    [\n      \"champion\",\n      \"{{ $json.winner === 'challenger' ? $json.previousChallenger.subject : $json.previousChampion.subject }}\",\n      \"{{ $json.winner === 'challenger' ? $json.previousChallenger.body : $json.previousChampion.body }}\",\n      \"0\",\n      \"0\",\n      \"0\"\n    ],\n    [\n      \"challenger\",\n      \"{{ $json.newChallengerSubject }}\",\n      \"{{ $json.newChallengerBody }}\",\n      \"0\",\n      \"0\",\n      \"0\"\n    ]\n  ]\n}","sendBody":true,"specifyBody":"json","authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"Fzpsut9akLL5grlP","name":"Header Auth account"}},"typeVersion":4.2,"alwaysOutputData":true},{"id":"instantly-update","name":"Update Instantly Campaign Copy","type":"n8n-nodes-base.httpRequest","notes":"Deploys promoted champion and new challenger as A/B variants in Instantly. Verify this matches your Instantly campaign sequence structure.","position":[2240,400],"parameters":{"url":"=https://api.instantly.ai/api/v2/campaigns/{{ $env.REMOVEFAST_CAMPAIGN_ID }}/sequences","method":"POST","options":{},"jsonBody":"={\n  \"sequences\": [\n    {\n      \"steps\": [\n        {\n          \"subject\": \"{{ $json.winner === 'challenger' ? $json.previousChallenger.subject : $json.previousChampion.subject }}\",\n          \"body\": \"{{ $json.winner === 'challenger' ? $json.previousChallenger.body : $json.previousChampion.body }}\"\n        }\n      ]\n    },\n    {\n      \"steps\": [\n        {\n          \"subject\": \"{{ $json.newChallengerSubject }}\",\n          \"body\": \"{{ $json.newChallengerBody }}\"\n        }\n      ]\n    }\n  ]\n}","sendBody":true,"sendHeaders":true,"specifyBody":"json","headerParameters":{"parameters":[{"name":"Authorization","value":"=Bearer {{ $env.INSTANTLY_API_KEY }}"},{"name":"Content-Type","value":"application/json"}]}},"typeVersion":4.2,"alwaysOutputData":true}],"active":false,"pinData":{},"settings":{"binaryMode":"separate","callerPolicy":"workflowsFromSameOwner","availableInMCP":false,"executionOrder":"v1","saveDataErrorExecution":"all","saveDataSuccessExecution":"all"},"versionId":"d56f89c4-6a2a-4612-9aa2-4629e0f5bacb","connections":{"Route by Action":{"main":[[{"node":"Safety Floor Check","type":"main","index":0}]]},"Read Program Doc":{"main":[[{"node":"Merge Stats and History","type":"main","index":0}]]},"Run Every 6 Hours":{"main":[[{"node":"Pull Instantly Campaign Stats","type":"main","index":0}]]},"Safety Floor Check":{"main":[[{"node":"Claude Evaluate and Generate","type":"main","index":0},{"node":"Telegram Safety Alert","type":"main","index":0}]]},"Check Data Threshold":{"main":[[{"node":"Route by Action","type":"main","index":0}]]},"Read Active Variants":{"main":[[{"node":"Merge Stats and History","type":"main","index":0}]]},"Parse Claude Response":{"main":[[{"node":"Log Experiment to History","type":"main","index":0},{"node":"Update Active Variants","type":"main","index":0}]]},"Update Active Variants":{"main":[[{"node":"Update Instantly Campaign Copy","type":"main","index":0}]]},"Merge Stats and History":{"main":[[{"node":"Check Data Threshold","type":"main","index":0}]]},"Read Experiment History":{"main":[[{"node":"Merge Stats and History","type":"main","index":0}]]},"Log Experiment to History":{"main":[[{"node":"Update Instantly Campaign Copy","type":"main","index":0}]]},"Claude Evaluate and Generate":{"main":[[{"node":"Parse Claude Response","type":"main","index":0}]]},"Pull Instantly Campaign Stats":{"main":[[{"node":"Read Experiment History","type":"main","index":0},{"node":"Read Active Variants","type":"main","index":0},{"node":"Read Program Doc","type":"main","index":0}]]}}},"lastUpdatedBy":29,"workflowInfo":{"nodeCount":20,"nodeTypes":{"n8n-nodes-base.code":{"count":5},"n8n-nodes-base.stickyNote":{"count":5},"n8n-nodes-base.httpRequest":{"count":9},"n8n-nodes-base.scheduleTrigger":{"count":1}}},"status":"published","readyToDemo":null,"user":{"name":"Devon Toh","username":"motomoto","bio":"Automation Consultant With 3 Years Experience. \n\nI help Sales and Marketing Teams to Streamline their workflows and system. \n\nHop on a call with me here \n- https://cal.com/devon-toh-vrmdab/30min","verified":true,"links":["https://www.baraco.ai"],"avatar":"https://gravatar.com/avatar/ac4d1aec81986fe98a61e31b22b1a3a2e2b0ef2046751b74760c8d0763c6ade8?r=pg&d=retro&size=200"},"nodes":[{"id":19,"icon":"file:httprequest.svg","name":"n8n-nodes-base.httpRequest","codex":{"data":{"alias":["API","Request","URL","Build","cURL"],"resources":{"generic":[{"url":"https://n8n.io/blog/2021-the-year-to-automate-the-new-you-with-n8n/","icon":"☀️","label":"2021: The Year to Automate the New You with n8n"},{"url":"https://n8n.io/blog/why-business-process-automation-with-n8n-can-change-your-daily-life/","icon":"🧬","label":"Why business process automation with n8n can change your daily life"},{"url":"https://n8n.io/blog/automatically-pulling-and-visualizing-data-with-n8n/","icon":"📈","label":"Automatically pulling and visualizing data with n8n"},{"url":"https://n8n.io/blog/learn-how-to-automatically-cross-post-your-content-with-n8n/","icon":"✍️","label":"Learn how to automatically cross-post your content with n8n"},{"url":"https://n8n.io/blog/automatically-adding-expense-receipts-to-google-sheets-with-telegram-mindee-twilio-and-n8n/","icon":"🧾","label":"Automatically Adding Expense Receipts to Google Sheets with Telegram, Mindee, Twilio, and n8n"},{"url":"https://n8n.io/blog/running-n8n-on-ships-an-interview-with-maranics/","icon":"🛳","label":"Running n8n on ships: An interview with Maranics"},{"url":"https://n8n.io/blog/what-are-apis-how-to-use-them-with-no-code/","icon":" 🪢","label":"What are APIs and how to use them with no code"},{"url":"https://n8n.io/blog/5-tasks-you-can-automate-with-notion-api/","icon":"⚡️","label":"5 tasks you can automate with the new Notion API "},{"url":"https://n8n.io/blog/world-poetry-day-workflow/","icon":"📜","label":"Celebrating World Poetry Day with a daily poem in Telegram"},{"url":"https://n8n.io/blog/automate-google-apps-for-productivity/","icon":"💡","label":"15 Google apps you can combine and automate to increase productivity"},{"url":"https://n8n.io/blog/automate-designs-with-bannerbear-and-n8n/","icon":"🎨","label":"Automate Designs with Bannerbear and n8n"},{"url":"https://n8n.io/blog/how-uproc-scraped-a-multi-page-website-with-a-low-code-workflow/","icon":" 🕸️","label":"How uProc scraped a multi-page website with a low-code workflow"},{"url":"https://n8n.io/blog/building-an-expense-tracking-app-in-10-minutes/","icon":"📱","label":"Building an expense tracking app in 10 minutes"},{"url":"https://n8n.io/blog/5-workflow-automations-for-mattermost-that-we-love-at-n8n/","icon":"🤖","label":"5 workflow automations for Mattermost that we love at n8n"},{"url":"https://n8n.io/blog/how-to-use-the-http-request-node-the-swiss-army-knife-for-workflow-automation/","icon":"🧰","label":"How to use the HTTP Request Node - The Swiss Army Knife for Workflow Automation"},{"url":"https://n8n.io/blog/learn-how-to-use-webhooks-with-mattermost-slash-commands/","icon":"🦄","label":"Learn how to use webhooks with Mattermost slash commands"},{"url":"https://n8n.io/blog/how-a-membership-development-manager-automates-his-work-and-investments/","icon":"📈","label":"How a Membership Development Manager automates his work and investments"},{"url":"https://n8n.io/blog/a-low-code-bitcoin-ticker-built-with-questdb-and-n8n-io/","icon":"📈","label":"A low-code bitcoin ticker built with QuestDB and n8n.io"},{"url":"https://n8n.io/blog/how-to-set-up-a-ci-cd-pipeline-with-no-code/","icon":"🎡","label":"How to set up a no-code CI/CD pipeline with GitHub and TravisCI"},{"url":"https://n8n.io/blog/automations-for-activists/","icon":"✨","label":"How Common Knowledge use workflow automation for activism"},{"url":"https://n8n.io/blog/creating-scheduled-text-affirmations-with-n8n/","icon":"🤟","label":"Creating scheduled text affirmations with n8n"},{"url":"https://n8n.io/blog/how-goomer-automated-their-operations-with-over-200-n8n-workflows/","icon":"🛵","label":"How Goomer automated their operations with over 200 n8n workflows"},{"url":"https://n8n.io/blog/aws-workflow-automation/","label":"7 no-code workflow automations for Amazon Web Services"}],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.httprequest/"}]},"categories":["Development","Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Helpers"]}}},"group":"[\"output\"]","defaults":{"name":"HTTP Request","color":"#0004F5"},"iconData":{"type":"file","fileBuffer":"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHZpZXdCb3g9IjAgMCA0MCA0MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik00MCAyMEM0MCA4Ljk1MzE0IDMxLjA0NjkgMCAyMCAwQzguOTUzMTQgMCAwIDguOTUzMTQgMCAyMEMwIDMxLjA0NjkgOC45NTMxNCA0MCAyMCA0MEMzMS4wNDY5IDQwIDQwIDMxLjA0NjkgNDAgMjBaTTIwIDM2Ljk0NThDMTguODg1MiAzNi45NDU4IDE3LjEzNzggMzUuOTY3IDE1LjQ5OTggMzIuNjk4NUMxNC43OTY0IDMxLjI5MTggMTQuMTk2MSAyOS41NDMxIDEzLjc1MjYgMjcuNjg0N0gyNi4xODk4QzI1LjgwNDUgMjkuNTQwMyAyNS4yMDQ0IDMxLjI5MDEgMjQuNTAwMiAzMi42OTg1QzIyLjg2MjIgMzUuOTY3IDIxLjExNDggMzYuOTQ1OCAyMCAzNi45NDU4Wk0xMi45MDY0IDIwQzEyLjkwNjQgMjEuNjA5NyAxMy4wMDg3IDIzLjE2NCAxMy4yMDAzIDI0LjYzMDVIMjYuNzk5N0MyNi45OTEzIDIzLjE2NCAyNy4wOTM2IDIxLjYwOTcgMjcuMDkzNiAyMEMyNy4wOTM2IDE4LjM5MDMgMjYuOTkxMyAxNi44MzYgMjYuNzk5NyAxNS4zNjk1SDEzLjIwMDNDMTMuMDA4NyAxNi44MzYgMTIuOTA2NCAxOC4zOTAzIDEyLjkwNjQgMjBaTTIwIDMuMDU0MTlDMjEuMTE0OSAzLjA1NDE5IDIyLjg2MjIgNC4wMzA3OCAyNC41MDAxIDcuMzAwMzlDMjUuMjA2NiA4LjcxNDA4IDI1LjgwNzIgMTAuNDA2NyAyNi4xOTIgMTIuMzE1M0gxMy43NTAxQzE0LjE5MzMgMTAuNDA0NyAxNC43OTQyIDguNzEyNTQgMTUuNDk5OCA3LjMwMDY0QzE3LjEzNzcgNC4wMzA4MyAxOC44ODUxIDMuMDU0MTkgMjAgMy4wNTQxOVpNMzAuMTQ3OCAyMEMzMC4xNDc4IDE4LjQwOTkgMzAuMDU0MyAxNi44NjE3IDI5LjgyMjcgMTUuMzY5NUgzNi4zMDQyQzM2LjcyNTIgMTYuODQyIDM2Ljk0NTggMTguMzk2NCAzNi45NDU4IDIwQzM2Ljk0NTggMjEuNjAzNiAzNi43MjUyIDIzLjE1OCAzNi4zMDQyIDI0LjYzMDVIMjkuODIyN0MzMC4wNTQzIDIzLjEzODMgMzAuMTQ3OCAyMS41OTAxIDMwLjE0NzggMjBaTTI2LjI3NjcgNC4yNTUxMkMyNy42MzY1IDYuMzYwMTkgMjguNzExIDkuMTMyIDI5LjM3NzQgMTIuMzE1M0gzNS4xMDQ2QzMzLjI1MTEgOC42NjggMzAuMTA3IDUuNzgzNDYgMjYuMjc2NyA0LjI1NTEyWk0xMC42MjI2IDEyLjMxNTNINC44OTI5M0M2Ljc1MTQ3IDguNjY3ODQgOS44OTM1MSA1Ljc4MzQxIDEzLjcyMzIgNC4yNTUxM0MxMi4zNjM1IDYuMzYwMjEgMTEuMjg5IDkuMTMyMDEgMTAuNjIyNiAxMi4zMTUzWk0zLjA1NDE5IDIwQzMuMDU0MTkgMjEuNjAzIDMuMjc3NDMgMjMuMTU3NSAzLjY5NDg0IDI0LjYzMDVIMTAuMTIxN0M5Ljk0NjE5IDIzLjE0MiA5Ljg1MjIyIDIxLjU5NDMgOS44NTIyMiAyMEM5Ljg1MjIyIDE4LjQwNTcgOS45NDYxOSAxNi44NTggMTAuMTIxNyAxNS4zNjk1SDMuNjk0ODRDMy4yNzc0MyAxNi44NDI1IDMuMDU0MTkgMTguMzk3IDMuMDU0MTkgMjBaTTI2LjI3NjYgMzUuNzQyN0MyNy42MzY1IDMzLjYzOTMgMjguNzExIDMwLjg2OCAyOS4zNzc0IDI3LjY4NDdIMzUuMTA0NkMzMy4yNTEgMzEuMzMyMiAzMC4xMDY4IDM0LjIxNzkgMjYuMjc2NiAzNS43NDI3Wk0xMy43MjM0IDM1Ljc0MjdDOS44OTM2OSAzNC4yMTc5IDYuNzUxNTUgMzEuMzMyNCA0Ljg5MjkzIDI3LjY4NDdIMTAuNjIyNkMxMS4yODkgMzAuODY4IDEyLjM2MzUgMzMuNjM5MyAxMy43MjM0IDM1Ljc0MjdaIiBmaWxsPSIjM0E0MkU5Ii8+Cjwvc3ZnPgo="},"displayName":"HTTP Request","typeVersion":4,"nodeCategories":[{"id":5,"name":"Development"},{"id":9,"name":"Core Nodes"}]},{"id":565,"icon":"fa:sticky-note","name":"n8n-nodes-base.stickyNote","codex":{"data":{"alias":["Comments","Notes","Sticky"],"categories":["Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Helpers"]}}},"group":"[\"input\"]","defaults":{"name":"Sticky Note","color":"#FFD233"},"iconData":{"icon":"sticky-note","type":"icon"},"displayName":"Sticky Note","typeVersion":1,"nodeCategories":[{"id":9,"name":"Core Nodes"}]},{"id":834,"icon":"file:code.svg","name":"n8n-nodes-base.code","codex":{"data":{"alias":["cpde","Javascript","JS","Python","Script","Custom Code","Function"],"details":"The Code node allows you to execute JavaScript in your workflow.","resources":{"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.code/"}]},"categories":["Development","Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Helpers","Data Transformation"]}}},"group":"[\"transform\"]","defaults":{"name":"Code"},"iconData":{"type":"file","fileBuffer":"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTEyIiBoZWlnaHQ9IjUxMiIgdmlld0JveD0iMCAwIDUxMiA1MTIiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMF8xMTcxXzQ0MSkiPgo8cGF0aCBkPSJNMTcwLjI4MyA0OEgxOTYuNUMyMDMuMTI3IDQ4IDIwOC41IDQyLjYyNzQgMjA4LjUgMzZWMTJDMjA4LjUgNS4zNzI1OCAyMDMuMTI3IDAgMTk2LjUgMEgxNzAuMjgzQzEyNi4xIDAgOTAuMjgzIDM1LjgxNzIgOTAuMjgzIDgwVjE3NkM5MC4yODMgMjA2LjkyOCA2NS4yMTA5IDIzMiAzNC4yODMgMjMySDIzQzE2LjM3MjYgMjMyIDExIDIzNy4zNzIgMTEgMjQ0VjI2OEMxMSAyNzQuNjI3IDE2LjM3MjQgMjgwIDIyLjk5OTYgMjgwTDM0LjI4MyAyODBDNjUuMjEwOSAyODAgOTAuMjgzIDMwNS4wNzIgOTAuMjgzIDMzNlY0NDBDOTAuMjgzIDQ3OS43NjQgMTIyLjUxOCA1MTIgMTYyLjI4MyA1MTJIMTk2LjVDMjAzLjEyNyA1MTIgMjA4LjUgNTA2LjYyNyAyMDguNSA1MDBWNDc2QzIwOC41IDQ2OS4zNzMgMjAzLjEyNyA0NjQgMTk2LjUgNDY0SDE2Mi4yODNDMTQ5LjAyOCA0NjQgMTM4LjI4MyA0NTMuMjU1IDEzOC4yODMgNDQwVjMzNkMxMzguMjgzIDMwOS4wMjIgMTI4LjAxMSAyODQuNDQzIDExMS4xNjQgMjY1Ljk2MUMxMDYuMTA5IDI2MC40MTYgMTA2LjEwOSAyNTEuNTg0IDExMS4xNjQgMjQ2LjAzOUMxMjguMDExIDIyNy41NTcgMTM4LjI4MyAyMDIuOTc4IDEzOC4yODMgMTc2VjgwQzEzOC4yODMgNjIuMzI2OSAxNTIuNjEgNDggMTcwLjI4MyA0OFoiIGZpbGw9IiNGRjk5MjIiLz4KPHBhdGggZD0iTTMwNSAzNkMzMDUgNDIuNjI3NCAzMTAuMzczIDQ4IDMxNyA0OEgzNDIuOTc5QzM2MC42NTIgNDggMzc0Ljk3OCA2Mi4zMjY5IDM3NC45NzggODBWMTc2QzM3NC45NzggMjAyLjk3OCAzODUuMjUxIDIyNy41NTcgNDAyLjA5OCAyNDYuMDM5QzQwNy4xNTMgMjUxLjU4NCA0MDcuMTUzIDI2MC40MTYgNDAyLjA5OCAyNjUuOTYxQzM4NS4yNTEgMjg0LjQ0MyAzNzQuOTc4IDMwOS4wMjIgMzc0Ljk3OCAzMzZWNDMyQzM3NC45NzggNDQ5LjY3MyAzNjAuNjUyIDQ2NCAzNDIuOTc5IDQ2NEgzMTdDMzEwLjM3MyA0NjQgMzA1IDQ2OS4zNzMgMzA1IDQ3NlY1MDBDMzA1IDUwNi42MjcgMzEwLjM3MyA1MTIgMzE3IDUxMkgzNDIuOTc5QzM4Ny4xNjEgNTEyIDQyMi45NzggNDc2LjE4MyA0MjIuOTc4IDQzMlYzMzZDNDIyLjk3OCAzMDUuMDcyIDQ0OC4wNTEgMjgwIDQ3OC45NzkgMjgwSDQ5MEM0OTYuNjI3IDI4MCA1MDIgMjc0LjYyOCA1MDIgMjY4VjI0NEM1MDIgMjM3LjM3MyA0OTYuNjI4IDIzMiA0OTAgMjMyTDQ3OC45NzkgMjMyQzQ0OC4wNTEgMjMyIDQyMi45NzggMjA2LjkyOCA0MjIuOTc4IDE3NlY4MEM0MjIuOTc4IDM1LjgxNzIgMzg3LjE2MSAwIDM0Mi45NzkgMEgzMTdDMzEwLjM3MyAwIDMwNSA1LjM3MjU4IDMwNSAxMlYzNloiIGZpbGw9IiNGRjk5MjIiLz4KPC9nPgo8ZGVmcz4KPGNsaXBQYXRoIGlkPSJjbGlwMF8xMTcxXzQ0MSI+CjxyZWN0IHdpZHRoPSI1MTIiIGhlaWdodD0iNTEyIiBmaWxsPSJ3aGl0ZSIvPgo8L2NsaXBQYXRoPgo8L2RlZnM+Cjwvc3ZnPgo="},"displayName":"Code","typeVersion":2,"nodeCategories":[{"id":5,"name":"Development"},{"id":9,"name":"Core Nodes"}]},{"id":839,"icon":"fa:clock","name":"n8n-nodes-base.scheduleTrigger","codex":{"data":{"alias":["Time","Scheduler","Polling","Cron","Interval"],"resources":{"generic":[],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.scheduletrigger/"}]},"categories":["Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0"}},"group":"[\"trigger\",\"schedule\"]","defaults":{"name":"Schedule Trigger","color":"#31C49F"},"iconData":{"icon":"clock","type":"icon"},"displayName":"Schedule Trigger","typeVersion":1,"nodeCategories":[{"id":9,"name":"Core Nodes"}]}],"categories":[{"id":38,"name":"Lead Nurturing"},{"id":49,"name":"AI Summarization"}],"image":[]}}