Integration 2026-05-01 14 min read

How to Integrate Claude Code with n8n: Event-Driven AI Automation (2026)

n8n handles events, webhooks, and workflow orchestration. Claude Code handles reasoning, file operations, and autonomous tasks. Together they cover everything a modern automation stack needs. This guide shows the exact integration patterns we use in production.

What you'll learn
  1. Why n8n + Claude Code (not just one or the other)
  2. Pattern 1: n8n triggers Claude Code via SSH
  3. Pattern 2: Claude Code calls n8n webhooks
  4. Pattern 3: Shared state via Supabase
  5. Pattern 4: Human-in-the-loop escalation
  6. Production architecture we run

Our setup: We run 20+ Claude Code agents with n8n on Hostinger (self-hosted). n8n handles email sequences, Telegram notifications, Supabase writes, and webhook routing. Claude Code agents handle content creation, analysis, reporting, and browser automation. Total cost: ~€300/month.

Why n8n + Claude Code (not either alone)

Both tools have hard limits that the other fills:

Capabilityn8nClaude Code
Event triggers (webhooks, cron, email)✓ nativeManual only
Service integrations (Gmail, Slack, Sheets)✓ 400+ nodesVia bash/API only
Long-running autonomous tasksLimited (timeout)✓ native
Reasoning over unstructured dataBasic AI nodes✓ native
File operations, code executionLimited✓ native
Multi-step decision treesComplex to build✓ via CLAUDE.md

The split: n8n owns events and integrations. Claude Code owns reasoning and execution. n8n is the nervous system. Claude Code is the brain.

Pattern 1: n8n Triggers a Claude Code Agent via SSH

The simplest integration: n8n detects an event (new email, form submission, schedule) and fires a Claude Code agent on your server.

n8n workflow setup

In n8n, use an SSH node to run Claude Code on your VPS:

# n8n SSH node configuration:
Host: your-server-ip
Port: 22
Username: claude
Auth: Private Key

# Command to execute:
cd /home/claude/project && claude -p "{{ $json.task }}" \
  --allowedTools Read,Write,Bash,LS \
  --output-format json 2>&1

In the n8n node, map the task variable from whatever triggered the workflow (form data, email subject, webhook body).

Passing data to the agent

# Write task data to a file before running the agent
echo '{{ JSON.stringify($json) }}' > /tmp/n8n-task.json && \
cd /home/claude/project && \
claude -p "Read /tmp/n8n-task.json and process the task defined there" \
  --allowedTools Read,Write,Bash,LS

Why write to file instead of passing inline? JSON in bash strings breaks on special characters. Writing to a file first is reliable at any data size. The agent reads it with the Read tool automatically.

Reading the result back in n8n

Have the agent write output to a known file, then read it in n8n:

# In CLAUDE.md:
## Output
Write your result as JSON to /tmp/agent-output.json:
{"status": "done", "result": "...", "errors": []}

# n8n: second SSH node reads the file:
cat /tmp/agent-output.json

Pattern 2: Claude Code Agent Calls n8n Webhooks

The reverse: a Claude Code agent decides to trigger something in n8n — send an email, notify a Slack channel, write to a database.

In your CLAUDE.md

# CLAUDE.md — Agent with n8n notification

## Escalation (use when task is complete or blocked)
Call the n8n webhook to report results:

curl -s -X POST https://your-n8n-host/webhook/agent-report \
  -H "Content-Type: application/json" \
  -d '{"agent": "content-writer", "status": "done", "output": "report.md", "errors": 0}'

## Trigger conditions
- Call webhook AFTER writing final output to file
- Call webhook if error occurs more than twice
- NEVER call webhook without a status and output path

n8n webhook receiver workflow

In n8n: Webhook node → Switch node (route by status) → branches:

# n8n webhook receives from agent, routes by status
Webhook (POST /webhook/agent-report)
  → Switch on {{ $json.body.status }}
    → "done"    → Telegram: "✅ {{ $json.body.agent }} complete"
    → "error"   → Telegram: "❌ {{ $json.body.agent }}: {{ $json.body.error }}"
    → "escalate"→ Gmail + Telegram + Notion task create

Pattern 3: Shared State via Supabase

For multi-agent systems where agents and n8n workflows need to share state, a shared database is cleaner than direct HTTP calls.

n8n writes: trial_signups, upgrade_requests, email_status
Agents read: pending tasks, new signups, config flags
Agents write: task results, heartbeats, KPI data
n8n reads: agent outputs to trigger emails/notifications

