DEV Community

Pirate Prentice
Pirate Prentice

Posted on

n8n Webhook Routing: Conditional Logic That Actually Works (No Coding Required)

n8n Webhook Routing: Conditional Logic That Actually Works (No Coding Required)

TL;DR: Most n8n users blast all webhook data into one workflow and chaos ensues. The fix? Use a Router node to conditionally split data based on conditions (lead vs. customer vs. error). One webhook, multiple destinations, zero code.


The Problem: "Webhook Chaos"

You've set up a webhook. Maybe it's Typeform submissions, Stripe events, or Calendly bookings. Now you realize: the same webhook endpoint receives different types of data, and you need to handle them differently.

Real scenario: You're tracking form submissions via Typeform. The form has 3 different pages depending on user input:

  • Page 1: Lead capture (name + email)
  • Page 2: Customer survey (existing customer feedback)
  • Page 3: Error log (customer report a bug)

All three send to the same webhook URL.

Without routing, your workflow becomes spaghetti:

Webhook trigger
↓ Check type (if/else/if/else/if/else)
├─ If lead: send Slack message
├─ If customer: add to CRM
└─ If error: create ticket + alert team
Enter fullscreen mode Exit fullscreen mode

With nested conditions, it's unmaintainable. With routing, it's clean.


Solution: The Router Node

The Router node is n8n's secret weapon for splitting data streams. It evaluates conditions and sends data to the correct output branch automatically.

Syntax is simple:

If condition → output branch 1
Else if condition → output branch 2
Else → default output
Enter fullscreen mode Exit fullscreen mode

Step-by-Step: Typeform Webhook Routing

Setup: Three Typeform Workflows

You have one Typeform and three potential outcomes. You need three separate branches in n8n, not three separate workflows.

Why? A single workflow with routing is cleaner than 3 webhooks / 3 workflows.

Step 1: Webhook Trigger

Trigger: Webhook
Webhook URL: https://your-n8n.com/webhook/typeform-router
Method: POST
Enter fullscreen mode Exit fullscreen mode

When Typeform submits data, it hits this webhook. The webhook returns the form response object, which includes:

  • answers[] — array of user responses
  • form_id — Typeform ID
  • response_id — unique response ID

For this example, assume Typeform is configured to send a "form_type" field in the JSON:

