Customer complaint analysis to process improvement action plan
- Published
Customer complaints are goldmines of insight, yet most organisations treat them like rubbish to be sorted through quickly. Every complaint contains signals about broken processes, training gaps, product defects, or service failures. The problem is that complaints arrive in different channels (email, chat, forms, support tickets) and extracting actionable intelligence from them requires reading, categorising, pattern-matching, and writing proper recommendations. That takes time, and time is money.
Most teams do this manually: someone reads complaints, tags them, maybe puts them in a spreadsheet, and then someone else writes improvement suggestions. Weeks can pass before anything actionable reaches the people who need to fix it. By then, more customers have had the same bad experience.
This workflow automates the entire journey from raw complaint to structured improvement plan. You'll feed incoming complaints into Accio AI for initial classification, let Cogram process and organise the structured data, then use Terrakotta AI to generate specific, actionable recommendations. An orchestration layer ties it all together so nothing requires human intervention between receipt and delivery of the improvement plan.
The Automated Workflow
Why n8n for this workflow
We'll use n8n as the orchestration engine here. Zapier and Make are valid alternatives, but n8n gives you better control over data transformation between steps and costs less at higher volumes. Since complaint workflows can generate dozens of items daily, n8n's per-execution pricing makes more sense than Zapier's per-task model.
The workflow architecture
The workflow follows this sequence:
- Complaint input trigger (webhook or polling from email/ticketing system)
- Accio AI classifies and extracts complaint metadata
- Cogram structures and deduplicates similar complaints
- Terrakotta AI generates improvement actions
- Output to Google Sheets, Slack, or your internal system
Here's how it connects:
[Incoming Complaint]
↓
[Accio AI Classification]
↓
[Cogram Structure & Group]
↓
[Terrakotta AI Action Plan]
↓
[Send to Sheets/Slack/Database]
Step 1: Capturing complaints
Set up n8n to listen for incoming complaints via webhook. Most support systems (Zendesk, Intercom, Help Scout) can post to a webhook when new tickets arrive. If you use email, set up a forwarding rule to a webhook service first.
In n8n, create a Webhook trigger node and configure it to accept POST requests:
{
"complaint_id": "12345",
"customer_name": "Sarah Mitchell",
"channel": "email",
"complaint_text": "Your delivery driver left my package in the rain. It arrived soaked and the contents were ruined.",
"received_at": "2024-01-15T09:30:00Z",
"priority": "high"
}
This becomes your base payload that flows through the entire workflow.
Step 2: Accio AI classification
Accio AI specialises in extracting structured data from unstructured text. You'll use it to identify complaint categories, severity, root cause indicators, and affected departments.
Add an HTTP request node in n8n pointing to Accio's API endpoint:
POST https://api.accio-ai.com/v1/classify
{
"api_key": "YOUR_ACCIO_API_KEY",
"text": "{{ $node['Webhook'].json.complaint_text }}",
"labels": [
"product_defect",
"delivery_issue",
"customer_service",
"billing",
"quality",
"packaging",
"communication"
],
"extract_entities": true,
"confidence_threshold": 0.7
}
Accio returns structured JSON:
{
"primary_category": "delivery_issue",
"secondary_categories": ["packaging", "quality"],
"severity": "high",
"entities": {
"issue_type": "water_damage",
"affected_product": "electronics",
"responsibility": "logistics_partner"
},
"confidence_scores": {
"primary_category": 0.94,
"severity": 0.87
}
}
In your n8n node, set up the response mapping to extract these fields into your workflow variables.
Step 3: Cogram grouping and structuring
Cogram processes information and identifies patterns. You'll use it to deduplicate complaints (is this the same issue we've seen before?), group related complaints, and build context around each issue.
Create another HTTP request node:
POST https://api.cogram.com/v1/process
{
"api_key": "YOUR_COGRAM_API_KEY",
"input_data": {
"complaint_id": "{{ $node['Webhook'].json.complaint_id }}",
"text": "{{ $node['Webhook'].json.complaint_text }}",
"category": "{{ $node['Accio Classification'].json.primary_category }}",
"severity": "{{ $node['Accio Classification'].json.severity }}"
},
"operation": "cluster_and_summarise",
"historical_context": true,
"output_format": "structured"
}
Cogram will return:
{
"cluster_id": "delivery_issue_001",
"cluster_size": 7,
"is_new_issue": false,
"summary": "Package damaged in transit due to inadequate packaging for weather exposure",
"affected_customers": 7,
"date_range": "2024-01-10 to 2024-01-15",
"root_cause_hypothesis": "insufficient_waterproofing",
"similar_complaints": [
"complaint_id_11982",
"complaint_id_12004"
]
}
This tells you immediately if this is an isolated complaint or a recurring problem affecting multiple customers. That context is crucial for prioritisation.
Step 4: Terrakotta AI generates improvement actions
Terrakotta AI specialises in generating specific, implementable recommendations. Feed it the classified complaint, the clustering information, and let it produce actionable improvement steps.
Add a third HTTP request node:
POST https://api.terrakotta-ai.com/v1/generate-actions
{
"api_key": "YOUR_TERRAKOTTA_API_KEY",
"complaint_data": {
"text": "{{ $node['Webhook'].json.complaint_text }}",
"category": "{{ $node['Accio Classification'].json.primary_category }}",
"severity": "{{ $node['Accio Classification'].json.severity }}",
"entity_responsibility": "{{ $node['Accio Classification'].json.entities.responsibility }}"
},
"clustering_context": {
"cluster_id": "{{ $node['Cogram'].json.cluster_id }}",
"cluster_size": "{{ $node['Cogram'].json.cluster_size }}",
"root_cause": "{{ $node['Cogram'].json.root_cause_hypothesis }}"
},
"action_type": "process_improvement",
"include_metrics": true,
"include_timeline": true
}
Terrakotta returns actionable recommendations:
{
"actions": [
{
"action_id": "action_001",
"title": "Upgrade packaging materials for weather protection",
"description": "Introduce waterproof outer layer and desiccant packs for all electronics shipments",
"owner_department": "logistics",
"priority": "high",
"estimated_cost": "£2,400",
"implementation_timeline": "2 weeks",
"expected_impact": "85% reduction in water damage complaints",
"success_metrics": ["reduction_in_complaints", "customer_satisfaction_nps"]
},
{
"action_id": "action_002",
"title": "Brief delivery partners on weather handling",
"description": "Create short training for all logistics partners on protecting packages from weather during last-mile delivery",
"owner_department": "logistics_operations",
"priority": "medium",
"estimated_cost": "£600",
"implementation_timeline": "1 week",
"expected_impact": "20% additional reduction in water damage"
},
{
"action_id": "action_003",
"title": "Add insurance option for high-value items",
"description": "Offer customers optional weather damage insurance at checkout for electronics",
"owner_department": "product",
"priority": "low",
"estimated_cost": "£1,200",
"implementation_timeline": "3 weeks"
}
],
"overall_recommendation": "Focus on actions 001 and 002 in parallel; these target root cause and have highest ROI"
}
Notice how Terrakotta doesn't just say "fix the problem," it gives owners, costs, timelines, and success metrics. That's what makes it actionable.
Step 5: Output to your system
The final node sends the improvement plan somewhere your team actually sees it. Options:
Option A: Google Sheets for tracking and accountability.
POST https://sheets.googleapis.com/v4/spreadsheets/{{ SPREADSHEET_ID }}/values/Improvements!A1:append
{
"values": [
[
"{{ $node['Webhook'].json.complaint_id }}",
"{{ $node['Accio Classification'].json.primary_category }}",
"{{ $node['Cogram'].json.cluster_id }}",
"{{ $node['Cogram'].json.cluster_size }}",
"{{ $node['Terrakotta AI'].json.actions[0].title }}",
"{{ $node['Terrakotta AI'].json.actions[0].owner_department }}",
"{{ $node['Terrakotta AI'].json.actions[0].priority }}",
"{{ $node['Terrakotta AI'].json.actions[0].implementation_timeline }}"
]
]
}
Option B: Slack notification for immediate visibility.
POST https://hooks.slack.com/services/YOUR/WEBHOOK/URL
{
"text": "New customer complaint requiring action",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*{{ $node['Accio Classification'].json.primary_category }}* ({{ $node['Accio Classification'].json.severity }})\n{{ $node['Cogram'].json.summary }}\n*Affects:* {{ $node['Cogram'].json.affected_customers }} customers"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Top Action:* {{ $node['Terrakotta AI'].json.actions[0].title }}\n*Owner:* {{ $node['Terrakotta AI'].json.actions[0].owner_department }}\n*Timeline:* {{ $node['Terrakotta AI'].json.actions[0].implementation_timeline }}"
}
}
]
}
Option C: Direct database insert to your internal system via SQL or API.
The key is that once triggered, the workflow runs to completion without anyone touching it. The improvement plan lands in the right place, ready for the relevant department to action.
The Manual Alternative
If you want more control or need custom logic at any step, you can insert approval nodes or manual review gates.
Add a Wait for Webhook node after Terrakotta AI where a team lead reviews the recommended actions before they're published. They can accept, reject, or request modifications via a webhook callback. This is useful if you want an expert checking recommendations before they hit the improvement backlog.
You could also use Claude Code (available in some n8n nodes) to write custom logic that doesn't quite fit the standard tool APIs. For instance, if your complaint text includes customer sentiment language that needs special handling, you can insert a Claude Code node:
const complaint = $node['Webhook'].json.complaint_text;
const classification = $node['Accio Classification'].json;
// Custom logic: if complaint mentions "never again" language, escalate priority
if (complaint.toLowerCase().includes('never again') ||
complaint.toLowerCase().includes('will not') ||
complaint.toLowerCase().includes('unacceptable')) {
classification.priority = 'critical';
}
return classification;
This hybrid approach (mostly automated, manual gates where needed) gives you safety rails without losing the speed benefit.
Pro Tips
1. Error handling for API failures
Accio, Cogram, and Terrakotta all have rate limits and occasional downtime. Wrap each API call in n8n's Error Trigger node:
On error, wait 60 seconds, then retry up to 3 times before sending an alert to Slack.
This prevents single API hiccups from breaking your workflow. Set retry strategy to exponential backoff (5 seconds, then 15 seconds, then 45 seconds) so you don't hammer the API.
2. Batch processing for cost efficiency
Rather than processing each complaint individually, batch them every 2 hours. Send 20 complaints to Accio in one request instead of 20 separate requests. Most APIs discount or allow batch endpoints that process multiple items cheaper than single calls.
In n8n, use a Schedule trigger set to "every 2 hours" and a Database query node to fetch all complaints since the last batch run.
3. Deduplication to avoid duplicate actions
Before sending improvement actions to your output, check if an action with the same title and owner already exists in your Sheets or database for the same cluster. Cogram helps here, but a quick lookup prevents your improvement backlog filling with duplicates.
4. Track action completion metrics
Create a second n8n workflow triggered weekly that checks which recommended actions were actually completed, and by whom. Link back to the original complaint to measure whether your improvements actually reduced similar complaints. This closes the feedback loop.
5. Cost monitoring
Accio and Terrakotta charge per API call. If your complaint volume spikes (say, after a product recall or service outage), you could hit unexpected costs. Set up a monthly cost forecast in n8n that counts expected API calls and alerts you if costs exceed budget.
Cost Breakdown
| Tool | Plan Needed | Monthly Cost | Notes |
|---|---|---|---|
| n8n Cloud | Team or Enterprise | £50–200 | Based on workflow executions. 10,000 executions/month fits Team plan; higher volume needs Enterprise. Self-hosted n8n is free but requires infrastructure. |
| Accio AI | Pay-as-you-go | £100–300 | £0.03 per classification call. Assumes 5,000 complaints/month. Batch processing reduces this by ~40%. |
| Cogram | Pro | £80 | Fixed monthly. Includes 100,000 operations/month, well above typical complaint volume. |
| Terrakotta AI | Growth | £150–250 | £0.02 per action generation. Assumes 8,000 action generations/month (clusters often generate 1–2 recommendations per cluster). Volume discounts available. |
| Google Sheets API | Free tier | £0 | Free for up to 1,000,000 cells written/month. Complains rarely exceed this. |
| Slack API | Free tier | £0 | Free for unlimited notifications. Upgrade only if you need advanced workflows. |
| Total | £380–830 | Includes typical complaint volumes of 5,000–10,000 monthly. Self-hosted n8n reduces cost to £280–730. |
The cost is justified when you consider the time savings: manually reviewing and writing improvement plans for 5,000 complaints monthly would require at least one full-time person at £35,000+ annually. This workflow does it for less than the cost of one month of that person's salary, every month.
More Recipes
Automated Podcast Production Workflow
Automated Podcast Production Workflow: From Raw Audio to Published Episode
Build an Automated YouTube Channel with AI
Build an Automated YouTube Channel with AI
Medical device regulatory documentation from technical specifications
Medtech companies spend significant resources translating technical specs into regulatory-compliant documentation.