Skip to main content
Intermediate

Human-in-the-Loop Approvals in n8n

Implement approval workflows where humans review and approve AI-generated content before it goes live

Tools Required

n8n Slack Airtable

Tags

Automation Workflows AI

Human-in-the-Loop Approvals in n8n

Sometimes AI gets it 90% right, but you need human oversight for that final 10%. Here’s how to build approval workflows in n8n.

Use Cases

  • Approve AI-generated emails before sending
  • Review content before publishing
  • Validate data before writing to production database
  • Sign off on high-value transactions

Workflow Structure

1. AI generates content

2. Save to Airtable with "pending" status

3. Send Slack message with preview + buttons

4. Wait for button click

5. If approved → proceed
   If rejected → skip or modify

Step-by-Step

1. Generate Content

// In Function node
const content = {
  id: $input.item.json.id,
  subject: "...",
  body: "...",
  recipient: "...",
  status: "pending_approval"
};

return content;

2. Save to Airtable

Create Airtable base with columns:

  • ID (unique)
  • Content (JSON)
  • Status (Single select: pending, approved, rejected)
  • Approver
  • Timestamp

3. Send Slack Message

Use Slack’s Block Kit for rich formatting:

{
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "*New email pending approval*"
      }
    },
    {
      "type": "section",
      "fields": [
        {"type": "mrkdwn", "text": "*To:*\n{{recipient}}"},
        {"type": "mrkdwn", "text": "*Subject:*\n{{subject}}"}
      ]
    },
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "{{body}}"
      }
    },
    {
      "type": "actions",
      "elements": [
        {
          "type": "button",
          "text": {"type": "plain_text", "text": "Approve"},
          "style": "primary",
          "value": "approve_{{id}}"
        },
        {
          "type": "button",
          "text": {"type": "plain_text", "text": "Reject"},
          "style": "danger",
          "value": "reject_{{id}}"
        }
      ]
    }
  ]
}

4. Wait for Approval

Two approaches:

A) Webhook approach (simpler)

  • Create webhook to receive Slack button clicks
  • Slack button click → triggers new workflow
  • Update Airtable status
  • Original workflow polls Airtable every 30s

B) n8n Wait node (better)

  • Use Wait node in workflow
  • Generate unique resume URL
  • Include URL in Slack button action
  • Clicking button resumes workflow

5. Process Result

// Check approval status
if ($input.item.json.status === 'approved') {
  // Send email, publish content, etc.
  return { approved: true };
} else {
  // Log rejection, notify creator
  return { approved: false };
}

Tips

  • Set timeout: Auto-reject after 24 hours if no response
  • Track approver: Record who approved for audit trail
  • Allow editing: Let approvers modify content before approving
  • Bulk approval: Process multiple items at once

Example: Email Approval Workflow

Real workflow I use for AI-generated sales emails:

  1. AI drafts 50 emails
  2. Batch them in groups of 10
  3. Send each batch to Slack for review
  4. SDR approves/rejects each
  5. Approved emails → SendGrid queue (rate-limited)
  6. Rejected emails → saved for analysis

Result: 95% approval rate, SDR only reviews instead of writing from scratch.

Common Pitfalls

❌ Not handling timeouts ❌ Losing context between approval and action ❌ No way to edit before approving ❌ Not tracking who approved what

Start with simple approve/reject, add editing capabilities later.