Semarize

Automation

Automate Call Analysis with n8n

A practical guide to building automated transcript analysis workflows in n8n. Connect your call recording platform to the Semarize API using n8n's native polling loops, extract structured scores and signals from every conversation, and route results to your database, Slack, or CRM — self-hosted and fully under your control.

What you'll learn

  • How the Webhook → HTTP Request → Poll Loop → Transform → Route pattern works in n8n
  • Two architecture options: sync mode (simple) and async mode with native polling loops (n8n’s strength)
  • Why n8n is ideal for async polling and when sync mode is the better choice
  • Five ready-to-use workflow templates — Postgres scoring, batch processing, Slack alerts, multi-source aggregation, and compliance pipelines
  • Common gotchas: self-hosting, webhook URLs, expression syntax, memory limits, and credential management

Context

Why n8n for Automated Call Analysis

n8n gives you the full power of a workflow automation platform with the freedom to self-host. Data never leaves your infrastructure, loops are native, and there are no per-task costs. But it requires more setup than cloud-only alternatives.

n8n strengths

Self-hosted — full data sovereignty, transcripts never leave your network
Native loop support — Wait + IF nodes for async polling patterns
Free for self-hosted deployments, no per-task pricing
Developer-friendly — Code node for JavaScript/Python transformations
Built-in error handling with retry logic per node
Docker / Kubernetes deployment — fits any infrastructure

Consider alternatives when

You need zero-code setup — n8n has a learning curve Zapier
You need 7,000+ native integrations out of the box Zapier
You want visual branching with built-in Router modules Make
You need row-based data enrichment at scale Clay
Enterprise governance and SOC 2 compliance are required Workato

For teams that value data control, cost efficiency, and developer flexibility, n8n is the strongest automation option for Semarize. Its native loop support makes it the only platform where async mode with polling works cleanly out of the box — no workarounds, no premium add-ons, no per-execution costs.

Architecture

How n8n + Semarize Works

n8n supports two architecture patterns with Semarize. The sync pattern is simpler and works like other platforms. The async pattern with polling is n8n's unique strength — handling long-running evaluations gracefully with native loop nodes.

Pattern A — Sync mode (simple)
Webhook
Receive transcript payload
HTTP Method: POST
Path: /semarize-eval
HTTP Request
POST /v1/runs (sync)
URL: https://api.semarize.com/v1/runs
Body: { kit_code, mode: "sync", input: { transcript } }
Response returned inline
Code — Transform
Extract brick values with JavaScript
Postgres / Slack / HTTP
Route results to destination
Best for: short transcripts (<60 min), simple Kits, quick setup.
Pattern B — Async + polling loopRecommended
Webhook
Receive transcript payload
HTTP Method: POST
Path: /semarize-eval
HTTP Request — Create Run
POST /v1/runs (async, default)
URL: https://api.semarize.com/v1/runs
Body: { kit_code, input: { transcript } }
Returns: { run_id, status: "processing" }
Loop until complete
Wait
Pause 2 seconds
Resume: After Time Interval
Interval: 2s
HTTP Request — Poll
GET /v1/runs/:runId
IF — Check Status
status !== 'succeeded' ? loop : continue
Run complete
Code — Transform
Extract and reshape brick values
Postgres / Slack / HTTP
Route results to destination
Best for: long transcripts, complex Kits, guaranteed completion handling.

Why async mode shines in n8n

Unlike Zapier or Clay, n8n has native loop support. The Wait + IF node combination creates a clean polling loop that retries until the run completes. No premium add-ons, no workarounds. If a sync run would take longer than ~30 seconds (rare for standard transcripts), async mode handles it gracefully instead of returning a sync_fallback: true response.

Setup Guide

Build Your First Workflow: Step-by-Step

This walkthrough covers the recommended async polling pattern — n8n's native strength. A sync-mode alternative is noted where applicable.

1

Add a Webhook node as the workflow trigger

Create a new workflow. Add a Webhook node. Set HTTP Method to POST and define a path (e.g., /semarize-eval). Your external system will POST transcripts to this URL.

Your backendPOST to n8n webhook URLMost flexible
Gong webhookPOST on call completeDirect integration
Cron nodeScheduled triggerFor batch processing
Semarize webhookTrigger on run.completedReverse pattern
For self-hosted n8n, your webhook URL will be something like https://n8n.yourcompany.com/webhook/semarize-eval. Make sure this URL is reachable from wherever you're sending transcripts.
2