{
  "form_id": "abc123",
  "response_id": "resp_xyz",
  "form_type": "lead_capture",
  "answers": [
    { "field_id": "q1", "text": "John Doe" },
    { "field_id": "q2", "email": "john@example.com" }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Add Router Node

After the Webhook trigger, add a Router node.

Router node settings:

  • Output 1: Condition = {{ $json.form_type === "lead_capture" }}
  • Output 2: Condition = {{ $json.form_type === "customer_survey" }}
  • Output 3: Condition = {{ $json.form_type === "error_report" }}
  • Default output: (anything that doesn't match)

Step 3: Add Nodes per Branch

Now you have 3 output branches from the Router. Connect each to its own action:

Branch 1 (Lead Capture):

Router Output 1
  ↓
Format Slack message
  ↓
Send Slack notification to #leads channel
Enter fullscreen mode Exit fullscreen mode

Branch 2 (Customer Survey):

Router Output 2
  ↓
Extract customer feedback
  ↓
Add to HubSpot as activity
  ↓
Send thank-you email (Resend/Brevo)
Enter fullscreen mode Exit fullscreen mode

Branch 3 (Error Report):

Router Output 3
  ↓
Create GitHub issue with error details
  ↓
Send alert to #urgent-bugs Slack channel
Enter fullscreen mode Exit fullscreen mode

Real Code Example: Airtable Lead Routing

Let's say you're syncing leads from Typeform → Airtable, but different fields matter for different lead types.

Scenario:

  • B2B leads get tagged in Airtable with "Enterprise" (use in HubSpot later)
  • B2C leads get auto-replied immediately (send email)
  • Inbound support requests go to a separate table

Webhook → Router → Conditional Branches:

Webhook (Typeform)
  ↓
Router
  ├─ Output 1: $json.business_type === "B2B"
  │   └─ Add to Airtable [Leads] with tag "Enterprise"
  │   └─ (Optional) Webhook to HubSpot to notify sales team
  │
  ├─ Output 2: $json.business_type === "B2C"
  │   └─ Add to Airtable [Leads] with tag "Consumer"
  │   └─ Send auto-reply email
  │
  └─ Output 3: $json.request_type === "support"
      └─ Add to Airtable [Support Tickets]
      └─ Assign to support team Slack channel
Enter fullscreen mode Exit fullscreen mode

Each branch is independent. No interference, no spaghetti logic.


Why SMBs Need Webhook Routing

Real pain point: You're managing 50+ leads per day from multiple sources (Typeform, LinkedIn, website contact form, referrals). Without routing:

  • Leads end up in wrong fields
  • Follow-ups go to wrong people
  • Duplicate entries in CRM
  • Sales team misses half the leads

With routing: Each lead type flows to its correct destination. No manual sorting. No "oops, missed that one."


Advanced: Routing by HTTP Header or URL Parameter

Sometimes Typeform (or other services) don't include a type field in the JSON. You can route based on:

Option 1: Different Webhook URLs (cleanest)

https://your-n8n.com/webhook/typeform-leads
https://your-n8n.com/webhook/typeform-support
https://your-n8n.com/webhook/typeform-survey
Enter fullscreen mode Exit fullscreen mode

Then each webhook feeds into its own workflow. (But this defeats the purpose of a single Router.)

Option 2: Query Parameter

https://your-n8n.com/webhook/typeform?type=lead_capture
Enter fullscreen mode Exit fullscreen mode

Access in n8n: {{ $url.query.type }}

Then route on: {{ $url.query.type === "lead_capture" }}

Option 3: HTTP Header

Typeform can send a custom header: X-Form-Type: lead_capture

Access in n8n: {{ $headers.get('x-form-type') }}

Then route on: {{ $headers.get('x-form-type') === "lead_capture" }}


Common Gotchas & Fixes

Gotcha 1: Condition returns wrong type

$json.age === 21  // ✓ correct
$json.age == "21" // ✗ wrong (string vs number)
Enter fullscreen mode Exit fullscreen mode

Always use === (strict equality). Check data types in the test panel.

Gotcha 2: Router has no output branches

If all conditions fail → Router output is empty → workflow stops.
Enter fullscreen mode Exit fullscreen mode

Fix: Always add a default output to catch unmatched data. Log it or send to a fallback workflow.

Gotcha 3: Nested Router nodes (routing → routing → routing)

Router 1
  ├─ Output 1 → Router 2
  │   ├─ Output 1 → Action A
  │   └─ Output 2 → Action B
  └─ Output 2 → Action C
Enter fullscreen mode Exit fullscreen mode

This works, but it's hard to debug. Use flat routing when possible.


Case Study: Slack Webhook Routing

Real example: A team uses Slack for everything (sales leads, support tickets, billing alerts). Without routing, all notifications blend together. No priority. Everything feels urgent.

Solution: Webhook routing + Slack channel assignment

Incoming webhook (could be from Zapier, IFTTT, custom API)
  ↓
Router (check message priority)
  ├─ HIGH priority (payment failure, security alert)
  │   └─ Send to #urgent-alerts (red color, @channel ping)
  │
  ├─ MEDIUM priority (new lead, customer reply)
  │   └─ Send to #sales (yellow color, normal ping)
  │
  └─ LOW priority (form submission, feedback)
      └─ Send to #feedback (blue color, no ping)
Enter fullscreen mode Exit fullscreen mode

Result: Slack channels stay organized. People see what matters first. Alerts don't drown in noise.


Next Steps: Level Up Your Routing

After you master basic routing, try:

  1. Routing + Batch: Collect 10 leads, batch them, then route the batch
  2. Routing + Error Handling: Route successful/failed API responses separately
  3. Routing + Database Lookups: Route based on whether a lead exists in Airtable (existing vs. new)

Takeaway

Webhook routing is the difference between:

  • ❌ One chaotic workflow that handles 5 different things badly
  • ✅ Five clean branches that each do one thing well

If you're managing multiple data sources or lead types, Router is non-negotiable.


Ready to Build This?

The $99 audit includes:

  • Mapping your current data sources → n8n routing strategy
  • Identifying which conditions matter (business type? priority? source?)
  • Building your first Router workflow (15–30 min per source)

The $299/mo retainer includes:

  • Ongoing workflow tuning as your data sources change
  • Performance optimization (batch vs. real-time routing)
  • Support when conditions need tweaking

Get a free audit or book a retainer.


Questions? Drop a comment below or check out n8n's Router docs.

Top comments (0)