This workflow corresponds to n8n.io template #17054 — we link there as the canonical source.
This workflow follows the Agent → Error Trigger recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "FpauF9jfmoRaFe8q",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "AI Review & Reputation Manager",
"tags": [],
"nodes": [
{
"id": "cbfbcc8a-5690-46ac-9c91-a681f199018f",
"name": "Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
368,
672
],
"parameters": {
"color": 7,
"width": 544,
"height": 1488,
"content": "## \u2b50 AI Review & Reputation Manager\n\nPolls Google Business and Trustpilot hourly, deduplicates new reviews, drafts LLM-powered replies on-brand, and routes positive reviews for one-tap approval while escalating negative reviews to the owner with suggested resolutions.\n\n**Perfect for:** local businesses, service providers, and ecommerce companies managing online reputation at scale.\n\n---\n\n## How it works\n\n1. **Every Hour** \u2014 Schedule trigger runs hourly.\n2. **Fetch Google Reviews** \u2014 HTTP request retrieves reviews from Google Business Profile API.\n3. **Fetch Trustpilot Reviews** \u2014 HTTP request retrieves reviews from Trustpilot API.\n4. **Combine Sources** \u2014 Merge node combines Google and Trustpilot results.\n5. **Dedupe New Reviews** \u2014 Code node filters out previously seen reviews using workflow static data.\n6. **Any New Reviews?** \u2014 If condition: exits if no fresh reviews, otherwise continues.\n7. **No New Reviews** \u2014 No-op endpoint when no new reviews exist.\n8. **Process Each Review** \u2014 SplitInBatches loops through each fresh review one at a time.\n9. **Draft Reply (AI Agent)** \u2014 LangChain agent with OpenAI LLM drafts sentiment-aware reply.\n10. **OpenAI Chat Model** \u2014 Language model node (gpt-5-mini) powers the AI agent.\n11. **Structured Output Parser** \u2014 Validates LLM output as JSON (sentiment, draftReply, suggestedResolution).\n12. **Negative Review?** \u2014 If condition: branches on sentiment.\n13. **Escalate to Owner** \u2014 Slack node alerts owner for negative reviews with suggested resolution.\n14. **Request Approval** \u2014 Slack node sends positive review drafts for human approval, waits 24 hours max.\n15. **Approved?** \u2014 If condition: publishes only if approved.\n16. **Publish Reply** \u2014 HTTP request submits approved reply to Trustpilot API.\n17. **Error Trigger** \u2014 Error handler catches workflow failures.\n18. **Notify Ops** \u2014 Slack node alerts ops team of errors.\n\n---\n\n## Setup (about 20 minutes)\n\n1. **Google Business Profile API** \u2014 Add header auth credentials in *Fetch Google Reviews* with your account and location IDs.\n2. **Trustpilot API** \u2014 Add header auth credentials in *Fetch Trustpilot Reviews* and *Publish Reply* with your business unit ID.\n3. **OpenAI Account** \u2014 Connect OpenAI API in *OpenAI Chat Model*. Model is set to gpt-5-mini with temperature 0.4.\n4. **Slack Account** \u2014 Connect Slack OAuth in *Escalate to Owner*, *Request Approval*, and *Notify Ops*. Set your owner-alerts and review-replies channels.\n> Adjust the sentiment classification logic in *Draft Reply (AI Agent)* system message if you want custom routing rules. The workflow deduplicates by tracking review IDs in static data; this persists across runs but does not survive instance restarts."
},
"typeVersion": 1
},
{
"id": "3c757dfb-b6f9-47e5-96bc-b37e189daa4c",
"name": "1\ufe0f\u20e3 Fetch & Dedupe",
"type": "n8n-nodes-base.stickyNote",
"position": [
992,
544
],
"parameters": {
"color": 5,
"width": 1064,
"height": 728,
"content": "## 1\ufe0f\u20e3 Fetch & Dedupe\n\nThe **Every Hour** schedule trigger starts the run. The **Fetch Google Reviews** and **Fetch Trustpilot Reviews** nodes retrieve reviews in parallel. The **Combine Sources** node merges both lists. The **Dedupe New Reviews** code node filters to only unseen reviews using static data tracking, and **Any New Reviews?** exits early if nothing is new."
},
"typeVersion": 1
},
{
"id": "63edbdcc-df3d-400b-9d66-a868a8338384",
"name": "2\ufe0f\u20e3 AI Draft & Route",
"type": "n8n-nodes-base.stickyNote",
"position": [
2096,
560
],
"parameters": {
"color": 3,
"width": 712,
"height": 864,
"content": "## 2\ufe0f\u20e3 AI Draft & Route\n\nThe **Process Each Review** node loops through each fresh review. The **Draft Reply (AI Agent)** LangChain agent calls the **OpenAI Chat Model** and validates output via the **Structured Output Parser**, extracting sentiment, draft reply, and suggested resolution as JSON. The **Negative Review?** condition branches: negative reviews go to owner escalation, positive reviews continue to approval."
},
"typeVersion": 1
},
{
"id": "e547470b-de1e-4c38-89ba-4ba10f744445",
"name": "3\ufe0f\u20e3 Approve & Publish",
"type": "n8n-nodes-base.stickyNote",
"position": [
2848,
656
],
"parameters": {
"color": 6,
"width": 776,
"height": 816,
"content": "## 3\ufe0f\u20e3 Approve & Publish\n\nThe **Escalate to Owner** node immediately posts negative reviews and resolutions to the owner Slack channel for manual action. The **Request Approval** node sends positive draft replies to the review-replies channel with a 24-hour timeout for approval. The **Approved?** condition checks the Slack response. If approved, the **Publish Reply** node posts to Trustpilot. Both branches loop back to **Process Each Review**."
},
"typeVersion": 1
},
{
"id": "ee4e67ff-cc13-4361-80ca-46c1e03b8b68",
"name": "4\ufe0f\u20e3 Monitor",
"type": "n8n-nodes-base.stickyNote",
"position": [
992,
1312
],
"parameters": {
"color": 4,
"width": 676,
"height": 340,
"content": "## 4\ufe0f\u20e3 Monitor\n\nThe **Error Trigger** catches any workflow failure. The **Notify Ops** node immediately alerts the ops team via Slack with error details for rapid troubleshooting."
},
"typeVersion": 1
},
{
"id": "d2f3e026-b013-4d44-be16-ae68860ef666",
"name": "Every Hour",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
1024,
960
],
"parameters": {
"rule": {
"interval": [
{
"field": "hours"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "ef24142b-7bb5-4b42-9309-6706354529d4",
"name": "Fetch Google Reviews",
"type": "n8n-nodes-base.httpRequest",
"maxTries": 3,
"position": [
1264,
880
],
"parameters": {
"url": "https://mybusiness.googleapis.com/v4/YOUR_ACCOUNT/locations/YOUR_LOCATION/reviews",
"options": {
"timeout": 10000
}
},
"retryOnFail": true,
"typeVersion": 4.2
},
{
"id": "3e21a425-4eae-4ce2-bb6d-8a339c158ab6",
"name": "Fetch Trustpilot Reviews",
"type": "n8n-nodes-base.httpRequest",
"maxTries": 3,
"position": [
1264,
1056
],
"parameters": {
"url": "https://api.trustpilot.com/v1/business-units/YOUR_UNIT_ID/reviews",
"options": {
"timeout": 10000
}
},
"retryOnFail": true,
"typeVersion": 4.2
},
{
"id": "dd80613d-0068-43db-953d-21f73dd73793",
"name": "Combine Sources",
"type": "n8n-nodes-base.merge",
"position": [
1504,
960
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineAll"
},
"typeVersion": 3.2
},
{
"id": "66a57c46-e32c-4c2c-9ace-4c8ba4528873",
"name": "Dedupe New Reviews",
"type": "n8n-nodes-base.code",
"position": [
1728,
960
],
"parameters": {
"jsCode": "const staticData = $getWorkflowStaticData('global');\nif (!staticData.seenIds) staticData.seenIds = [];\nconst items = $input.all();\nconst fresh = items.filter(i => {\n const id = i.json.reviewId || i.json.id;\n return id && !staticData.seenIds.includes(id);\n});\nfresh.forEach(i => staticData.seenIds.push(i.json.reviewId || i.json.id));\nif (staticData.seenIds.length > 5000) staticData.seenIds = staticData.seenIds.slice(-2000);\nreturn fresh;"
},
"typeVersion": 2
},
{
"id": "4b7c90b5-a863-4b9d-8300-b64464b47037",
"name": "Any New Reviews?",
"type": "n8n-nodes-base.if",
"position": [
1952,
960
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "cond-new-reviews",
"operator": {
"type": "number",
"operation": "gt"
},
"leftValue": "={{ $input.all().length }}",
"rightValue": 0
}
]
}
},
"typeVersion": 2.2
},
{
"id": "e8479ec0-8114-429f-8aa1-e710437aebb0",
"name": "No New Reviews",
"type": "n8n-nodes-base.noOp",
"position": [
2192,
816
],
"parameters": {},
"typeVersion": 1
},
{
"id": "f8503e41-5584-4326-9fe4-2b5be64f6ec6",
"name": "Process Each Review",
"type": "n8n-nodes-base.splitInBatches",
"position": [
2192,
1040
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "a005edba-2192-4e85-a83f-5344a6609d79",
"name": "Limit To Done",
"type": "n8n-nodes-base.noOp",
"position": [
2432,
816
],
"parameters": {},
"typeVersion": 1
},
{
"id": "ac875b64-f44b-4766-b7a7-742b0ea0cbae",
"name": "Draft Reply (AI Agent)",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
2432,
1040
],
"parameters": {
"text": "=Review ({{ $json.rating }} stars) from {{ $json.author }}: \"{{ $json.text }}\"",
"options": {
"systemMessage": "You are the reputation manager for a local business. For every review, output JSON with: sentiment ('positive' or 'negative'), draftReply (a warm, on-brand, concise reply, max 60 words), and suggestedResolution (empty string if positive, otherwise a concrete next step for the owner)."
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 1.7
},
{
"id": "832d53f2-852b-4a4b-b411-084ac8357509",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
2416,
1216
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-5-mini"
},
"options": {
"temperature": 0.4
},
"builtInTools": {}
},
"typeVersion": 1.3
},
{
"id": "14bf9b41-3979-494a-9ca0-ba7b107e5994",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
2576,
1216
],
"parameters": {
"schemaType": "manual",
"inputSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"sentiment\": { \"type\": \"string\", \"enum\": [\"positive\", \"negative\"] },\n \"draftReply\": { \"type\": \"string\" },\n \"suggestedResolution\": { \"type\": \"string\" }\n },\n \"required\": [\"sentiment\", \"draftReply\"]\n}"
},
"typeVersion": 1.2
},
{
"id": "202dba62-2050-4915-8a42-29fe3680c9af",
"name": "Negative Review?",
"type": "n8n-nodes-base.if",
"position": [
2672,
1040
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "cond-negative",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.output.sentiment }}",
"rightValue": "negative"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "4154ca01-2ecb-49b4-a9ec-03df585d3263",
"name": "Escalate to Owner",
"type": "n8n-nodes-base.slack",
"position": [
2912,
896
],
"parameters": {
"text": "=\ud83d\udd34 Negative review ({{ $('Process Each Review').item.json.rating }}\u2605) from {{ $('Process Each Review').item.json.author }}: \"{{ $('Process Each Review').item.json.text }}\"\\nSuggested resolution: {{ $json.output.suggestedResolution }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "REPLACE_WITH_CHANNEL_ID",
"cachedResultName": "owner-alerts"
},
"otherOptions": {}
},
"typeVersion": 2.3
},
{
"id": "10017f38-9917-42df-b881-2667c17c9570",
"name": "Request Approval",
"type": "n8n-nodes-base.slack",
"position": [
2912,
1152
],
"parameters": {
"select": "channel",
"message": "=Draft reply for {{ $('Process Each Review').item.json.author }}'s {{ $('Process Each Review').item.json.rating }}\u2605 review:\\n\\n\"{{ $json.output.draftReply }}\"",
"options": {
"limitWaitTime": {
"values": {
"resumeAmount": 24
}
}
},
"channelId": {
"__rl": true,
"mode": "list",
"value": "REPLACE_WITH_CHANNEL_ID",
"cachedResultName": "review-replies"
},
"operation": "sendAndWait",
"approvalOptions": {
"values": {
"approveLabel": "Publish Reply"
}
}
},
"typeVersion": 2.3
},
{
"id": "b01c19b7-57e9-47f8-af45-3d5b535d0689",
"name": "Approved?",
"type": "n8n-nodes-base.if",
"position": [
3152,
1152
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "cond-approved",
"operator": {
"type": "boolean",
"operation": "true"
},
"leftValue": "={{ $json.data.approved }}"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "02c68c2c-c5ab-476c-8cf6-01ba394fd654",
"name": "Publish Reply",
"type": "n8n-nodes-base.httpRequest",
"maxTries": 3,
"position": [
3392,
1104
],
"parameters": {
"url": "=https://api.trustpilot.com/v1/reviews/{{ $('Process Each Review').item.json.reviewId }}/reply",
"method": "POST",
"options": {
"timeout": 10000
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "message",
"value": "={{ $('Draft Reply (AI Agent)').item.json.output.draftReply }}"
}
]
}
},
"retryOnFail": true,
"typeVersion": 4.2
},
{
"id": "63a99087-30fa-42ba-836d-cc7de88fe06d",
"name": "Error Trigger",
"type": "n8n-nodes-base.errorTrigger",
"position": [
1104,
1488
],
"parameters": {},
"typeVersion": 1
},
{
"id": "44e2b2db-a0e7-470a-b9ed-e426ae1b7ff6",
"name": "Notify Ops",
"type": "n8n-nodes-base.slack",
"position": [
1344,
1488
],
"parameters": {
"text": "=\ud83d\udea8 AI Review & Reputation Manager failed: {{ $json.execution.error.message }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "REPLACE_WITH_CHANNEL_ID",
"cachedResultName": "ops-alerts"
},
"otherOptions": {}
},
"typeVersion": 2.3
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"versionId": "af5af0e2-a868-4e0a-8ba4-8401442e7ca3",
"nodeGroups": [],
"connections": {
"Approved?": {
"main": [
[
{
"node": "Publish Reply",
"type": "main",
"index": 0
}
],
[
{
"node": "Process Each Review",
"type": "main",
"index": 0
}
]
]
},
"Every Hour": {
"main": [
[
{
"node": "Fetch Google Reviews",
"type": "main",
"index": 0
},
{
"node": "Fetch Trustpilot Reviews",
"type": "main",
"index": 0
}
]
]
},
"Error Trigger": {
"main": [
[
{
"node": "Notify Ops",
"type": "main",
"index": 0
}
]
]
},
"Publish Reply": {
"main": [
[
{
"node": "Process Each Review",
"type": "main",
"index": 0
}
]
]
},
"Combine Sources": {
"main": [
[
{
"node": "Dedupe New Reviews",
"type": "main",
"index": 0
}
]
]
},
"Any New Reviews?": {
"main": [
[
{
"node": "No New Reviews",
"type": "main",
"index": 0
}
],
[
{
"node": "Process Each Review",
"type": "main",
"index": 0
}
]
]
},
"Negative Review?": {
"main": [
[
{
"node": "Escalate to Owner",
"type": "main",
"index": 0
}
],
[
{
"node": "Request Approval",
"type": "main",
"index": 0
}
]
]
},
"Request Approval": {
"main": [
[
{
"node": "Approved?",
"type": "main",
"index": 0
}
]
]
},
"Escalate to Owner": {
"main": [
[
{
"node": "Process Each Review",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "Draft Reply (AI Agent)",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Dedupe New Reviews": {
"main": [
[
{
"node": "Any New Reviews?",
"type": "main",
"index": 0
}
]
]
},
"Process Each Review": {
"main": [
[
{
"node": "Limit To Done",
"type": "main",
"index": 0
}
],
[
{
"node": "Draft Reply (AI Agent)",
"type": "main",
"index": 0
}
]
]
},
"Fetch Google Reviews": {
"main": [
[
{
"node": "Combine Sources",
"type": "main",
"index": 0
}
]
]
},
"Draft Reply (AI Agent)": {
"main": [
[
{
"node": "Negative Review?",
"type": "main",
"index": 0
}
]
]
},
"Fetch Trustpilot Reviews": {
"main": [
[
{
"node": "Combine Sources",
"type": "main",
"index": 1
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "Draft Reply (AI Agent)",
"type": "ai_outputParser",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow runs hourly to fetch new Google Business Profile and Trustpilot reviews, deduplicates them, uses OpenAI via a LangChain agent to draft sentiment-aware replies, escalates negative reviews in Slack, and routes positive replies to Slack for approval before posting the…
Source: https://n8n.io/workflows/17054/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Monitor daily brand visibility and reputation with an automated AI-powered mention tracker. 🔍🤖 This workflow checks Hacker News every morning for new stories matching your brand keyword, classifies ea
Created by: Peyton Leveillee Last updated: October 2025
This workflow automates end-to-end sustainability lifecycle management for corporate sustainability teams, ESG governance officers, and circular economy programme leads. It addresses the challenge of
This workflow automates end-to-end ESG (Environmental, Social, and Governance) sustainability reporting for enterprise sustainability teams, compliance officers, and green governance leads. It solves
This workflow is designed for Japanese-speaking professionals, and learners who want to efficiently stay up to date with practical productivity, lifehack, and efficiency-related insights from Japanese