Create an HTTP Header Auth credential for Semarize

Before configuring the API call, set up the credential. Go to Credentials → New → Header Auth. Set the header name to Authorization and value to Bearer smz_live_your_key.

Where to find your credentials: Generate an API key at Settings → API Keys in the Semarize app. Copy the Kit code from your Kit's settings page.
3

Add an HTTP Request node to create the run

Add an HTTP Request node. Set method to POST, URL to https://api.semarize.com/v1/runs. Select your Header Auth credential. Set Body Content Type to JSON.

Configuration

MethodPOST
URLhttps://api.semarize.com/v1/runs
AuthenticationHeader Auth (Semarize)
Body TypeJSON
Send BodyYes

Request body (async)

HTTP Request node body
{
"kit_code": "YOUR_KIT_CODE",
"input": {
"transcript": {{ $json.transcript }}
}
}

For sync mode, add "mode": "sync" to the body and skip steps 4-6.

4

Add a Wait node for the polling interval

Add a Wait node. Set Resume to "After Time Interval" and the interval to 2 seconds. This creates a pause between each poll so you don't hammer the API.

5

Add an HTTP Request node to poll the run status

Add another HTTP Request node. Set method to GET. Use an expression for the URL:

https://api.semarize.com/v1/runs/{{ $('HTTP Request').item.json.run_id }}

Use the same Header Auth credential. This node fetches the current status of the run.

6

Add an IF node to check completion and create the loop

Add an IF node. Set the condition: {{ $json.status }} is not equal to "succeeded".

True output (still processing): Connect back to the Wait node. This creates the loop.
False output (succeeded): Connect forward to the Code/Transform node.
7

Add a Code node to transform the output

Add a Code node. Set the language to JavaScript. Extract and reshape the brick values from the completed run.

n8n Code node - JavaScript
// Code Node - Transform Semarize output
const bricks = items[0].json.output.bricks;
return [{
json: {
call_id: items[0].json.run_id,
score: bricks.overall_score.value,
risk: bricks.risk_flag.value,
pain_point: bricks.pain_point.value,
confidence: bricks.overall_score.confidence,
evidence: bricks.pain_point.evidence,
}
}];
8

Add the destination node and activate the workflow

Add your final node — Postgres, Slack, HTTP Request to your CRM, or any other n8n integration. Map the transformed fields from the Code node. Test each node, then activate the workflow.

The Webhook node shows a test URL and a production URL — use the production URL when activating
The polling loop creates a visual backward connection in the editor — this is expected
Test with a short transcript first to verify the full pipeline
Check the execution log for each node's input/output to debug issues

API Reference

API Request & Response Details

What the HTTP Request nodes send and receive. Both sync and async patterns use the same POST /v1/runs endpoint.

Async request (default)

POST /v1/runs
// POST https://api.semarize.com/v1/runs
// Authorization: Bearer smz_live_...
// Content-Type: application/json
{
"kit_code": "discovery_quality_v2",
"input": {
"transcript": "Rep: Hi Sarah, thanks for..."
}
}

Returns 202 immediately with run_id. Poll GET /v1/runs/:runId for results.

Sync request (alternative)

POST /v1/runs (sync)
// Same endpoint, add mode: "sync"
{
"kit_code": "discovery_quality_v2",
"mode": "sync",
"input": {
"transcript": "Rep: Hi Sarah, thanks for..."
}
}

Returns 200 with full results inline. No polling needed.

Completed run response (200)

GET /v1/runs/:runId - or sync 200
{
"run_id": "run_8f3a...",
"status": "succeeded",
"duration_ms": 1200,
"output": {
"bricks": {
"overall_score": { "value": 72, "confidence": 0.94 },
"risk_flag": { "value": false, "confidence": 0.91 },
"pain_point": { "value": "Losing 3 hrs/week...", ... }
}
}
}

Brick value types

TypeExample brickExample valuen8n expression
Numeric (score)overall_score72{{ $json.output.bricks.overall_score.value }}
Boolean (flag)risk_flagfalse{{ $json.output.bricks.risk_flag.value }}
Text (extraction)pain_point"Losing 3 hrs/week..."{{ $json.output.bricks.pain_point.value }}
Categoricalcall_stage"discovery"{{ $json.output.bricks.call_stage.value }}
Sync fallback: If a sync-mode run exceeds ~30 seconds, Semarize returns 202 with sync_fallback: true and a run_id. With n8n, you can handle this gracefully: add an IF node after the sync request that checks for a 202 status code, and if true, switches to the polling loop pattern for that specific run.

