n8n-campaign-ops
Generates client-specific n8n workflow configurations for campaign operations — Clay-to-sequencer pipeline, CRM syncing, bounce monitoring, Slack alerting, and error handling. Updated each time a new trigger play is activated for a client. Reads profile.md, strategy.md, and active workflow files to produce per-play n8n specs. Outputs Prospects/{client-slug}/n8n-config.md. Triggers on "n8n setup", "campaign operations", "Clay n8n integration", "CRM sync", "bounce monitoring", "Slack alerts", "workflow automation", "lead routing n8n", "error handling campaign", "campaign monitoring". Do NOT use for general n8n knowledge (use ColdIQ n8n reference skills) or email infrastructure setup (use /deliverability-setup).
How do I install this agent skill?
npx skills add https://github.com/thrustlab-io/thrustlab-skills-library --skill n8n-campaign-opsIs this agent skill safe to install?
- Gen Agent Trust Hubpass
This skill generates n8n workflow configurations for campaign operations by analyzing local project files. It provides architectural blueprints for lead routing, monitoring, and CRM integration without executing remote code or exposing sensitive credentials.
- Socketpass
No alerts
- Snykpass
Risk: LOW · No issues
What does this agent skill do?
n8n Campaign Operations
Generates client-specific n8n workflow specifications for the operational layer that sits between Clay (enrichment) and the sequencer (sending). This is the nervous system of the GTM machine — it routes leads, monitors health, alerts on problems, and logs everything.
This is NOT "how to use n8n." This is "what n8n workflows does THIS client need for THEIR active plays."
Prerequisites:
Prospects/{client-slug}/profile.mdexistsProspects/{client-slug}/strategy.mdexists- At least one workflow has been built (
Prospects/{client-slug}/workflows/workflow-*.md) /deliverability-setuphas been run (sending infrastructure is configured or in warmup)- Client has n8n access (cloud or self-hosted) — if not, include setup recommendation
Output: Prospects/{client-slug}/n8n-config.md
Update cadence: Re-run this skill each time a new trigger play goes live. The config is additive — new plays add workflows, they don't replace existing ones.
Workflow
Step 1: Load Client Context
Read all available files:
From profile.md:
- CRM in use (HubSpot, Salesforce, Pipedrive, or none)
- Existing automation tools (Zapier, Make, or n8n already?)
- Team structure (who monitors campaigns, who follows up on leads)
- Slack workspace (for alert routing)
- Tech comfort level (determines how detailed the n8n specs need to be)
From strategy.md:
- Active trigger plays and their priority order
- Signal stacking configuration (if multiple plays are active)
- Cadence structure (email-only, email+LinkedIn, multichannel)
- ICP scoring thresholds (Hot/Warm/Active from signal stacking guide)
From active workflow files (Prospects/{slug}/workflows/):
- Which Clay tables exist and their column schemas
- Enrichment sequences per play
- Copy variant structure (ATL/BTL branches)
- Sequencer campaign names
From deliverability-config.md:
- Active sending domains and mailboxes
- Monitoring thresholds (bounce, spam, open rate)
- Sending windows and limits
Step 2: Design Core n8n Architecture
Every client gets the same architectural pattern, customized to their stack:
┌─────────────────────────────────────────────────────┐
│ CLIENT n8n INSTANCE │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ INBOUND │ │ PROCESS │ │ OUTBOUND │ │
│ │ │ │ │ │ │ │
│ │ Clay │───▶│ Validate │───▶│ Sequencer │ │
│ │ Webhooks │ │ Route │ │ (Instantly/ │ │
│ │ │ │ Score │ │ Smartlead) │ │
│ │ CRM │ │ Dedupe │ │ │ │
│ │ Triggers │ │ Enrich │ │ CRM Update │ │
│ │ │ │ │ │ │ │
│ │ Sequencer│ │ Branch │ │ Slack Alert │ │
│ │ Events │ │ (ATL/BTL)│ │ │ │
│ └──────────┘ └──────────┘ └──────────────┘ │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ MONITORING LAYER │ │
│ │ Bounce watch │ Health check │ Error handler │ │
│ └──────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
Step 3: Generate Per-Play Workflow Specs
For EACH active trigger play, produce an n8n workflow specification:
Workflow: Clay → Sequencer Pipeline (per trigger play)
Name: {client-slug}-{trigger-name}-pipeline
Trigger: Webhook (POST from Clay "Send to webhook" action)
Flow:
1. Webhook node
- Path: /clay/{client-slug}/{trigger-name}
- Auth: Header auth (X-Clay-Secret: {generated-secret})
- Accepts: JSON payload from Clay table
2. Validate node (Code)
- Check required fields: email, first_name, company_name
- Check email is verified (email_status = "valid")
- Check not in suppression list (query CRM or Google Sheet)
- Check ICP score meets minimum threshold: {threshold from strategy}
- On fail: route to error handler, log reason
3. Deduplicate node (Code or CRM lookup)
- Query {CRM}: does contact with this email already exist?
- If exists AND in active sequence → SKIP (log as "already in pipeline")
- If exists AND not in sequence → UPDATE contact, add to new sequence
- If new → proceed to next step
4. Route node (Switch)
- Based on signal_score from Clay:
- Hot (≥{hot_threshold}): → Slack alert + CRM priority + sequence
- Warm ({warm_threshold}-{hot_threshold-1}): → sequence + CRM
- Active ({active_threshold}-{warm_threshold-1}): → sequence only
- Based on contact_seniority from Clay:
- VP+ → ATL sequence campaign
- Manager/IC → BTL sequence campaign
5. Add to Sequencer node (HTTP Request)
- Instantly API: POST /api/v1/lead/add
OR
- Smartlead API: POST /api/v1/campaigns/{campaign_id}/leads
- Map fields: email, first_name, last_name, company, custom variables
- Custom variables from Clay: {list all personalization tokens from the workflow}
- Campaign assignment based on Route node output
6. CRM Update node (HubSpot/Salesforce/Pipedrive)
- Create or update contact
- Set properties: source={trigger-name}, signal_score, date_added
- Add to list/segment: "{Client} - {Trigger Name} - Active"
- Log enrichment data from Clay
7. Slack Notification node (conditional — Hot leads only)
- Channel: #{client-slug}-thrustlab (or client's designated channel)
- Message format:
🔥 *Hot Lead from {Trigger Name}*
*{first_name} {last_name}* — {title} at {company_name}
Signal score: {signal_score} | Seniority: {contact_seniority}
Trigger: {trigger_detail}
Added to: {sequence_name}
{CRM link}
8. Log node (Google Sheets or Airtable)
- Row: timestamp, email, company, trigger, score, sequence, status
- Purpose: audit trail independent of CRM
Step 4: Generate Monitoring Workflows
These are client-wide (not per-play):
Workflow: Bounce Monitor
Name: {client-slug}-bounce-monitor
Trigger: Schedule (every 6 hours)
Flow:
1. Schedule Trigger: 6:00, 12:00, 18:00, 00:00
2. Sequencer API call: GET bounces/unsubscribes since last check
- Instantly: GET /api/v1/campaign/{id}/analytics
- Smartlead: GET /api/v1/campaigns/{id}/statistics
3. Code node: Calculate metrics per domain
- bounce_rate = bounces / sent_today
- spam_rate = spam_complaints / sent_today
- Compare against thresholds from deliverability-config.md
4. IF node: Threshold check
- bounce_rate > {yellow_threshold}: → Warning path
- bounce_rate > {red_threshold}: → Critical path
- spam_complaints > 0: → Critical path (always)
5a. Warning path:
- Slack: ⚠️ Warning in #{client-slug}-thrustlab
- Include: domain, current rate, threshold, trend
5b. Critical path:
- Slack: 🚨 CRITICAL in #{client-slug}-thrustlab
- Sequencer API: PAUSE campaigns on affected domain
- CRM: flag affected contacts
- Include: domain, what was paused, investigation needed
6. Log: Record check timestamp, metrics, actions taken
Workflow: Daily Health Report
Name: {client-slug}-daily-health
Trigger: Schedule (weekdays 8:30 AM {client timezone})
Flow:
1. Schedule Trigger: Mon-Fri, 8:30 AM
2. Parallel fetch:
a. Sequencer stats: sent, opens, replies, bounces per campaign
b. CRM stats: new leads added, deals progressed
c. Clay stats: rows processed per table (if API available)
3. Code node: Compile daily report
- Per-play breakdown: sent, opens, replies, bounce rate
- Overall health: all-domain average metrics
- Comparison to previous day and 7-day average
- Flag anything outside normal range
4. Slack message: 📊 Daily Report in #{client-slug}-thrustlab
Format:
📊 *{Company Name} — Daily GTM Report ({date})*
*{Trigger Play 1}:*
Sent: {n} | Opens: {n}% | Replies: {n}% | Bounces: {n}%
*{Trigger Play 2}:*
Sent: {n} | Opens: {n}% | Replies: {n}% | Bounces: {n}%
*General Outbound:*
Sent: {n} | Opens: {n}% | Replies: {n}% | Bounces: {n}%
*Overall Health:* ✅ All green / ⚠️ See flags below
{Any flagged items}
Workflow: Error Handler (global)
Name: {client-slug}-error-handler
Trigger: Error Trigger (linked to ALL other workflows)
Flow:
1. Error Trigger: catches failures from any {client-slug}-* workflow
2. Code node: Parse error
- Extract: workflow name, node that failed, error message, input data
- Classify: API_ERROR | AUTH_ERROR | DATA_ERROR | RATE_LIMIT | UNKNOWN
3. Switch node: By error type
- RATE_LIMIT → queue for retry in 5 min
- AUTH_ERROR → Slack alert (credentials expired)
- DATA_ERROR → log bad record, continue
- API_ERROR → retry 3x with exponential backoff
- UNKNOWN → Slack alert for manual investigation
4. Retry mechanism (for retryable errors):
- Wait node: exponential backoff (1min → 3min → 9min)
- HTTP Request: retry the failed API call
- If 3 retries fail → dead letter log + Slack alert
5. Slack alert:
🔴 *Workflow Error — {workflow_name}*
Node: {failed_node}
Type: {error_type}
Message: {error_message}
Action: {what was done — retried/paused/logged}
6. Dead letter log (Google Sheets):
- timestamp, workflow, node, error, input_data, retry_count, resolved
Step 4b: Reply Handling Pipeline (reply-classifier integration)
Every client gets a reply handling pipeline by default. This is where inbound replies from the sequencer are classified and routed to CRM + optional notification channel.
Architecture — see shared/references/n8n-workflow-library.md Pattern D:
Sequencer Webhook (Lemlist | Smartlead | Instantly)
↓
[Normalizer Code Node] — convert platform payload to unified schema
↓
[reply-classifier skill] — called via HTTP node or inline prompt
↓
Output: {category, confidence, crm_fields, notification_text}
↓
┌─────────────────────────┬─────────────────────────┐
↓ ↓ ↓
[CRM Adapter: route] [Notification Adapter] [Master Inbox Tag]
Classification output (7 categories):
INTERESTED→ auto-create Teamleader opportunity (if auto-create enabled) OR flag for manual AE review + Slack/Teams HIGH alertNOT_NOW→ update lead status to "nurture", schedule re-touch in 30 days, MEDIUM noteOBJECTION→ route to AE for manual handling + log objection textREFERRAL→ create new contact for referee, log source, send thank-you templateOOO→ snooze sequence per parsed OOO date, no notificationUNSUBSCRIBE→ mark suppressed in CRM + client's suppression listOTHER→ log for manual review
Per-client configuration (stored in n8n credentials + client config):
{
"crm": "teamleader | hubspot | salesforce | other",
"crm_credentials": "n8n credential ID",
"notification": "slack | teams | none",
"notification_channel": "#client-replies",
"auto_create_opportunity_on_interested": false,
"ooo_snooze_days": 14
}
The reply-classifier skill is the classifier core (see /reply-classifier). This n8n-campaign-ops skill builds the pipeline + adapters around it. Keep the two concerns separate:
reply-classifier= pure classification logic (sequencer-agnostic input → categorical output)n8n-campaign-ops= orchestration + CRM/notification adapters (client-specific plumbing)
Reference workflows: Pattern D in n8n-workflow-library.md. Working examples: workflow 7b (PIA Go! Smartlead), 7c (PIA Go! Lemlist) — these should be migrated to use the new reply-classifier skill once it's built.
Step 5: Generate CRM Integration Spec
Based on the client's CRM from profile.md:
If Teamleader:
Authentication: OAuth2 — see shared/references/teamleader-guide.md for full setup
Required scopes: contacts, deals, notes, tags
Contact tags to configure (client-specific prefix required, e.g. "2 Klant" or "TL Lead"):
- Thrustlab-Source-{trigger-name} — one per active trigger play
- Thrustlab-Status-{Active|Replied|Bounced|Completed}
- Thrustlab-Seniority-{ATL|BTL}
Deal creation on INTERESTED replies:
- Auto-create: only if auto_create_opportunity_on_interested = true
- Default stage: "Qualified — auto-created by Thrustlab" (manual AE review required before advancing)
- Link to contact + add reply text as note
If HubSpot:
Authentication: OAuth2 (n8n handles refresh)
Required scopes: contacts, companies, deals, lists
Contact properties to create (custom):
- thrustlab_source (single-line text) — trigger play that generated the lead
- thrustlab_signal_score (number) — composite score from Clay
- thrustlab_seniority (dropdown) — ATL/BTL classification
- thrustlab_sequence_status (dropdown) — Active/Replied/Bounced/Completed
- thrustlab_first_touch_date (date) — when first added to sequence
- thrustlab_trigger_detail (multi-line text) — the specific trigger event
Lists to create:
- {Company Name} — All Thrustlab Leads
- {Company Name} — Hot Leads (signal_score ≥ {hot_threshold})
- {Company Name} — Replied (for nurture)
- {Company Name} — Bounced (suppression)
- Per trigger play: {Company Name} — {Trigger Name} Active
Workflows to configure in HubSpot:
- When thrustlab_sequence_status = "Replied" → notify assigned owner
- When deal created from Thrustlab lead → update thrustlab_sequence_status
If Salesforce:
Authentication: OAuth2 (Connected App)
Required: API access enabled on user profile
Custom fields on Lead/Contact:
- Thrustlab_Source__c (picklist)
- Thrustlab_Signal_Score__c (number)
- Thrustlab_Seniority__c (picklist: ATL, BTL)
- Thrustlab_Sequence_Status__c (picklist)
- Thrustlab_First_Touch__c (date)
- Thrustlab_Trigger_Detail__c (long text)
Campaign structure:
- Parent: {Company Name} — Thrustlab GTM
- Children: one per trigger play + general outbound
If no CRM:
- Recommend HubSpot Free as minimum (contacts, lists, basic pipeline)
- Alternative: Google Sheets as lightweight CRM (with n8n keeping it in sync)
- Flag this as a gap in Slack: "⚠️ No CRM configured — using Sheets as fallback"
Step 6: Generate n8n Setup Instructions
Client-specific setup steps:
n8n Instance:
- Recommended: n8n Cloud Pro ($50/mo — 10,000 executions, covers most clients)
- If client has DevOps: self-hosted Docker on DigitalOcean/Hetzner ($20-55/mo)
- Sizing: estimate executions = (daily lead volume × workflows per lead × 30 days) + monitoring runs
Credentials to configure in n8n:
- Clay webhook secrets (one per trigger play)
- Sequencer API key ({Instantly/Smartlead})
- CRM OAuth2 ({HubSpot/Salesforce})
- Slack Bot Token (for #{client-slug}-thrustlab channel)
- Google Sheets API (for logging/dead letter)
Webhook URLs to configure in Clay: For each active trigger play, set the Clay table's "Send to webhook" action to:
{n8n-instance-url}/webhook/clay/{client-slug}/{trigger-name}
Header: X-Clay-Secret: {generated-secret}
Step 7: Produce Output File
Save to Prospects/{client-slug}/n8n-config.md:
# {Company Name} — n8n Campaign Operations
**Prepared by:** Thrustlab
**Date:** {date}
**Active plays:** {list of active trigger plays}
**n8n instance:** {cloud/self-hosted} — {URL if known}
## Architecture Overview
{Diagram from Step 2, customized to client's stack}
## Per-Play Pipeline Workflows
{One section per active trigger play from Step 3}
### {Trigger Play 1}: {Name}
- Webhook path: /clay/{slug}/{trigger-name}
- Routing: Hot → Slack + CRM + {ATL/BTL sequence} | Warm → CRM + sequence | Active → sequence
- Sequencer campaigns: {campaign names}
- CRM mapping: {field mappings}
### {Trigger Play 2}: {Name}
{Same structure}
### General Outbound
{Same structure}
## Monitoring Workflows
### Bounce Monitor
{Spec from Step 4}
### Daily Health Report
{Spec from Step 4}
### Error Handler
{Spec from Step 4}
## CRM Integration
{Spec from Step 5}
## Setup Checklist
- [ ] n8n instance provisioned ({cloud/self-hosted})
- [ ] All credentials configured (Clay, Sequencer, CRM, Slack, Sheets)
- [ ] Per-play webhook URLs configured in Clay tables
- [ ] Test: send 1 test record through each pipeline
- [ ] Verify: record appears in sequencer, CRM, and Slack
- [ ] Bounce monitor active and tested
- [ ] Daily report configured and first report received
- [ ] Error handler linked to all workflows
- [ ] Dead letter sheet created and accessible
## Maintenance
- When adding a new trigger play: duplicate an existing pipeline workflow, update webhook path and campaign mapping
- When client changes CRM fields: update CRM Update node in all pipelines
- Monthly: review error logs, clean dead letter queue, verify all credentials still valid
Step 8: Share & Next Steps
After saving:
- Share in client Slack channel
- If client doesn't have n8n yet: include setup recommendation with cost estimate
- Coordinate with client's ops person (or Thrustlab if managing) for implementation
- Test each pipeline with a single Clay record before going live
- Cross-reference with
/deliverability-setupconfig to ensure sending thresholds are aligned
Known Issues / Edge Cases
- Always use
specifyBody: "json"in HTTP Request nodes. Using"string"sends form-encoded data even when the Content-Type header is set to JSON. This causes silent failures where the API receives garbled data. - Google Sheets API via direct HTTP is more reliable than n8n's native Google Sheets node for batch operations. The native node has intermittent issues with large writes and token refresh. Use HTTP Request nodes with OAuth2 credentials for production workflows.
Notes
- This skill is ADDITIVE — run it again when activating a new trigger play. New plays get new pipeline workflows; existing ones stay unchanged.
- The n8n workflows in this spec are architectural blueprints, not importable JSON. The person implementing (Thrustlab or client) builds them in n8n using these specs.
- For actual n8n implementation details (node configuration, expressions, error patterns), reference the ColdIQ n8n master-skill and its 6 sub-skills.
- Signal stacking integration: if the client has the Signal Aggregation Table active, the routing in Step 3 uses composite scores from that table rather than per-play scores.
- If the client is on Zapier/Make instead of n8n, the architectural patterns are the same but node names and webhook formats differ. Adapt accordingly, but recommend migration to n8n for cost efficiency on complex workflows.
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/thrustlab-io/thrustlab-skills-library/n8n-campaign-ops">View n8n-campaign-ops on skillZs</a>