NinA AI

Freebies · n8n

Review Slack Agent

Download the complete N8N workflow JSON for a Review Slack Agent that analyzes and summarizes customer reviews.

Review Slack Agent

Below you will find the JSON for the Review Slack Agent. Note: you can also connect your reviews through external services — if you get stuck, feel free to send me a message!

New to N8N? We wrote a short introduction to N8N, you can find it here:

Download N8N Setup Guide (PDF)

JSON File

n8n workflow JSON
{
  "name": "Slack Demo",
  "nodes": [
    {
      "parameters": {
        "jsCode": "const b = $json.body || $json;\nconst parts = (b.text || \"\").trim().split(/\\s+/);\n\nreturn [{\n  topic: parts[0] || \"BigTall\",\n  lookbackDays: parseInt(parts[1] || \"365\", 10),\n  responseUrl: b.response_url,\n  channelId: b.channel_id,\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        0,
        0
      ],
      "id": "9242e300-ac67-41de-8b90-5974b97c17cc",
      "name": "Parse Slash Params"
    },
    {
      "parameters": {
        "documentId": {
          "__rl": true,
          "value": "1aqO3DcacWjT1ijCr2wQGW6ScVH73zFux3wmjD5p3zm8",
          "mode": "list",
          "cachedResultName": "Customer Reviews",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1aqO3DcacWjT1ijCr2wQGW6ScVH73zFux3wmjD5p3zm8/edit?usp=drivesdk"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "Reviews",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1aqO3DcacWjT1ijCr2wQGW6ScVH73zFux3wmjD5p3zm8/edit#gid=0"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        432,
        0
      ],
      "id": "1fd2d536-90a4-4f20-a1f2-89fd6af9e420",
      "name": "Get row(s) in sheet",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "nRNcPx3A1pXw2Vn5",
          "name": "Google Sheets account"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "function fromSlash() {\n  try {\n    const body = $items('Slack Webhook')[0].json.body || {};\n    const raw = (body.text || '').toString().trim();\n    const m = raw.match(/--days\\s+(\\d+)/i);\n    const lookbackDays = m ? parseInt(m[1], 10) : 365;\n    const topic = raw.replace(/--days\\s+\\d+/ig, '').trim().toLowerCase();\n    return { topic, lookbackDays };\n  } catch (_) {\n    return { topic: '', lookbackDays: 365 };\n  }\n}\n\nconst params = fromSlash();\nconst topic = params.topic;\nconst lookbackDays = params.lookbackDays;\nconst since = Date.now() - (lookbackDays * 86400000);\n\nconst kept = [];\nfor (const row of items) {\n  const r = row.json || {};\n  const ts = new Date(r.date).getTime();\n  if (!Number.isFinite(ts) || ts < since) continue;\n  const blob = ((r.text || '') + ' ' + (r.title || '')).toLowerCase();\n  if (!topic || blob.includes(topic)) kept.push(r);\n}\n\nconst out = (kept.length ? kept : items.map(i => i.json)).slice(0, 100);\nreturn [{ json: { topic, lookbackDays, reviews: out } }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        656,
        0
      ],
      "id": "76e79a93-0876-48da-b9f6-beed32a71327",
      "name": "Filter Reviews"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "f7a54644-d1c8-49ab-8d36-a877830ca83c",
        "options": {
          "noResponseBody": true
        }
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        -240,
        208
      ],
      "id": "fb9d0148-d7ed-40a8-9dc5-13cf1e9668ab",
      "name": "Slack Webhook",
      "webhookId": "f7a54644-d1c8-49ab-8d36-a877830ca83c"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $json.responseUrl }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "{\n  \"response_type\": \"ephemeral\",\n  \"text\": \"Working on it…\"\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        224,
        0
      ],
      "id": "63be5e27-70d7-4495-b267-456fc9351d94",
      "name": "Ack to Slack"
    },
    {
      "parameters": {
        "jsCode": "const resp = $items('Parse Slash Params')[0].json || {};\nconst { reviews = [], topic, lookbackDays } = $json;\nconst compact = reviews.slice(0, 60).map(r => ({\n  date: r.date, stars: r.rating, title: r.title || '',\n  text: (r.text || '').slice(0, 400), url: r.url || ''\n}));\nreturn [{ json: { responseUrl: resp.responseUrl, channelId: resp.channelId, topic, lookbackDays, reviews: compact } }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -16,
        272
      ],
      "id": "578e735f-c867-4326-a6a1-6f3843e5f834",
      "name": "Prep for LLM"
    },
    {
      "parameters": {
        "jsonSchemaExample": "{\n  \"phrases\": [\n    { \"text\": \"finally sleeves that reach my wrists\", \"label\": \"length\" }\n  ],\n  \"headlines\": [\n    \"Jeans that actually reach your ankles\",\n    \"Finally: long inseams that fit\"\n  ]\n}",
        "autoFix": true
      },
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "typeVersion": 1.3,
      "position": [
        208,
        464
      ],
      "id": "cbf56487-91ee-4613-95ea-0bb0db4eac93",
      "name": "Structured Output Parser"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=Topic: {{ $json.topic }}\nWindow (days): {{ $json.lookbackDays }}\n\nReviews (JSON):\n{{ JSON.stringify($json.reviews) }}",
        "hasOutputParser": true,
        "messages": {
          "messageValues": [
            {
              "message": "You analyze apparel reviews for a given search topic and return JSON ONLY matching the provided schema (no prose).\nTASKS\n1) Extract up to 20 short, verbatim phrases customers actually use (no rewriting). Label each: fit, length, comfort, quality, confidence, price, durability.\n2) Write 10 paid-social headlines (4–10 words) using only those phrases."
            }
          ]
        },
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.7,
      "position": [
        176,
        288
      ],
      "id": "be3bbada-6867-4fb8-8e1e-56f460d4f11b",
      "name": "LLM: Phrases + Headlines"
    },
    {
      "parameters": {
        "jsCode": "const out = $json.output || {};\nconst phrases = Array.isArray(out.phrases) ? out.phrases.slice(0, 10) : [];\nconst headlines = Array.isArray(out.headlines) ? out.headlines.slice(0, 10) : [];\nconst ctx = ($items('Prep for LLM')[0]?.json) || {};\nconst { responseUrl, topic, lookbackDays } = ctx;\nconst phraseLines = phrases.map(p => \"• \" + p.text + \"  _(\" + p.label + \")_\").join('\\n');\nconst headlineLines = headlines.map((h, i) => (i + 1) + \". \" + h).join('\\n');\nconst blocks = [\n  { type: \"header\", text: { type: \"plain_text\", text: \"Review Mining: \" + (topic || '—') } },\n  { type: \"section\", text: { type: \"mrkdwn\", text: \"*Source:* Google Sheet  ·  *Window:* past \" + (lookbackDays || 365) + \" days\\n*Results:* \" + headlines.length + \" headlines\" } },\n  { type: \"divider\" },\n  { type: \"section\", text: { type: \"mrkdwn\", text: \"*Top customer phrases*\\n\" + phraseLines } },\n  { type: \"divider\" },\n  { type: \"section\", text: { type: \"mrkdwn\", text: \"*10 Headline Ideas*\\n\" + headlineLines } }\n];\nreturn [{ json: { responseUrl, blocks } }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        496,
        288
      ],
      "id": "963c97c7-2e57-4675-b015-0fa1726803c8",
      "name": "Build Slack Blocks"
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "={{ $items('Parse Slash Params')[0].json.channelId }}",
          "mode": "id"
        },
        "messageType": "block",
        "blocksUi": "={{ { text: 'Review Mining results', blocks: $json.blocks } }}",
        "text": "Review Mining results",
        "otherOptions": {}
      },
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.3,
      "position": [
        672,
        272
      ],
      "id": "5e678854-7c13-4939-ad88-60690c0e8198",
      "name": "Send a message",
      "webhookId": "213b13f6-45aa-4dfb-a7ae-4f4e9e6fb1f5",
      "credentials": {
        "slackApi": {
          "id": "WnKmj8nHtDHIxLF7",
          "name": "Slack account dev"
        }
      }
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini"
        },
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.2,
      "position": [
        -128,
        576
      ],
      "id": "f343f88c-03fc-4a0c-845b-a896b7554cdf",
      "name": "OpenAI Chat Model",
      "credentials": {
        "openAiApi": {
          "id": "vzAipRmXoEwtFWxi",
          "name": "OpenAi account - n8n demo 2"
        }
      }
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini"
        },
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.2,
      "position": [
        112,
        672
      ],
      "id": "e8fd08c1-e4f3-4325-931c-638c3a179662",
      "name": "OpenAI Chat Model1",
      "credentials": {
        "openAiApi": {
          "id": "vzAipRmXoEwtFWxi",
          "name": "OpenAi account - n8n demo 2"
        }
      }
    }
  ],
  "pinData": {},
  "connections": {
    "Parse Slash Params": {
      "main": [
        [
          {
            "node": "Ack to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get row(s) in sheet": {
      "main": [
        [
          {
            "node": "Filter Reviews",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack Webhook": {
      "main": [
        [
          {
            "node": "Parse Slash Params",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Ack to Slack": {
      "main": [
        [
          {
            "node": "Get row(s) in sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Reviews": {
      "main": [
        [
          {
            "node": "Prep for LLM",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prep for LLM": {
      "main": [
        [
          {
            "node": "LLM: Phrases + Headlines",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "LLM: Phrases + Headlines",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "LLM: Phrases + Headlines": {
      "main": [
        [
          {
            "node": "Build Slack Blocks",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Slack Blocks": {
      "main": [
        [
          {
            "node": "Send a message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "LLM: Phrases + Headlines",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "Structured Output Parser",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "a03d5aca-8b96-414c-bdae-708922f0015e",
  "meta": {
    "templateCredsSetupCompleted": true,
    "instanceId": "12503e15ecf13227b3ba751bc7b2fcdaf2d55ae6cdf7295a1c0184e3b8c65b95"
  },
  "id": "c8KtHsI7hYsChEeb",
  "tags": []
}