Templates

Workflow Templates for Common Use Cases

Five ready-to-use workflow patterns for common call analysis scenarios. Each template shows the complete node chain with the specific configuration and destination.

Webhook-Triggered Scoring to Postgres

Async with polling loop — the full n8n-native pattern

Async + Loop

Bricks used

overall_score = 72risk_flag = falsepain_point = "..."confidence = 0.94

Every call is scored asynchronously. The polling loop waits until the run completes, then the Code node transforms the output and inserts a row into your Postgres call_evaluations table.

Webhook → POST /v1/runs → Poll Loop → Code → Postgres
call_evaluations - Postgres
call_iddatescoreriskpain_pointstatus
call_8f3aJan 2872NoManual data entrysucceeded
call_92b1Jan 2838YesBudget concernssucceeded
call_a4e7Jan 2785NoScaling bottlenecksucceeded

Auto-inserted by n8n workflow · 142 rows

Scheduled Batch Processing to Database

Cron trigger + SplitInBatches for daily call analysis

Batch

Workflow pattern

A Cron node triggers the workflow every morning at 6 AM. An HTTP Request fetches yesterday's calls from your recording platform. SplitInBatches iterates through each call, sends it to Semarize, waits for results, and inserts each row into the database.

Cron 06:00 → Fetch Calls → SplitInBatches → Semarize → DB Insert
Batch Processing — Cron @ 06:00 UTC
call_001Sarah K.succeeded72
call_002James T.succeeded85
call_003Maria L.processing
call_004David R.queued

4 calls queued · 2 completed · 1 processing · 1 waiting

Real-time Deal Alerts to Slack

Sync mode for instant alerts — simpler flow, no polling

Uses IF Filter

Bricks used

risk_flag = truerisk_reason = "budget not confirmed"overall_score = 38

Uses sync mode for instant results. An IF node checks if risk_flag is true — only flagged calls trigger a Slack message. Clean signal, no noise. No polling loop needed since sync returns results inline.

Webhook → POST /v1/runs (sync) → IF risk → Slack
#deal-alerts
n8n Workflow2:34 PM

Deal Risk Detected

Deal: Acme Corp — Enterprise

Score: 38 / 100

Risk: Budget not confirmed, decision maker absent

Rep: Sarah K.

Multi-Source Aggregation Pipeline

Process calls from Gong, Fireflies, and Zoom in one workflow

Advanced

Multiple webhook endpoints

Create separate Webhook nodes for each source platform (‘/gong-eval’, ‘/fireflies-eval’, ‘/zoom-eval’). A Merge node normalizes the transcript format. Then a single Semarize API call + Code transform pipeline processes every call identically, regardless of source.

3 Webhooks → Merge → Semarize → Unified DB
Multi-Source Pipeline
Gong/gong-eval
transcript: mappedsource: gong

→ Merge → Semarize → call_evaluations

Fireflies/fireflies-eval
transcript: mappedsource: fireflies

→ Merge → Semarize → call_evaluations

Zoom/zoom-eval
transcript: mappedsource: zoom

→ Merge → Semarize → call_evaluations

Compliance Pipeline to Database + Email

Error handling + retry logic + compliance alerting

Bricks used

disclosure_given = trueconsent_obtained = trueprohibited_language = true

For regulated industries. Every call is checked against a compliance Kit. Results are inserted into a compliance database. If any check fails, an IF node routes to an email alert for the compliance team. n8n's per-node retry ensures transient failures don't drop calls.

Webhook → Semarize → IF failed checks → DB + Email
Compliance Pipeline — Call #4819
Disclosure given
Consent obtained
Prohibited languageDetected: guaranteed returns
Required disclaimers
Identity verification

4 of 5 checks passed · Flagged for review

Email sent to compliance@

Advanced

Advanced n8n Patterns

Beyond the basic workflow — patterns for production-grade automation, scaling, error resilience, and deployment.

Async vs sync trade-offs

Async + polling (recommended)

  • Handles any transcript length
  • Guaranteed completion detection
  • Native to n8n's loop model
  • Slightly more nodes to configure

