This workflow corresponds to n8n.io template #17147 — we link there as the canonical source.
This workflow follows the Gmail → Google Sheets 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": "TFGOETci2MiMoI3f",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "NPS Survey Auto-Handler - AI Reply, Score Routing, Gmail and Google Sheets",
"tags": [],
"nodes": [
{
"id": "2011d78b-7ab8-496f-8a65-8d10c3985f66",
"name": "Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2256,
-160
],
"parameters": {
"width": 480,
"height": 964,
"content": "## NPS Survey Auto-Handler\n\nTurn raw NPS survey rows in a Google Sheet into personalized customer replies with no manual work. This is for support, customer success, and product teams who collect Net Promoter Score feedback and want every respondent handled the same day. The flow runs on a schedule, writes a unique reply for each person, and routes promoters, passives, and detractors to the right follow-up.\n\n### How it works\n1. A **Schedule** trigger reads new rows from your NPS sheet every 6 hours and keeps only rows marked new.\n2. A **Code** node checks the row and turns the 0 to 10 score into a segment: Promoter, Passive, or Detractor.\n3. An **OpenAI** request writes a warm, personal email reply that fits the score and the comment.\n4. **Gmail** sends that reply to the customer, then a **Switch** sends each person down the matching branch.\n5. Promoter quotes are saved to a testimonials tab, detractors trigger a support alert, and every row is marked Processed.\n\n### Setup steps\n1. Connect your Google Sheets and Gmail accounts in n8n, and add an OpenAI credential on node 5.\n2. Replace YOUR_NPS_SHEET_ID with your sheet ID in nodes 2, 8, 9, 11, and 13.\n3. Replace YOUR_SUPPORT_TEAM_EMAIL with your team inbox in node 12.\n4. Activate the workflow, add a test row with Status set to new, and run once to confirm.\n\n### Customization\n- Change the run frequency on node 1 (default is every 6 hours).\n- Edit the tone or length of the reply in the prompt on node 5."
},
"typeVersion": 1
},
{
"id": "46ff0c04-98f9-4635-9486-ee27d0d7c01d",
"name": "Sheet Columns",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1632,
416
],
"parameters": {
"color": 7,
"width": 900,
"height": 332,
"content": "## Google Sheet columns\n\nMain tab (nps-responses):\nTimestamp, Name, Email, NPS Score, Comment, Product, Status.\nStatus values: new (to process), Processed (done).\n\nTestimonials tab (promoter-quotes):\nDate, Name, Email, NPS Score, Quote, Product.\n\nStatus rows are matched for the update by Email."
},
"typeVersion": 1
},
{
"id": "8539e6b2-13fd-4c75-9161-68abf41892c3",
"name": "S1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1632,
16
],
"parameters": {
"color": 7,
"width": 794,
"height": 328,
"content": "## 1. Trigger and read\nRuns on a schedule, reads the NPS sheet, and keeps only rows with Status new so nothing is processed twice."
},
"typeVersion": 1
},
{
"id": "03d8b5f4-bd5d-4f85-8a05-1013919a8c99",
"name": "S2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-752,
16
],
"parameters": {
"color": 7,
"width": 758,
"height": 328,
"content": "## 2. Validate and write reply\nChecks each row and scores it into a segment, then OpenAI drafts a personal email and the next node builds the subject line."
},
"typeVersion": 1
},
{
"id": "11e650cd-0d7b-4900-8f41-f809dba08bc5",
"name": "S3",
"type": "n8n-nodes-base.stickyNote",
"position": [
64,
-96
],
"parameters": {
"color": 7,
"width": 534,
"height": 584,
"content": "## 3. Send reply and route\nEmails the personal reply to the customer, then routes each person by segment: Promoter, Passive, or Detractor."
},
"typeVersion": 1
},
{
"id": "f4e4f3fa-d778-48ef-83d1-6b6da87c4219",
"name": "S4",
"type": "n8n-nodes-base.stickyNote",
"position": [
768,
-352
],
"parameters": {
"color": 7,
"width": 598,
"height": 1044,
"content": "## 4. Branch actions\nPromoters: save the quote, then mark Processed. Passives: mark Processed. Detractors: alert the support team, then mark Processed."
},
"typeVersion": 1
},
{
"id": "8253703f-67e1-43aa-9b9c-c97749c1b9ba",
"name": "1. Schedule - Run Every 6 Hours",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-1520,
160
],
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 6
}
]
}
},
"typeVersion": 1.2
},
{
"id": "b9110224-571a-4e4c-882d-33bf2f8c1c30",
"name": "2. Sheets - Read NPS Responses",
"type": "n8n-nodes-base.googleSheets",
"position": [
-1280,
160
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "name",
"value": "nps-responses"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_NPS_SHEET_ID"
}
},
"typeVersion": 4.5
},
{
"id": "6c34bd9f-9126-4978-ad99-b19ff89d8b2c",
"name": "3. Filter - Only Status New Rows",
"type": "n8n-nodes-base.filter",
"position": [
-1040,
160
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": false,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "cond-new-status",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.Status }}",
"rightValue": "new"
}
]
}
},
"typeVersion": 2.3
},
{
"id": "02f44217-7ca0-4275-8f48-c6cd5f5f325b",
"name": "4. Code - Validate and Parse NPS Score",
"type": "n8n-nodes-base.code",
"position": [
-688,
160
],
"parameters": {
"jsCode": "// Validate required fields and parse NPS score\nconst row = $json;\n\nconst name = (row.Name || '').trim();\nconst email = (row.Email || '').trim();\nconst comment = (row.Comment || '').trim();\nconst product = (row.Product || 'our product').trim();\nconst timestamp = (row.Timestamp || new Date().toISOString()).trim();\n\nif (!name) throw new Error('Name is missing in row: ' + JSON.stringify(row));\nif (!email || !email.includes('@')) throw new Error('Valid email is missing in row for: ' + name);\n\n// Parse NPS score as integer 0-10\nconst rawScore = row['NPS Score'] || row['Score'] || row['Rating'] || 0;\nconst npsScore = parseInt(String(rawScore).trim(), 10);\n\nif (isNaN(npsScore) || npsScore < 0 || npsScore > 10) {\n throw new Error('NPS score must be 0-10. Found: ' + rawScore + ' for ' + name);\n}\n\n// Determine NPS segment\nconst segment =\n npsScore >= 9 ? 'Promoter' :\n npsScore >= 7 ? 'Passive' :\n 'Detractor';\n\n// Segment description for AI prompt\nconst segmentContext =\n segment === 'Promoter' ? 'highly satisfied customer who loves the product (score ' + npsScore + '/10)' :\n segment === 'Passive' ? 'moderately satisfied customer who has some reservations (score ' + npsScore + '/10)' :\n 'dissatisfied customer who had a poor experience (score ' + npsScore + '/10)';\n\nconst dateOnly = new Date().toISOString().split('T')[0];\n\nreturn [{\n json: {\n name, email, comment, product, timestamp,\n npsScore, segment, segmentContext, dateOnly\n }\n}];"
},
"typeVersion": 2
},
{
"id": "856c2229-ed4e-4b1a-972f-4233d53aab4c",
"name": "5. HTTP - OpenAI Generate Personalized Reply",
"type": "n8n-nodes-base.httpRequest",
"position": [
-448,
160
],
"parameters": {
"url": "https://api.openai.com/v1/chat/completions",
"method": "POST",
"options": {
"timeout": 30000
},
"jsonBody": "={\n \"model\": \"gpt-4o-mini\",\n \"temperature\": 0.5,\n \"max_tokens\": 300,\n \"messages\": [\n {\n \"role\": \"system\",\n \"content\": \"You are a customer success specialist writing personalized email replies to NPS survey responses. Write in a warm, genuine, professional tone. Never sound like a template. Use the customer's name. Reference their specific comment if provided. Keep the email concise - 3 to 4 short paragraphs maximum. Do not include a subject line. Do not include placeholders. Just write the email body text.\"\n },\n {\n \"role\": \"user\",\n \"content\": {{ JSON.stringify(\n \"Write a personalized email reply to this NPS survey response:\\n\\n\" +\n \"Customer Name: \" + $json.name + \"\\n\" +\n \"Product: \" + $json.product + \"\\n\" +\n \"NPS Score: \" + $json.npsScore + \" out of 10\\n\" +\n \"Segment: \" + $json.segment + \" (\" + $json.segmentContext + \")\\n\" +\n \"Their Comment: \" + ($json.comment || 'No comment provided') + \"\\n\\n\" +\n \"Instructions based on segment:\\n\" +\n ($json.segment === 'Promoter' ? \"Thank them warmly for their loyalty. Mention that their feedback means a lot. Optionally invite them to share a review or refer a friend.\" : \"\") +\n ($json.segment === 'Passive' ? \"Thank them for their honest feedback. Acknowledge there is room to improve. Ask one specific question about what would make the experience a 10 out of 10.\" : \"\") +\n ($json.segment === 'Detractor' ? \"Sincerely apologize for falling short of their expectations. Show empathy. Mention that a team member will follow up personally. Do not make excuses.\" : \"\")\n ) }}\"\n }\n ]\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"nodeCredentialType": "openAiApi"
},
"typeVersion": 4.3
},
{
"id": "cfb0f2b8-e040-44ae-b14e-47e60db76970",
"name": "5b. Code - Parse AI Reply and Build Email",
"type": "n8n-nodes-base.code",
"position": [
-208,
160
],
"parameters": {
"jsCode": "// Parse AI reply and merge with respondent context\nconst gptResp = $json;\nconst ctx = $('4. Code - Validate and Parse NPS Score').first().json;\n\nconst rawReply = gptResp?.choices?.[0]?.message?.content || '';\nif (!rawReply) throw new Error('OpenAI returned empty response. Check your API key.');\n\nconst emailBody = rawReply.trim();\n\n// Build email subject based on segment\nconst subject =\n ctx.segment === 'Promoter' ? 'Thank you for your amazing feedback, ' + ctx.name + '!' :\n ctx.segment === 'Passive' ? 'Your feedback matters - a quick question for you, ' + ctx.name :\n 'We are sorry - personal follow-up from our team, ' + ctx.name;\n\nreturn [{\n json: {\n name: ctx.name,\n email: ctx.email,\n comment: ctx.comment,\n product: ctx.product,\n npsScore: ctx.npsScore,\n segment: ctx.segment,\n dateOnly: ctx.dateOnly,\n emailBody,\n emailSubject: subject\n }\n}];"
},
"typeVersion": 2
},
{
"id": "0590ff5a-e8c3-4102-941b-c1293c0d5319",
"name": "6. Gmail - Send Personalized Reply to Customer",
"type": "n8n-nodes-base.gmail",
"position": [
144,
160
],
"parameters": {
"sendTo": "={{ $json.email }}",
"message": "={{ $json.emailBody }}",
"options": {
"senderName": "Customer Success Team",
"appendAttribution": false
},
"subject": "={{ $json.emailSubject }}"
},
"typeVersion": 2.1
},
{
"id": "77fa337f-4d8c-48d6-9895-ea6fd103b04b",
"name": "7. Switch - Route by NPS Segment",
"type": "n8n-nodes-base.switch",
"position": [
384,
144
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "Promoter",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "r-promoter",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.segment }}",
"rightValue": "Promoter"
}
]
},
"renameOutput": true
},
{
"outputKey": "Passive",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "r-passive",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.segment }}",
"rightValue": "Passive"
}
]
},
"renameOutput": true
},
{
"outputKey": "Detractor",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "r-detractor",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.segment }}",
"rightValue": "Detractor"
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3.4
},
{
"id": "d4d943e1-a076-49ac-878b-bcaaf06b254d",
"name": "8. Sheets - Save Promoter Quote",
"type": "n8n-nodes-base.googleSheets",
"position": [
912,
-112
],
"parameters": {
"columns": {
"value": {
"Date": "={{ $json.dateOnly }}",
"Name": "={{ $json.name }}",
"Email": "={{ $json.email }}",
"Quote": "={{ $json.comment }}",
"Product": "={{ $json.product }}",
"NPS Score": "={{ $json.npsScore }}"
},
"schema": [
{
"id": "Date",
"type": "string",
"display": true,
"required": false,
"displayName": "Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Name",
"type": "string",
"display": true,
"required": false,
"displayName": "Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Email",
"type": "string",
"display": true,
"required": false,
"displayName": "Email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "NPS Score",
"type": "string",
"display": true,
"required": false,
"displayName": "NPS Score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Quote",
"type": "string",
"display": true,
"required": false,
"displayName": "Quote",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Product",
"type": "string",
"display": true,
"required": false,
"displayName": "Product",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": true
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "promoter-quotes"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_NPS_SHEET_ID"
}
},
"typeVersion": 4.5
},
{
"id": "b0c97597-4764-4b70-8292-8705b9836582",
"name": "9. Sheets - Update Promoter Status to Processed",
"type": "n8n-nodes-base.googleSheets",
"position": [
1152,
-112
],
"parameters": {
"columns": {
"value": {
"Email": "={{ $json.email }}",
"Status": "Processed"
},
"schema": [
{
"id": "Name",
"type": "string",
"display": true,
"required": false,
"displayName": "Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Email",
"type": "string",
"display": true,
"required": false,
"displayName": "Email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "NPS Score",
"type": "string",
"display": true,
"required": false,
"displayName": "NPS Score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Comment",
"type": "string",
"display": true,
"required": false,
"displayName": "Comment",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Product",
"type": "string",
"display": true,
"required": false,
"displayName": "Product",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "string",
"display": true,
"required": false,
"displayName": "Status",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"Email"
],
"attemptToConvertTypes": false,
"convertFieldsToString": true
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "nps-responses"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_NPS_SHEET_ID"
}
},
"typeVersion": 4.5
},
{
"id": "6eac381c-e845-4e0e-9660-c93ef31d87b2",
"name": "11. Sheets - Update Passive Status to Processed",
"type": "n8n-nodes-base.googleSheets",
"position": [
912,
128
],
"parameters": {
"columns": {
"value": {
"Email": "={{ $json.email }}",
"Status": "Processed"
},
"schema": [
{
"id": "Name",
"type": "string",
"display": true,
"required": false,
"displayName": "Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Email",
"type": "string",
"display": true,
"required": false,
"displayName": "Email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "NPS Score",
"type": "string",
"display": true,
"required": false,
"displayName": "NPS Score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Comment",
"type": "string",
"display": true,
"required": false,
"displayName": "Comment",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Product",
"type": "string",
"display": true,
"required": false,
"displayName": "Product",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "string",
"display": true,
"required": false,
"displayName": "Status",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"Email"
],
"attemptToConvertTypes": false,
"convertFieldsToString": true
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "nps-responses"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_NPS_SHEET_ID"
}
},
"typeVersion": 4.5
},
{
"id": "f39ceaba-0199-4c18-9def-c342455178cb",
"name": "12. Gmail - Send Detractor Alert to Support Team",
"type": "n8n-nodes-base.gmail",
"position": [
912,
368
],
"parameters": {
"sendTo": "YOUR_SUPPORT_TEAM_EMAIL",
"message": "=<div style=\"font-family:Arial,sans-serif;max-width:620px;margin:0 auto;\">\n <div style=\"background:#dc2626;padding:18px 22px;border-radius:8px 8px 0 0;\">\n <h2 style=\"color:#fff;margin:0;font-size:17px;\">NPS Detractor Alert - Immediate Action Needed</h2>\n </div>\n <div style=\"background:#fff;padding:20px 22px;border:1px solid #fca5a5;border-top:none;\">\n <table style=\"width:100%;font-size:14px;\">\n <tr><td style=\"padding:6px 0;color:#555;width:140px;\">Customer</td><td style=\"font-weight:700;color:#111;\">{{ $json.name }}</td></tr>\n <tr><td style=\"padding:6px 0;color:#555;\">Email</td><td style=\"color:#111;\">{{ $json.email }}</td></tr>\n <tr><td style=\"padding:6px 0;color:#555;\">Product</td><td style=\"color:#111;\">{{ $json.product }}</td></tr>\n <tr><td style=\"padding:6px 0;color:#555;\">NPS Score</td><td style=\"color:#dc2626;font-weight:700;font-size:16px;\">{{ $json.npsScore }} / 10</td></tr>\n <tr><td style=\"padding:6px 0;color:#555;vertical-align:top;\">Their Comment</td><td style=\"color:#111;line-height:1.6;\">{{ $json.comment || 'No comment provided' }}</td></tr>\n </table>\n <div style=\"background:#fef2f2;border-left:4px solid #dc2626;padding:12px 14px;margin-top:16px;border-radius:0 6px 6px 0;\">\n <p style=\"margin:0;font-size:13px;color:#7f1d1d;\"><strong>Action:</strong> A personal recovery email has already been sent to the customer. Please follow up with a direct call or personal email within 24 hours.</p>\n </div>\n </div>\n <div style=\"background:#f3f4f6;padding:10px 22px;border-radius:0 0 8px 8px;\">\n <p style=\"font-size:11px;color:#888;margin:0;\">NPS Survey Auto-Handler - n8n + OpenAI</p>\n </div>\n</div>",
"options": {
"senderName": "NPS Alert System",
"appendAttribution": false
},
"subject": "=URGENT - NPS Detractor Alert: {{ $json.name }} scored {{ $json.npsScore }}/10"
},
"typeVersion": 2.1
},
{
"id": "a1e03f52-5e94-48ac-9d73-70fc2445ff27",
"name": "13. Sheets - Update Detractor Status to Processed",
"type": "n8n-nodes-base.googleSheets",
"position": [
1152,
368
],
"parameters": {
"columns": {
"value": {
"Email": "={{ $json.email }}",
"Status": "Processed"
},
"schema": [
{
"id": "Name",
"type": "string",
"display": true,
"required": false,
"displayName": "Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Email",
"type": "string",
"display": true,
"required": false,
"displayName": "Email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "NPS Score",
"type": "string",
"display": true,
"required": false,
"displayName": "NPS Score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Comment",
"type": "string",
"display": true,
"required": false,
"displayName": "Comment",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Product",
"type": "string",
"display": true,
"required": false,
"displayName": "Product",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "string",
"display": true,
"required": false,
"displayName": "Status",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"Email"
],
"attemptToConvertTypes": false,
"convertFieldsToString": true
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "nps-responses"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_NPS_SHEET_ID"
}
},
"typeVersion": 4.5
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"versionId": "e9f61515-b8d2-4af6-a746-b52b5a86e11c",
"nodeGroups": [],
"connections": {
"2. Sheets - Read NPS Responses": {
"main": [
[
{
"node": "3. Filter - Only Status New Rows",
"type": "main",
"index": 0
}
]
]
},
"1. Schedule - Run Every 6 Hours": {
"main": [
[
{
"node": "2. Sheets - Read NPS Responses",
"type": "main",
"index": 0
}
]
]
},
"8. Sheets - Save Promoter Quote": {
"main": [
[
{
"node": "9. Sheets - Update Promoter Status to Processed",
"type": "main",
"index": 0
}
]
]
},
"3. Filter - Only Status New Rows": {
"main": [
[
{
"node": "4. Code - Validate and Parse NPS Score",
"type": "main",
"index": 0
}
]
]
},
"7. Switch - Route by NPS Segment": {
"main": [
[
{
"node": "8. Sheets - Save Promoter Quote",
"type": "main",
"index": 0
}
],
[
{
"node": "11. Sheets - Update Passive Status to Processed",
"type": "main",
"index": 0
}
],
[
{
"node": "12. Gmail - Send Detractor Alert to Support Team",
"type": "main",
"index": 0
}
]
]
},
"4. Code - Validate and Parse NPS Score": {
"main": [
[
{
"node": "5. HTTP - OpenAI Generate Personalized Reply",
"type": "main",
"index": 0
}
]
]
},
"5b. Code - Parse AI Reply and Build Email": {
"main": [
[
{
"node": "6. Gmail - Send Personalized Reply to Customer",
"type": "main",
"index": 0
}
]
]
},
"5. HTTP - OpenAI Generate Personalized Reply": {
"main": [
[
{
"node": "5b. Code - Parse AI Reply and Build Email",
"type": "main",
"index": 0
}
]
]
},
"6. Gmail - Send Personalized Reply to Customer": {
"main": [
[
{
"node": "7. Switch - Route by NPS Segment",
"type": "main",
"index": 0
}
]
]
},
"12. Gmail - Send Detractor Alert to Support Team": {
"main": [
[
{
"node": "13. Sheets - Update Detractor Status to Processed",
"type": "main",
"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 every 6 hours to read new NPS responses from Google Sheets, uses OpenAI to draft a personalized reply, sends it via Gmail, routes respondents by NPS segment, logs promoter quotes back to Google Sheets, alerts support on detractors, and marks each row as…
Source: https://n8n.io/workflows/17147/ — 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.
This workflow runs twice daily to fetch recent Instagram post comments via the Instagram Graph API, uses OpenAI to classify sentiment, saves new positive comments to Google Sheets, and emails an HTML
This workflow runs daily to pull job applicants from Google Sheets, score each candidate against role requirements using the Google Gemini API, log results back to Google Sheets, and notify a Slack ch
Founder's Discovery Engine. Uses googleSheets, googleDrive, httpRequest, gmail. Scheduled trigger; 18 nodes.
Know what your competitors are doing every morning before your first meeting. This workflow visits each competitor website daily, uses OpenAI to analyse it for strategic signals, and emails your team
Who's this for Finance teams, AI developers, product managers, and business owners who need to monitor and control OpenAI API costs across different models and projects. If you're using GPT-4, GPT-3.5