AutomationFlowsAI & RAG › Monitor & Respond to Google Maps Reviews Using Ai, Apify, Slack, and Sheets

Monitor & Respond to Google Maps Reviews Using Ai, Apify, Slack, and Sheets

Bytakuma @takuma on n8n.io

This workflow automates reputation management for physical stores (restaurants, retail, clinics) by monitoring Google Maps reviews, analyzing them with AI, and drafting professional replies.

Cron / scheduled trigger★★★★☆ complexityAI-powered15 nodesGoogle SheetsSlack@Apify/N8N Nodes ApifyAgentOpenRouter Chat
AI & RAG Trigger: Cron / scheduled Nodes: 15 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #11053 — we link there as the canonical source.

This workflow follows the Agent → 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 →

Download .json
{
  "id": "5yXquF2kybZBhbRV",
  "name": "Monitor Google Maps reviews from Apify to Slack and Google Sheets",
  "tags": [],
  "nodes": [
    {
      "id": "f2753220-ab01-4a39-86c6-d9e7f4de32a0",
      "name": "Every 24 Hours",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -496,
        48
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours"
            }
          ]
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "55818ecf-0a34-4a9f-bc6c-c399879c5f58",
      "name": "CONFIG (Edit Here)",
      "type": "n8n-nodes-base.set",
      "notes": "Settings: Enter your Store URL and Sheet ID here",
      "position": [
        -272,
        48
      ],
      "parameters": {
        "values": {
          "string": [
            {
              "name": "MAPS_URL",
              "value": "https://www.google.com/maps/place/YOUR_STORE_ID"
            },
            {
              "name": "SHOP_NAME",
              "value": "My Store Name"
            },
            {
              "name": "MANAGER_NAME",
              "value": "Manager"
            },
            {
              "name": "SHEET_ID",
              "value": "YOUR_GOOGLE_SHEET_ID"
            },
            {
              "name": "SHEET_NAME",
              "value": "Reviews"
            }
          ]
        },
        "options": {
          "dotNotation": true
        }
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "b40cd37c-e43c-4a81-9e2f-a9208ed41d23",
      "name": "Get Existing IDs",
      "type": "n8n-nodes-base.googleSheets",
      "notes": "For duplicate check",
      "position": [
        -48,
        144
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "",
          "cachedResultName": "Reviews"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.SHEET_ID }}"
        }
      },
      "notesInFlow": true,
      "typeVersion": 4.1
    },
    {
      "id": "19b27e60-9c7f-4c27-ab7e-09945d8e5725",
      "name": "Save to Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        976,
        48
      ],
      "parameters": {
        "columns": {
          "value": {
            "text": "={{ $json.text }}",
            "stars": "={{ $json.stars }}",
            "output": "={{ $json.output }}",
            "ai_reply": "={{ $json.ai_reply }}",
            "reviewId": "={{ $json.reviewerId }}",
            "reviewUrl": "={{ $json.reviewerUrl }}",
            "ai_summary": "={{ $json.ai_summary }}",
            "publishedAt": "={{ $json.publishAt }}",
            "reviewerName": "={{ $json.name }}",
            "publishedAt date": "={{ $json.publishedAtDate }}"
          },
          "schema": [
            {
              "id": "publishedAt date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "publishedAt date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "reviewId",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "reviewId",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "publishedAt",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "publishedAt",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "reviewerName",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "reviewerName",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "stars",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "stars",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "text",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "text",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "ai_summary",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "ai_summary",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "ai_reply",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "ai_reply",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "reviewUrl",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "reviewUrl",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "output",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "output",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "",
          "cachedResultName": "Reviews"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('CONFIG (Edit Here)').item.json.SHEET_ID }}"
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "48614959-cb01-4602-8c75-54366dfbd987",
      "name": "If Rating < 4",
      "type": "n8n-nodes-base.if",
      "position": [
        1200,
        48
      ],
      "parameters": {
        "conditions": {
          "number": [
            {
              "value1": "={{ $json.reviewId }}",
              "value2": 4
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "f104e08a-2bd0-4445-984b-2be8a4df0ff6",
      "name": "Slack (Alert)",
      "type": "n8n-nodes-base.slack",
      "position": [
        1424,
        -48
      ],
      "parameters": {
        "text": "\ud83d\udea8 Negative review detected",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_CHANNEL_ID",
          "cachedResultName": "negative"
        },
        "otherOptions": {
          "includeLinkToWorkflow": true
        },
        "authentication": "oAuth2"
      },
      "typeVersion": 2.1
    },
    {
      "id": "7abc738b-c7c2-405b-b2a3-e2b9e17c4a4c",
      "name": "Run an Actor and get dataset",
      "type": "@apify/n8n-nodes-apify.apify",
      "position": [
        -48,
        -48
      ],
      "parameters": {
        "actorId": {
          "__rl": true,
          "mode": "list",
          "value": "Xb8osYTtOjlsgI6k9",
          "cachedResultUrl": "https://console.apify.com/actors/Xb8osYTtOjlsgI6k9/input",
          "cachedResultName": "Google Maps Reviews Scraper (compass/Google-Maps-Reviews-Scraper)"
        },
        "operation": "Run actor and get dataset",
        "customBody": "={\n  \"startUrls\": [\n    {\n      \"url\": \"{{ $('CONFIG (Edit Here)').item.json.MAPS_URL }}\"\n    }\n  ],\n  \"maxReviews\": 10,\n  \"language\": \"en\",\n  \"reviewsSort\": \"newest\"\n}",
        "actorSource": "store"
      },
      "typeVersion": 1
    },
    {
      "id": "3bd96b91-da52-490c-921f-1edba358ea5c",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        416,
        48
      ],
      "parameters": {
        "text": "=Review Text: {{ $json.text }}\nStars: {{ $json.stars }}\nReviewer Name: {{ $json.reviewerName }}",
        "options": {
          "systemMessage": "You are an excellent customer support manager for a physical store.\nBased on the \"Google Maps Review\" and \"Star Rating (1-5)\" provided by the user, create the following two items:\n\n### 1. Summary (For Slack Notification)\nSummarize the main point of the review in under 30 characters so the store manager can grasp it immediately via notification.\n\n### 2. Reply Draft (For Spreadsheet)\nCreate an appropriate reply message from the store.\nStrictly follow these rules:\n- 4-5 Stars: Thank them for the high rating and warmly say you look forward to their next visit.\n- 1-3 Stars: Sincerely apologize for the inconvenience, thank them for the valuable feedback, and express a polite attitude towards improvement.\n- Tone: Polite (formal) but sincere and warm.\n- No signature needed.\n\n### Output Format\nDo not include any preamble or greetings. Output only the following format:\n\n[Summary]\n(Summary text here)\n\n[Reply Draft]\n(Reply draft here)"
        },
        "promptType": "define"
      },
      "typeVersion": 3
    },
    {
      "id": "a268a424-af7a-43c8-b646-628bfe03d152",
      "name": "OpenRouter Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        464,
        272
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "7a6610c6-cdb9-4de1-af03-dd5c08b3df18",
      "name": "Filter Duplicates",
      "type": "n8n-nodes-base.merge",
      "notes": "Pass only new reviews",
      "position": [
        176,
        48
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "joinMode": "keepNonMatches",
        "mergeByFields": {
          "values": [
            {
              "field1": "reviewerId",
              "field2": "reviewId"
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 2.1
    },
    {
      "id": "3b954670-8d94-4db0-b637-16bf447fdb4a",
      "name": "Slack (Alert)1",
      "type": "n8n-nodes-base.slack",
      "position": [
        1424,
        144
      ],
      "parameters": {
        "text": "\ud83d\udea8 Positive review received!",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_CHANNEL_ID",
          "cachedResultName": "positive"
        },
        "otherOptions": {
          "includeLinkToWorkflow": true
        },
        "authentication": "oAuth2"
      },
      "typeVersion": 2.1
    },
    {
      "id": "d481159e-c7fd-40f0-9695-aecdb3068015",
      "name": "Code in JavaScript",
      "type": "n8n-nodes-base.code",
      "position": [
        752,
        48
      ],
      "parameters": {
        "jsCode": "// Get all original data from the 'Filter Duplicates' node\nconst originalItems = $('Filter Duplicates').all();\n\n// Get all results from the 'AI Agent' node\nconst aiItems = $input.all();\n\n// Combine data in order and return\nreturn aiItems.map((item, index) => {\n  const aiText = item.json.output || item.json.text || \"\";\n\n  // Split the AI text into \"Summary\" and \"Reply Draft\" based on the English markers\n  const summaryMatch = aiText.match(/\\[Summary\\]\\s*([\\s\\S]*?)\\s*(?=\\[Reply Draft\\]|$)/);\n  const replyMatch = aiText.match(/\\[Reply Draft\\]\\s*([\\s\\S]*)/);\n\n  const summary = summaryMatch ? summaryMatch[1].trim() : \"\";\n  const reply = replyMatch ? replyMatch[1].trim() : \"\";\n\n  // Retrieve original data based on index\n  // Assuming AI processing order matches the original data order\n  const originalData = originalItems[index] ? originalItems[index].json : {};\n\n  return {\n    json: {\n      ...originalData,      // Inherit reviewId, stars, text, etc.\n      ai_summary: summary,  // Split summary\n      ai_reply: reply,      // Split reply draft\n      output: aiText        // Full AI output\n    }\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "9a9ca427-4026-4661-916d-9e4b0aa10195",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1168,
        -192
      ],
      "parameters": {
        "width": 512,
        "height": 624,
        "content": "## How it works\n1. **Schedule:** Runs every 24 hours (customizable) to fetch the latest data.\n2. **Scrape:** Uses **Apify** to retrieve the latest reviews from a specific Google Maps URL.\n3. **Filter:** Checks the **Google Sheet** database to identify only new reviews and avoid duplicates.\n4. **AI Analysis:** An **AI Agent** (via OpenRouter/OpenAI) analyzes the review text to:\n   - Generate a short summary.\n   - Draft a polite, context-aware reply based on the star rating (e.g., apologies for low stars, gratitude for high stars).\n5. **Alert:** Sends a **Slack** notification.\n   - **Low Rating (&lt;4 stars):** Alerts a specific channel (e.g., #customer-support) with a warning.\n   - **High Rating:** Alerts a general channel (e.g., #wins) to celebrate.\n6. **Save:** Appends the review details, AI summary, and draft reply to the Google Sheet.\n\n## Requirements\n- **n8n:** Cloud or self-hosted (v1.0+).\n- **Apify Account:** To run the *Google Maps Reviews Scraper*.\n- **Google Cloud Platform:** Enabled Google Sheets API.\n- **Slack Workspace:** A webhook URL or OAuth connection.\n- **OpenRouter (or OpenAI) API Key:** For the LLM generation.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "5bebe09f-3c19-4a4c-98cc-0ba8593b72eb",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -464,
        -272
      ],
      "parameters": {
        "color": 7,
        "width": 1952,
        "height": 592,
        "content": "## How to set up\n1. **Google Sheets:** Create a new sheet with the following headers in the first row:\n   `reviewId`, `publishedAt`, `reviewerName`, `stars`, `text`, `ai_summary`, `ai_reply`, `reviewUrl`, `output`, `publishedAt date`.\n2. **Configure Credentials:** Set up your accounts for Google Sheets, Apify, Slack, and OpenRouter within n8n.\n3. **Edit the \"CONFIG\" Node:**\n   - `MAPS_URL`: Paste the full Google Maps link to your store.\n   - `SHEET_ID`: Paste the ID found in your Google Sheet URL.\n   - `SHOP_NAME`: Your store's name.\n4. **Slack Nodes:** Select the appropriate channels for positive and negative alerts."
      },
      "typeVersion": 1
    },
    {
      "id": "ce00761e-fd4f-4cb4-8743-c6d8ba6c488a",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        800,
        416
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 208,
        "content": "## How to customize\n- **Change the AI Persona:** Open the **AI Agent** node and modify the \"System Message\" to match your brand's tone of voice (e.g., casual, formal, or witty).\n- **Adjust Alert Thresholds:** Edit the **If Rating &lt; 4** node to change the criteria for what constitutes a \"negative\" review (e.g., strictly &lt; 3 stars).\n- **Multi-Store Support:** You can loop this workflow over a list of URLs to manage multiple locations in a single execution."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "ec0852e5-41e9-4ed5-995e-cda9b88ad7cc",
  "connections": {
    "AI Agent": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Rating < 4": {
      "main": [
        [
          {
            "node": "Slack (Alert)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Slack (Alert)1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Every 24 Hours": {
      "main": [
        [
          {
            "node": "CONFIG (Edit Here)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Existing IDs": {
      "main": [
        [
          {
            "node": "Filter Duplicates",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Filter Duplicates": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CONFIG (Edit Here)": {
      "main": [
        [
          {
            "node": "Get Existing IDs",
            "type": "main",
            "index": 0
          },
          {
            "node": "Run an Actor and get dataset",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "Save to Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Save to Google Sheets": {
      "main": [
        [
          {
            "node": "If Rating < 4",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Run an Actor and get dataset": {
      "main": [
        [
          {
            "node": "Filter Duplicates",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow automates reputation management for physical stores (restaurants, retail, clinics) by monitoring Google Maps reviews, analyzing them with AI, and drafting professional replies.

Source: https://n8n.io/workflows/11053/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

This template is designed for B2B sales teams, recruiters, and business development professionals who want to identify sales opportunities by monitoring hiring signals from target companies. It's part

@Apify/N8N Nodes Apify, Google Sheets, Agent +4
AI & RAG

This workflow automates the discovery of new B2B service providers entering the market. It scrapes a specific category on Clutch.co weekly, standardizes the data using AI, and compares it against a hi

Output Parser Structured, OpenRouter Chat, Google Sheets +3
AI & RAG

Who’s it for This template is ideal for busy professionals, students, or anyone with a dynamic schedule who wants to optimize their brief periods of free time. If you frequently find yourself with une

Google Calendar, HTTP Request, Google Sheets +3
AI & RAG

This workflow automates competitive intelligence by continuously monitoring competitor websites for pricing and feature updates. It scrapes current data using BrowserAct, compares it against historica

Google Sheets, N8N Nodes Browseract, Agent +3
AI & RAG

This workflow automates Generative Engine Optimization (GEO) tracking by monitoring how your company appears in AI search results. It generates strategic queries, simulates searches on AI engines like

OpenRouter Chat, Output Parser Structured, Google Sheets +3