Sync mode

  • Fewer nodes, simpler flow
  • May hit 30s sync fallback on long transcripts
  • Good for quick prototyping
  • Need fallback handling for 202 responses

Error workflow for failure handling

Create a separate "Error Handler" workflow with an Error Trigger node. In your main workflow settings, set this as the error workflow. When any node fails, the error workflow receives the execution details and can:

Send a Slack message to #ops-alerts with the failed node name, error message, and execution ID
Log the failure to a Postgres errors table for tracking and SLA reporting
Retry the failed execution using n8n's API (POST /executions/:id/retry)
Escalate via email if the same workflow fails 3+ times in an hour

Expressions and data mapping

n8n expressions let you reference data from any previous node. Key patterns for Semarize workflows:

{{ $json.output.bricks.overall_score.value }}

Direct brick value access from current node input

{{ $('HTTP Request').item.json.run_id }}

Reference a specific node by name

{{ $json.status === 'succeeded' }}

Boolean expression for IF node conditions

{{ $json.output.bricks.pain_point.evidence?.join(', ') }}

Join evidence array into a string

Credential management

n8n encrypts all credentials at rest using the N8N_ENCRYPTION_KEY environment variable. Create a single HTTP Header Auth credential for Semarize and reuse it across all workflows. For team environments, share the credential explicitly with other users. Never hardcode the API key in Code nodes or expression fields.

Docker deployment tips

For production self-hosted deployments:

Use docker-compose with a Postgres database (not SQLite) for reliability: DB_TYPE=postgresdb
Set N8N_ENCRYPTION_KEY to a strong random string and persist it - losing this key means losing all encrypted credentials
Put n8n behind a reverse proxy (nginx, Caddy, Traefik) for SSL termination and stable webhook URLs
Set EXECUTIONS_DATA_PRUNE=true and EXECUTIONS_DATA_MAX_AGE=168 to auto-clean old execution logs
For high-throughput, enable queue mode: EXECUTIONS_MODE=queue with a Redis instance for distributing work across multiple n8n workers

Scaling with queue mode

When processing hundreds of calls per day, a single n8n instance may bottleneck. Enable queue mode (EXECUTIONS_MODE=queue) to separate the main process from worker processes. The main instance handles the UI and webhook triggers, while worker instances pick up executions from a Redis queue. Scale workers horizontally with Kubernetes replicas or Docker Swarm services.

Watch out for

Common Challenges & Gotchas

These are the issues that come up most often when teams build call analysis workflows in n8n.

Self-hosting complexity

Running n8n on your own infrastructure means you manage uptime, backups, SSL certificates, and updates. For teams without DevOps capacity, n8n Cloud eliminates this overhead while keeping the same workflow engine.

Webhook URL management

Self-hosted n8n webhook URLs include your server's hostname. If your IP changes or you move servers, all external systems posting to your webhooks break. Use a stable domain with a reverse proxy (nginx, Caddy) or n8n Cloud.

Expression syntax learning curve

n8n uses its own expression syntax ({{ $json.field }}, {{ $node['Name'].json }}) which differs from JavaScript. Common mistake: forgetting that expressions are evaluated in a sandbox and standard Node.js APIs are not available in expression fields.

Memory limits with large transcripts

n8n stores all node output in memory during workflow execution. A 90-minute transcript can be 50-100KB of text. Processing many calls in a batch loop can exhaust memory on smaller instances. Set N8N_DEFAULT_BINARY_DATA_MODE=filesystem for large payloads.

Retry configuration per node

Unlike platform-wide retry policies, n8n configures retries per node. If you forget to enable retries on the HTTP Request node calling Semarize, a transient 503 will fail the entire workflow. Set retry on error with a 2-second wait and 3 max attempts.

Loop connection can be confusing

Creating the polling loop requires connecting the IF node's true output back to the Wait node. In the visual editor this creates a backward connection that can look messy. Label your nodes clearly and use the sticky note feature to document the loop logic.

Credential sharing across workflows

n8n credentials are scoped to the user who created them. In team environments, other users cannot access your stored Semarize API key unless you explicitly share the credential. Plan credential management early.

Timezone and Cron gotchas

The Cron node uses the server's timezone by default. If your n8n instance runs in UTC but your team operates in EST, scheduled batch jobs may fire at unexpected times. Set the GENERIC_TIMEZONE environment variable or configure it per Cron node.

FAQ

Frequently Asked Questions

Explore

Explore Semarize