AutomationFlowsAI & RAG › Monitor Restaurant Ratings with Google Places, Gemini, Sheets, and Slack

Monitor Restaurant Ratings with Google Places, Gemini, Sheets, and Slack

ByDivyanshu Gupta @divyanshugupta on n8n.io

Automatically monitors restaurant ratings on Google Places daily, detects meaningful changes, uses Google Gemini AI to diagnose the root cause from real customer reviews, and delivers smart alerts to Slack — categorised as 🔴 Critical, 🟡 Watch, or 🟢 Positive.

Cron / scheduled trigger★★★★☆ complexityAI-powered19 nodesGoogle SheetsHTTP RequestGoogle GeminiSlack
AI & RAG Trigger: Cron / scheduled Nodes: 19 Complexity: ★★★★☆ AI nodes: yes Added:
Monitor Restaurant Ratings with Google Places, Gemini, Sheets, and Slack — n8n workflow card showing Google Sheets, HTTP Request, Google Gemini integration

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

This workflow follows the Googlegemini → 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": "T1J07hjfad1AYn81",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "RestaurantPulse \u2014 AI Restaurant Reputation Monitor",
  "tags": [
    {
      "id": "2MHdF7UD7XlXdEF3",
      "name": "slack",
      "createdAt": "2026-05-06T18:59:28.213Z",
      "updatedAt": "2026-05-06T18:59:28.213Z"
    },
    {
      "id": "Gfj8y1ILfs3t0Xbi",
      "name": "ai",
      "createdAt": "2026-05-06T18:59:28.190Z",
      "updatedAt": "2026-05-06T18:59:28.190Z"
    },
    {
      "id": "LoSxvmWgyZKSWDDa",
      "name": "gemini",
      "createdAt": "2026-05-06T18:59:28.232Z",
      "updatedAt": "2026-05-06T18:59:28.232Z"
    },
    {
      "id": "O5FroArGOpuzRH2A",
      "name": "reputation-monitoring",
      "createdAt": "2026-05-06T18:59:28.138Z",
      "updatedAt": "2026-05-06T18:59:28.138Z"
    },
    {
      "id": "ay4Ha4bae1Y04xa6",
      "name": "google-places",
      "createdAt": "2026-05-06T18:59:28.168Z",
      "updatedAt": "2026-05-06T18:59:28.168Z"
    },
    {
      "id": "yLLL2nboe7re4Rij",
      "name": "restaurant",
      "createdAt": "2026-05-06T18:59:28.106Z",
      "updatedAt": "2026-05-06T18:59:28.106Z"
    }
  ],
  "nodes": [
    {
      "id": "555ee298-ad02-4206-ad7a-9f57fc5a404e",
      "name": "\ud83d\udccb Workflow Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        944,
        848
      ],
      "parameters": {
        "color": 7,
        "width": 580,
        "height": 1108,
        "content": "# \ud83c\udf55 RestaurantPulse \u2014 AI Restaurant Reputation Monitor\n\n## What this workflow does\nAutomatically monitors restaurant ratings on **Google Places** daily, detects meaningful changes, uses **Google Gemini AI** to diagnose the root cause from real customer reviews, and delivers smart alerts to **Slack** \u2014 categorised as \ud83d\udd34 Critical, \ud83d\udfe1 Watch, or \ud83d\udfe2 Positive.\n\n## Why it's unique\nMost monitoring tools just tell you *that* a rating changed. RestaurantPulse tells you *why* \u2014 by reading actual customer reviews through AI and suggesting one concrete action to fix it.\n\n## How it works\n1. Reads restaurant list from Google Sheets (add any restaurant via place_id)\n2. Fetches live rating + reviews from Google Places API\n3. Compares against last known state stored in Google Sheets\n4. AI diagnoses root cause if change detected\n5. Routes alert to Slack by severity level\n6. Logs all alerts to Google Sheets for history\n\n## Prerequisites\n- Google Places API key (console.cloud.google.com)\n- Google Sheets OAuth2 credentials\n- Google Gemini API key\n- Slack OAuth2 credentials\n\n## Google Sheets Setup\nCreate a spreadsheet with two sheets:\n\n**Sheet 1 \u2014 restaurant_list**\nColumns: place_id | name | last_rating | last_review_count | last_checked\n\n**Sheet 2 \u2014 alert_history**\nColumns: timestamp | restaurant_name | old_rating | new_rating | rating_diff | alert_level | ai_diagnosis | place_id\n\n## How to find place_id\nCall this URL in your browser:\nhttps://maps.googleapis.com/maps/api/place/findplacefromtext/json?input=RESTAURANT+NAME+CITY&inputtype=textquery&fields=place_id,name&key=YOUR_KEY\n\n## Alert Levels\n\ud83d\udd34 Critical \u2014 rating dropped 0.3+ points\n\ud83d\udfe1 Watch \u2014 rating dropped 0.1+ points OR 50+ new reviews\n\ud83d\udfe2 Positive \u2014 rating improved 0.2+ points"
      },
      "typeVersion": 1
    },
    {
      "id": "adcad375-639c-4983-a784-63dc6a4df3fb",
      "name": "\ud83d\udce5 Phase 1 Label",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1680,
        1024
      ],
      "parameters": {
        "color": 4,
        "width": 820,
        "height": 476,
        "content": "## \ud83d\udce5 PHASE 1 \u2014 Data Ingestion"
      },
      "typeVersion": 1
    },
    {
      "id": "87aeba8f-f5f6-467e-93bd-44ecc06279a7",
      "name": "\ud83e\udde0 Phase 2 Label",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2544,
        1024
      ],
      "parameters": {
        "color": 3,
        "width": 380,
        "height": 436,
        "content": "## \ud83e\udde0 PHASE 2 \u2014 Intelligence Engine\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "93c4a9ad-0ecb-46f0-b91f-a8062cbd94a2",
      "name": "\ud83e\udd16 Phase 3 Label",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2976,
        992
      ],
      "parameters": {
        "color": 5,
        "width": 556,
        "height": 492,
        "content": "## \ud83e\udd16 PHASE 3 \u2014 AI Diagnosis\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "0c2d587e-78f1-467a-beb2-cf7e1dd7be15",
      "name": "\ud83d\udce3 Phase 4 Label",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4128,
        1008
      ],
      "parameters": {
        "color": 6,
        "width": 580,
        "height": 204,
        "content": "## \ud83d\udce3 PHASE 4 \u2014 Alert Delivery\n\n**Alert Routing (Switch)** routes to the correct Slack message format based on severity\n\n**Update State** writes today's rating back to Google Sheets so next run can detect future changes\n\n**Alert History** appends every alert with AI diagnosis to the `alert_history` sheet \u2014 building a historical dataset for trend analysis"
      },
      "typeVersion": 1
    },
    {
      "id": "890d5ab4-d644-44a4-84ee-10becda50a6f",
      "name": "\ud83d\udcca Read Restaurant List",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1936,
        1168
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1474149389,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1RseFGAH4RcvX1z6BFiDaSgKH0EVE5HgOCfr09V4R6wU/edit#gid=1474149389",
          "cachedResultName": "restaurant_list"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1RseFGAH4RcvX1z6BFiDaSgKH0EVE5HgOCfr09V4R6wU",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1RseFGAH4RcvX1z6BFiDaSgKH0EVE5HgOCfr09V4R6wU/edit?usp=drivesdk",
          "cachedResultName": "restaurant_list"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "5496286a-da27-4782-b9ab-15fa9a909363",
      "name": "\ud83d\udd04 Loop Over Restaurants",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        2144,
        1168
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "44cc727e-271a-4fec-a90e-9e408779cee7",
      "name": "\ud83c\udf10 Fetch Live Data (Google Places API)",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2368,
        1152
      ],
      "parameters": {
        "url": "https://maps.googleapis.com/maps/api/place/details/json",
        "options": {},
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "place_id",
              "value": "={{ $json.place_id }}"
            },
            {
              "name": "fields",
              "value": "name,rating,user_ratings_total,opening_hours,price_level,formatted_address,reviews"
            },
            {
              "name": "key",
              "value": "AIzaYOUR_GOOGLE_API_KEY_HERE"
            },
            {
              "name": "language",
              "value": "en"
            }
          ]
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "f13aed48-86dc-461d-b376-eb8c917987dc",
      "name": "\ud83e\udde0 Change Detection Engine",
      "type": "n8n-nodes-base.code",
      "position": [
        2592,
        1168
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\nconst results = [];\n\nfor (const item of items) {\n  const data = item.json;\n  \n  // Skip non-result items (html_attributions etc)\n  if (!data.result) continue;\n  \n  const live = data.result;\n  \n  // Find matching restaurant from loop node\n  const loop = $('\ud83d\udd04 Loop Over Restaurants').all().find(i => \n    i.json.place_id === data.result.place_id || \n    i.json.name === data.result.name\n  );\n  \n  if (!loop) continue;\n  \n  const stored = loop.json;\n  const r = parseFloat(stored.last_rating) || 4.0;\n  const rc = parseInt(stored.last_review_count) || 0;\n  const rd = parseFloat((live.rating - r).toFixed(2));\n  const rvd = live.user_ratings_total - rc;\n  \n  // Determine alert level\n  let al = 'none';\n  if (rd <= -0.3) al = 'critical';\n  else if (rd <= -0.1 || rvd > 50) al = 'watch';\n  else if (rd >= 0.2) al = 'positive';\n  \n  // Extract review text for AI\n  const rv = (live.reviews || []).map(x => x.rating + 'star ' + x.text).join(' | ');\n  \n  results.push({\n    json: {\n      place_id: stored.place_id,\n      name: live.name,\n      result: live,\n      last_rating: r,\n      last_review_count: rc,\n      ratingDiff: rd,\n      reviewDiff: rvd,\n      alertLevel: al,\n      reviewsText: rv,\n      checkedAt: new Date().toISOString()\n    }\n  });\n}\n\nreturn results;"
      },
      "typeVersion": 2
    },
    {
      "id": "44683c99-bab1-436f-b241-9bfa2716bb83",
      "name": "\ud83d\udea6 Alert Worthy? (IF)",
      "type": "n8n-nodes-base.if",
      "position": [
        2800,
        1168
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "ae53ac22-ee23-448f-a348-a14ccceba4a8",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.alertLevel }}",
              "rightValue": "none"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "aefed324-5e9e-46c5-a316-28479e80ecf3",
      "name": "\ud83e\udd16 AI Diagnosis (Google Gemini)",
      "type": "@n8n/n8n-nodes-langchain.googleGemini",
      "position": [
        3008,
        1072
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "models/gemini-2.5-flash",
          "cachedResultName": "models/gemini-2.5-flash"
        },
        "options": {
          "temperature": 0.3,
          "systemMessage": "You are an expert restaurant reputation analyst with 10 years of experience. When given rating changes and customer reviews, you: 1. Identify the ROOT CAUSE of the change (not just describe it) 2. Quantify the issue where possible (e.g. '4 of 5 reviews mention cold food') 3. Suggest ONE specific, actionable fix. Be concise, direct, and data-driven. Maximum 3 sentences."
        },
        "messages": {
          "values": [
            {
              "content": "=={{ \n'Restaurant: ' + $json.name + \n'\\nAddress: ' + $json.result.formatted_address +\n'\\nRating change: ' + $json.last_rating + ' \u2192 ' + $json.result.rating + \n' (' + ($json.ratingDiff > 0 ? '+' : '') + $json.ratingDiff + ' points)' +\n'\\nNew reviews since last check: ' + $json.reviewDiff +\n'\\nAlert level: ' + $json.alertLevel.toUpperCase() +\n'\\n\\nRecent customer reviews:\\n' + $json.reviewsText +\n'\\n\\nDiagnose the root cause and suggest one action.'\n}}"
            }
          ]
        },
        "builtInTools": {}
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1.1
    },
    {
      "id": "4fdba883-7039-4cee-b281-97690de77b1f",
      "name": "\ud83d\udd00 Merge AI + Restaurant Data",
      "type": "n8n-nodes-base.merge",
      "position": [
        3392,
        1280
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "338fef24-efb9-4476-8cfd-33b3f95b3dcc",
      "name": "\ud83d\udce1 Alert Routing (Switch)",
      "type": "n8n-nodes-base.switch",
      "position": [
        3632,
        1264
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "critical",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "dfd1c637-608d-49e3-91b3-07924cc1024b",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('\ud83d\udea6 Alert Worthy? (IF)').item.json.alertLevel }}",
                    "rightValue": "critical"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "watch",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "f0a8cfe1-96aa-47e3-a85e-9ee979cad554",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('\ud83d\udea6 Alert Worthy? (IF)').item.json.alertLevel }}",
                    "rightValue": "watch"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "positive",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "85e32343-222f-4b2a-ad1f-1db75715cdcb",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('\ud83d\udea6 Alert Worthy? (IF)').item.json.alertLevel }}",
                    "rightValue": "positive"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {
          "fallbackOutput": "none",
          "allMatchingOutputs": false
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "2dc5af1d-ddb2-4d8f-a689-280a71356b86",
      "name": "\ud83d\udd34 Critical Alert (Slack)",
      "type": "n8n-nodes-base.slack",
      "position": [
        3872,
        1072
      ],
      "parameters": {
        "text": "={{ '\ud83d\udd34 *CRITICAL ALERT \u2014 ' + $json.name + '*\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\\n\ud83d\udcc9 Rating: *' + $json.last_rating + '* \u2192 *' + $json.result.rating + '* (' + $json.ratingDiff + ' points)\\n\ud83d\udcac New reviews: +' + $json.reviewDiff + '\\n\ud83d\udccd ' + $json.result.formatted_address + '\\n\\n*\ud83e\udd16 AI Diagnosis:*\\n' + $json.content.parts[0].text }}",
        "user": {
          "__rl": true,
          "mode": "list",
          "value": "U0AS8B0F3S4",
          "cachedResultName": "guptadivyanshu765"
        },
        "select": "user",
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "2fa1ff20-f4ed-4a3e-b5d7-eee16dcdbddb",
      "name": "\ud83d\udfe1 Watch Alert (Slack)",
      "type": "n8n-nodes-base.slack",
      "position": [
        3872,
        1264
      ],
      "parameters": {
        "text": "={{ '\ud83d\udfe1 *WATCH \u2014 ' + $json.name + '*\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\\n\ud83d\udcca Rating: *' + $json.last_rating + '* \u2192 *' + $json.result.rating + '* (' + $json.ratingDiff + ' points)\\n\ud83d\udcac Unusual activity: +' + $json.reviewDiff + ' new reviews\\n\ud83d\udccd ' + $json.result.formatted_address + '\\n\\n*\ud83e\udd16 AI Diagnosis:*\\n' + $json.content.parts[0].text }}",
        "user": {
          "__rl": true,
          "mode": "list",
          "value": "U0AS8B0F3S4",
          "cachedResultName": "guptadivyanshu765"
        },
        "select": "user",
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "18efd361-c499-4ebb-b749-a90127dd10aa",
      "name": "\ud83d\udfe2 Positive Alert (Slack)",
      "type": "n8n-nodes-base.slack",
      "position": [
        3872,
        1472
      ],
      "parameters": {
        "text": "={{ '\ud83d\udfe2 *POSITIVE \u2014 ' + $json.name + '*\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\\n\ud83d\udcc8 Rating improved: *' + $json.last_rating + '* \u2192 *' + $json.result.rating + '* (+' + $json.ratingDiff + ' points)\\n\ud83d\udcac New reviews: +' + $json.reviewDiff + '\\n\ud83d\udccd ' + $json.result.formatted_address + '\\n\\n*\ud83e\udd16 AI Insight:*\\n' + $json.content.parts[0].text }}",
        "user": {
          "__rl": true,
          "mode": "list",
          "value": "U0AS8B0F3S4",
          "cachedResultName": "guptadivyanshu765"
        },
        "select": "user",
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "441fe08f-a9f5-4cac-b24f-92667690c9f2",
      "name": "\ud83d\udcbe Update State (Google Sheets)",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        4240,
        1264
      ],
      "parameters": {
        "columns": {
          "value": {
            "name": "={{ $('\ud83d\udce1 Alert Routing (Switch)').item.json.name }}",
            "place_id": "={{ $('\ud83d\udce1 Alert Routing (Switch)').item.json.place_id }}",
            "last_rating": "={{ $('\ud83d\udce1 Alert Routing (Switch)').item.json.last_rating }}",
            "last_checked": "={{ $('\ud83d\udce1 Alert Routing (Switch)').item.json.checkedAt }}",
            "last_review_count": "={{ $('\ud83d\udce1 Alert Routing (Switch)').item.json.last_review_count }}"
          },
          "schema": [
            {
              "id": "place_id",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "place_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "last_rating",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "last_rating",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "last_review_count",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "last_review_count",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "last_checked",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "last_checked",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "place_id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1474149389,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1RseFGAH4RcvX1z6BFiDaSgKH0EVE5HgOCfr09V4R6wU/edit#gid=1474149389",
          "cachedResultName": "restaurant_list"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1RseFGAH4RcvX1z6BFiDaSgKH0EVE5HgOCfr09V4R6wU",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1RseFGAH4RcvX1z6BFiDaSgKH0EVE5HgOCfr09V4R6wU/edit?usp=drivesdk",
          "cachedResultName": "restaurant_list"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "6f2157c5-5291-4abf-b7bf-dfdacb13632e",
      "name": "\ud83d\udcdc Log Alert History (Google Sheets)",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        4480,
        1264
      ],
      "parameters": {
        "columns": {
          "value": {
            "name": "={{ $json.name }}",
            "place_id": "={{ $json.place_id }}",
            "last_rating": "={{ $json.last_rating }}",
            "last_checked": "={{ $json.last_checked }}",
            "last_review_count": "={{ $json.last_review_count }}"
          },
          "schema": [
            {
              "id": "place_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "place_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "last_rating",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "last_rating",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "last_review_count",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "last_review_count",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "last_checked",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "last_checked",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1474149389,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1RseFGAH4RcvX1z6BFiDaSgKH0EVE5HgOCfr09V4R6wU/edit#gid=1474149389",
          "cachedResultName": "restaurant_list"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1RseFGAH4RcvX1z6BFiDaSgKH0EVE5HgOCfr09V4R6wU",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1RseFGAH4RcvX1z6BFiDaSgKH0EVE5HgOCfr09V4R6wU/edit?usp=drivesdk",
          "cachedResultName": "restaurant_list"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "8acf9ad3-5ec3-4182-b145-5f9e8fef4240",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        1728,
        1168
      ],
      "parameters": {
        "rule": {
          "interval": [
            {}
          ]
        }
      },
      "typeVersion": 1.3
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "258361ba-31c5-4662-9007-db12ed642235",
  "connections": {
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "\ud83d\udcca Read Restaurant List",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udea6 Alert Worthy? (IF)": {
      "main": [
        [
          {
            "node": "\ud83e\udd16 AI Diagnosis (Google Gemini)",
            "type": "main",
            "index": 0
          },
          {
            "node": "\ud83d\udd00 Merge AI + Restaurant Data",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "\ud83d\udfe1 Watch Alert (Slack)": {
      "main": [
        [
          {
            "node": "\ud83d\udcbe Update State (Google Sheets)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udcca Read Restaurant List": {
      "main": [
        [
          {
            "node": "\ud83d\udd04 Loop Over Restaurants",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udd04 Loop Over Restaurants": {
      "main": [
        [
          {
            "node": "\ud83c\udf10 Fetch Live Data (Google Places API)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "\ud83d\udd04 Loop Over Restaurants",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udce1 Alert Routing (Switch)": {
      "main": [
        [
          {
            "node": "\ud83d\udd34 Critical Alert (Slack)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "\ud83d\udfe1 Watch Alert (Slack)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "\ud83d\udfe2 Positive Alert (Slack)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udd34 Critical Alert (Slack)": {
      "main": [
        [
          {
            "node": "\ud83d\udcbe Update State (Google Sheets)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udfe2 Positive Alert (Slack)": {
      "main": [
        [
          {
            "node": "\ud83d\udcbe Update State (Google Sheets)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83e\udde0 Change Detection Engine": {
      "main": [
        [
          {
            "node": "\ud83d\udea6 Alert Worthy? (IF)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udd00 Merge AI + Restaurant Data": {
      "main": [
        [
          {
            "node": "\ud83d\udce1 Alert Routing (Switch)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udcbe Update State (Google Sheets)": {
      "main": [
        [
          {
            "node": "\ud83d\udcdc Log Alert History (Google Sheets)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83e\udd16 AI Diagnosis (Google Gemini)": {
      "main": [
        [
          {
            "node": "\ud83d\udd00 Merge AI + Restaurant Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83c\udf10 Fetch Live Data (Google Places API)": {
      "main": [
        [
          {
            "node": "\ud83e\udde0 Change Detection Engine",
            "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.

Pro

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

About this workflow

Automatically monitors restaurant ratings on Google Places daily, detects meaningful changes, uses Google Gemini AI to diagnose the root cause from real customer reviews, and delivers smart alerts to Slack — categorised as 🔴 Critical, 🟡 Watch, or 🟢 Positive.

Source: https://n8n.io/workflows/15516/ — 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

AI Institutional Stock Valuation Engine with Risk Scoring & Scenario Targets

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

Overview This is a production-grade, fully automated stock analysis system built entirely in n8n. It combines institutional-level financial analysis, dual AI model consensus, and a self-improving back

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

This workflow is a complete outbound automation system that discovers local businesses, extracts contact emails, generates personalized cold emails using AI, and runs a multi-step follow-up sequence —

Stop And Error, Google Sheets, HTTP Request +2
AI & RAG

A professional AI equity analysis automation built on n8n that transforms structured financial data and real-time news into disciplined, risk-adjusted price targets and actionable BUY/HOLD/SELL signal

Google Sheets, OpenAI, XML +3
AI & RAG

Imagine a dedicated financial expert tirelessly working behind the scenes, sifting through every transaction, every investment move, and every accounting entry. That's exactly what this automated syst

HTTP Request, Google Sheets, OpenAI +3