This workflow corresponds to n8n.io template #8746 — we link there as the canonical source.
This workflow follows the Google Sheets → Slack 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": "PdbwxMitcnvpqIV7",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Monitor Zendesk Churn Risk Signals and Notify CS Team in Slack",
"tags": [],
"nodes": [
{
"id": "85c1fc94-a3ce-472c-9f08-56f7272d4f66",
"name": "Log Churn Risk to Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
672,
1040
],
"parameters": {
"columns": {
"value": {},
"schema": [
{
"id": "ticket_id",
"type": "string",
"display": true,
"required": false,
"displayName": "ticket_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "subject",
"type": "string",
"display": true,
"required": false,
"displayName": "subject",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "description",
"type": "string",
"display": true,
"required": false,
"displayName": "description",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "status",
"type": "string",
"display": true,
"required": false,
"displayName": "status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "priority",
"type": "string",
"display": true,
"required": false,
"displayName": "priority",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "type",
"type": "string",
"display": true,
"required": false,
"displayName": "type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "created_at",
"type": "string",
"display": true,
"required": false,
"displayName": "created_at",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "updated_at",
"type": "string",
"display": true,
"required": false,
"displayName": "updated_at",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "channel",
"type": "string",
"display": true,
"required": false,
"displayName": "channel",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "requester_id",
"type": "string",
"display": true,
"required": false,
"displayName": "requester_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "assignee_id",
"type": "string",
"display": true,
"required": false,
"displayName": "assignee_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "organization_id",
"type": "string",
"display": true,
"required": false,
"displayName": "organization_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "group_id",
"type": "string",
"display": true,
"required": false,
"displayName": "group_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "tags",
"type": "string",
"display": true,
"required": false,
"displayName": "tags",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "encoded_id",
"type": "string",
"display": true,
"required": false,
"displayName": "encoded_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ticket_url",
"type": "string",
"display": true,
"required": false,
"displayName": "ticket_url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "is_public",
"type": "string",
"display": true,
"required": false,
"displayName": "is_public",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "satisfaction_score",
"type": "string",
"display": true,
"required": false,
"displayName": "satisfaction_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "custom_status_id",
"type": "string",
"display": true,
"required": false,
"displayName": "custom_status_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "brand_id",
"type": "string",
"display": true,
"required": false,
"displayName": "brand_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "formatted_at",
"type": "string",
"display": true,
"required": false,
"displayName": "formatted_at",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "is_urgent",
"type": "string",
"display": true,
"required": false,
"displayName": "is_urgent",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "has_assignee",
"type": "string",
"display": true,
"required": false,
"displayName": "has_assignee",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "priority_level",
"type": "string",
"display": true,
"required": false,
"displayName": "priority_level",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ticket_age_hours",
"type": "string",
"display": true,
"required": false,
"displayName": "ticket_age_hours",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "needs_attention",
"type": "string",
"display": true,
"required": false,
"displayName": "needs_attention",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "channel_type",
"type": "string",
"display": true,
"required": false,
"displayName": "channel_type",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "autoMapInputData",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/11ojVmCr69OzkW8nGhkeXm9c3g8nNzqz5G4DFSfJvofQ/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "11ojVmCr69OzkW8nGhkeXm9c3g8nNzqz5G4DFSfJvofQ",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/11ojVmCr69OzkW8nGhkeXm9c3g8nNzqz5G4DFSfJvofQ/edit?usp=drivesdk",
"cachedResultName": "Churn Risk Ticket"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4
},
{
"id": "2913f3a0-f1ba-470c-89fb-0e8109732d36",
"name": "Send Slack Alert",
"type": "n8n-nodes-base.slack",
"position": [
672,
1248
],
"parameters": {
"text": "=\ud83d\udea8 *Churn Risk Alert*\n\n**Ticket ID:** {{ $json.ticket_id }}\n**Rating:** {{ $json.satisfaction_score }} \n**Subject:** {{ $json.subject }} \n**Description:** {{ $json.description }} \n\n**Action Required:** Please reach out to this customer immediately to address their concerns.",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "C09FM9N8UEA",
"cachedResultName": "zendesk-YOUR_OPENAI_KEY_HERE-alerts"
},
"otherOptions": {
"includeLinkToWorkflow": false
}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2
},
{
"id": "3690cb18-cfca-49ad-8583-1a35442ed74d",
"name": "Fetch Zendesk Tickets",
"type": "n8n-nodes-base.zendesk",
"position": [
-112,
1152
],
"parameters": {
"options": {},
"operation": "getAll"
},
"credentials": {
"zendeskApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "3f4c0ada-de8a-4c76-970d-9d6ec950f71f",
"name": "Format Ticket Data",
"type": "n8n-nodes-base.code",
"position": [
96,
1152
],
"parameters": {
"jsCode": "// n8n Code Node - Zendesk Ticket Formatter\n// This code processes Zendesk ticket data and formats it into clean JSON structure\n\n// Function to format individual ticket data\nfunction formatTicketData(ticketData) {\n return {\n ticket_id: ticketData.id,\n subject: ticketData.subject || \"No Subject\",\n description: ticketData.description || \"No Description\",\n status: ticketData.status,\n priority: ticketData.priority,\n type: ticketData.type || \"general\",\n created_at: ticketData.created_at,\n updated_at: ticketData.updated_at,\n channel: ticketData.via?.channel || \"unknown\",\n requester_id: ticketData.requester_id,\n assignee_id: ticketData.assignee_id,\n organization_id: ticketData.organization_id,\n group_id: ticketData.group_id,\n tags: ticketData.tags || [],\n encoded_id: ticketData.encoded_id,\n ticket_url: ticketData.url,\n is_public: ticketData.is_public,\n satisfaction_score: ticketData.satisfaction_rating?.score || \"not_rated\",\n custom_status_id: ticketData.custom_status_id,\n brand_id: ticketData.brand_id,\n formatted_at: new Date().toISOString(),\n is_urgent: (ticketData.tags || []).includes('urgent'),\n has_assignee: ticketData.assignee_id ? true : false\n };\n}\n\n// Function to get priority level (for sorting/filtering)\nfunction getPriorityLevel(priority) {\n const levels = {\n 'low': 1,\n 'normal': 2,\n 'high': 3,\n 'urgent': 4\n };\n return levels[priority] || 2;\n}\n\n// Function to calculate ticket age in hours\nfunction getTicketAgeHours(createdAt) {\n const created = new Date(createdAt);\n const now = new Date();\n return Math.round((now - created) / (1000 * 60 * 60));\n}\n\n// Loop over input items and format each Zendesk ticket\nfor (const item of $input.all()) {\n // Get the original ticket data\n const originalTicket = item.json;\n \n // Format the ticket data into clean structure\n const formattedTicket = formatTicketData(originalTicket);\n \n // Add additional computed fields\n item.json = {\n ...formattedTicket,\n priority_level: getPriorityLevel(originalTicket.priority),\n ticket_age_hours: getTicketAgeHours(originalTicket.created_at),\n needs_attention: (\n originalTicket.status === 'open' && \n ((originalTicket.tags || []).includes('urgent') || \n getTicketAgeHours(originalTicket.created_at) > 24)\n ),\n channel_type: originalTicket.via?.channel === 'web' ? 'self_service' : \n originalTicket.via?.channel === 'api' ? 'system_generated' : \n originalTicket.via?.channel || 'unknown'\n };\n}\n\n// Return all processed items\nreturn $input.all();"
},
"typeVersion": 2
},
{
"id": "2d7eb3f7-d214-4e7b-b316-8f831e08583a",
"name": "StickyNote3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-208,
752
],
"parameters": {
"width": 267,
"height": 364,
"content": "## \ud83d\udce5 Ticket Retrieval\n\nFetches all tickets from your Zendesk instance.\n\n**\ud83d\udd27 Customization Options:**\n- Add filters for specific ticket types\n- Limit to recent tickets (last 24h)\n- Filter by organization or user segments\n- Add status filters (open, pending, etc.)\n\n**\u26a1 Performance:** Handles 100+ tickets efficiently"
},
"typeVersion": 1
},
{
"id": "a0d7fdf9-8067-4a7a-ac49-a7fa3509c3ab",
"name": "StickyNote4",
"type": "n8n-nodes-base.stickyNote",
"position": [
32,
1296
],
"parameters": {
"width": 263,
"height": 328,
"content": "## \ud83d\udd27 Data Processing\n\nTransforms raw Zendesk data into clean, structured format.\n\n**\u2728 Enhancements added:**\n- Ticket age calculation\n- Priority level mapping\n- Urgency flags\n- Channel categorization\n- Null value handling\n\n**\ud83d\udcca Output:** Clean JSON ready for filtering and alerts"
},
"typeVersion": 1
},
{
"id": "eec3e927-9e60-4bf8-9b6c-d3f9115e1e91",
"name": "StickyNote5",
"type": "n8n-nodes-base.stickyNote",
"position": [
224,
752
],
"parameters": {
"width": 290,
"height": 388,
"content": "## \u2696\ufe0f Churn Risk Filter\n\nIdentifies tickets with negative satisfaction scores.\n\n**\ud83c\udfaf Current Logic:**\n- satisfaction_score = \"bad\"\n\n**\ud83d\udd04 Extend to include:**\n- Multiple bad ratings from same customer\n- High-priority unresolved tickets\n- Tickets open > 48 hours\n- VIP customer complaints\n\n**\ud83d\udcc8 Customize:** Adjust criteria based on your churn patterns"
},
"typeVersion": 1
},
{
"id": "b75fafe4-88de-4683-9524-a14ea0c0edf2",
"name": "StickyNote6",
"type": "n8n-nodes-base.stickyNote",
"position": [
624,
624
],
"parameters": {
"width": 267,
"height": 408,
"content": "## \ud83d\udccb Tracking & Analytics\n\nLogs all churn risk incidents to Google Sheets for analysis.\n\n**\ud83d\udcca Captured Data:**\n- Ticket details\n- Satisfaction scores\n- Timestamp\n- Customer info\n\n**\ud83d\udca1 Use for:**\n- Monthly churn reports\n- Trend analysis\n- Team performance tracking\n- Customer health scoring"
},
"typeVersion": 1
},
{
"id": "f910ff82-e32a-421a-b10f-9aafd2e51a92",
"name": "StickyNote7",
"type": "n8n-nodes-base.stickyNote",
"position": [
624,
1408
],
"parameters": {
"width": 298,
"height": 409,
"content": "## \ud83d\udea8 Instant Team Alerts\n\nSends formatted Slack message to your CS team channel.\n\n**\ud83d\udce2 Message includes:**\n- Ticket ID & direct link\n- Customer satisfaction rating\n- Subject & description\n- Clear action required\n\n**\ud83c\udfa8 Customize:**\n- Add @mentions for specific team members\n- Include customer tier/value\n- Add escalation buttons\n- Format with Slack blocks for better UX"
},
"typeVersion": 1
},
{
"id": "5a2dbeb2-b3ce-429f-8291-d4070e26165f",
"name": "Check Negative Feedback",
"type": "n8n-nodes-base.if",
"position": [
336,
1152
],
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.satisfaction_score }}",
"value2": "bad"
}
]
},
"combineOperation": "any"
},
"typeVersion": 1
},
{
"id": "ceb7a743-8028-47b1-af90-95eceab7eded",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-352,
1152
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 0 20 * * 1-5"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "e33a6d2e-cb33-4b52-a9a7-b3ee885387eb",
"name": "StickyNote",
"type": "n8n-nodes-base.stickyNote",
"position": [
-560,
1296
],
"parameters": {
"width": 263,
"height": 312,
"content": "## \ud83d\udd27 Automated Schedule Trigger\n\nDaily Execution: Runs every day at 8:00 PM\n\u2699\ufe0f Configuration:\n\nTrigger Rule: 0 20 * * * (Cron expression) \n\nTimezone: Set to your local timezone \n\nMode: Every Day"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "96c30166-321c-4be9-bfef-401706c70cdb",
"connections": {
"Schedule Trigger": {
"main": [
[
{
"node": "Fetch Zendesk Tickets",
"type": "main",
"index": 0
}
]
]
},
"Format Ticket Data": {
"main": [
[
{
"node": "Check Negative Feedback",
"type": "main",
"index": 0
}
]
]
},
"Fetch Zendesk Tickets": {
"main": [
[
{
"node": "Format Ticket Data",
"type": "main",
"index": 0
}
]
]
},
"Check Negative Feedback": {
"main": [
[
{
"node": "Log Churn Risk to Sheet",
"type": "main",
"index": 0
},
{
"node": "Send Slack Alert",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
googleSheetsOAuth2ApislackApizendeskApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Automatically detect customer churn risks from Zendesk tickets, log them into Google Sheets for tracking, and send instant Slack alerts to your customer success team. This workflow helps you spot unhappy customers early and take proactive action to reduce churn. 🚨📊💬 Fetches…
Source: https://n8n.io/workflows/8746/ — 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.
Ensure your customer SLAs never slip with this n8n automation template. The workflow runs on a schedule, fetching open tickets from Zendesk, calculating SLA time remaining, and sending proactive alert
This workflow continuously monitors the Meta Ads Library for new creatives from a specific competitor pages, logs them into Google Sheets, and sends a concise Telegram notification with the number of
Enhance financial oversight with this automated n8n workflow. Triggered every 5 minutes, it fetches real-time bank transactions via an API, enriches and transforms the data, and applies smart logic to
This workflow automates competitive price intelligence using Bright Data's enterprise web scraping API. On a scheduled basis (default: daily at 9 AM), the system loops through configured competitor pr
> n8n, Binance API, Google Sheets, Slack, Telegram, Jira & Email