n8n: Write to Supabase on signup

# n8n HTTP Request node:
Method: POST
URL: http://your-supabase-host/rest/v1/trial_signups
Headers:
  apikey: {{ $env.SUPABASE_ANON_KEY }}
  Content-Type: application/json
  Prefer: return=minimal
Body:
{
  "email": "{{ $json.body.email }}",
  "name": "{{ $json.body.name }}",
  "signed_up_at": "{{ $now.toISO() }}",
  "status": "active"
}

Claude Code agent: Read pending tasks from Supabase

# In agent bash tool:
curl -s "http://your-supabase-host/rest/v1/tasks?status=eq.pending&limit=5" \
  -H "apikey: $SUPABASE_ANON_KEY" \
  -H "Authorization: Bearer $SUPABASE_ANON_KEY" | jq '.[] | {id, task_type, payload}'

Self-hosted Supabase tip: If you're running Supabase on your own VPS (we use Hostinger), the URL is your server IP, not the cloud console URL. The anon key comes from your .env file, not the Supabase dashboard.

Pattern 4: Human-in-the-Loop Escalation

The most important pattern for production: when an agent hits something it can't handle, it escalates through n8n to a human — then waits for the response.

Agent side (CLAUDE.md)

## Escalation triggers — call webhook and STOP
Conditions:
- Task requires spending > €50
- Output would be sent externally (email, social post)
- Error on same step more than 2 times
- Decision requires information not in context

When escalating:
1. Write current state to /tmp/escalation-state.json
2. POST to https://n8n-host/webhook/human-escalation
3. STOP. Do not continue until webhook confirms.

Escalation payload:
{
  "agent": "your-agent-name",
  "reason": "brief description",
  "state_file": "/tmp/escalation-state.json",
  "question": "what do you need from human?"
}

n8n escalation workflow

Webhook (POST /webhook/human-escalation)
  → Telegram: "🚨 Agent needs input: {{ $json.body.question }}"
  → Wait for Webhook (POST /webhook/human-response)
  → SSH: echo '{{ $json.body.answer }}' > /tmp/human-response.txt
  → Telegram: "✅ Response sent to agent"

The agent polls for the response file:

# In agent bash — poll every 30s up to 10 min
for i in $(seq 1 20); do
  if [ -f /tmp/human-response.txt ]; then
    cat /tmp/human-response.txt
    break
  fi
  sleep 30
done

Our Production Architecture

Here's exactly how we wire n8n and Claude Code in our live system:

EVENTS (n8n on Hostinger)
├── Trial signup → Supabase INSERT → 6-email sequence start
├── Upgrade request → Telegram Daniel + Supabase log
├── Cron 09:00 → SSH → content-writer agent → blog post published
├── Cron hourly → SSH → kpi-agent → Supabase KPI table
└── Watchdog timer → check agent heartbeats → alert if stale

EXECUTION (Claude Code on netcup VPS)
├── CEO agent → reads strategy_status.md → coordinates HoDs
├── Marketing agent → writes posts → webhook to n8n → Telegram
├── ICT agent → monitors services → SSH to ops server if issues
└── Strategy agent → KPI checks → writes shared-memory/ → webhook alert

Key wiring rules we learned

Common mistake: Calling Claude via the n8n AI Agent node for long-running tasks. The n8n AI Agent node has execution time limits and doesn't support file system access. Use SSH to run Claude Code on a server for anything requiring tools or lasting more than 30 seconds.

Minimal working example: Email-to-Agent pipeline

Full end-to-end: new email arrives → Claude Code analyzes it → response drafted → Telegram approval → sent.

# n8n workflow (simplified):
Gmail Trigger (new email)
  → Filter: not promotional
  → SSH node: echo '{{ $json }}' > /tmp/email.json
  → SSH node: claude -p "Read /tmp/email.json, draft a reply in /tmp/reply.txt"
  → Read File: /tmp/reply.txt
  → Telegram: "Reply draft:\n{{ $json.data }}\n\nSend? Reply YES/NO"
  → Wait for Telegram response
  → If YES: Gmail Send node
  → If NO: Telegram "Discarded. Reply with edits to resend."

Want the full n8n + Claude Code workflow templates?

The 7-day free trial includes our production n8n workflow exports, the CLAUDE.md files for each agent tier, and the Supabase schema we use. Real files, not examples built for a course.

Start Free Trial →