This workflow corresponds to n8n.io template #17596 — we link there as the canonical source.
This workflow follows the Apifyn8N Nodes Apify → 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 →
{
"name": "Track competitor Google review counts and star ratings in Google Sheets",
"nodes": [
{
"id": "9a1f4c70-0001-4b01-a001-000000000001",
"name": "Every Monday morning",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
0,
460
],
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"triggerAtDay": [
1
],
"triggerAtHour": 8
}
]
}
},
"typeVersion": 1.2
},
{
"id": "9a1f4c70-0002-4b02-a002-000000000002",
"name": "Set your business and search",
"type": "n8n-nodes-base.set",
"position": [
260,
460
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "9a1f4c70-0011-4b11-a011-+1234567890",
"name": "yourBusinessName",
"type": "string",
"value": "Greg's Auto Repair"
},
{
"id": "9a1f4c70-0012-4b12-a012-+1234567890",
"name": "searchTerm",
"type": "string",
"value": "auto repair"
},
{
"id": "9a1f4c70-0013-4b13-a013-+1234567890",
"name": "location",
"type": "string",
"value": "Nashville, Tennessee, United States"
},
{
"id": "9a1f4c70-0014-4b14-a014-+1234567890",
"name": "googleDomain",
"type": "string",
"value": "google.com"
},
{
"id": "9a1f4c70-0015-4b15-a015-+1234567890",
"name": "country",
"type": "string",
"value": "us"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "9a1f4c70-0003-4b03-a003-000000000003",
"name": "Search the Google local pack",
"type": "@apify/n8n-nodes-apify.apify",
"position": [
520,
460
],
"parameters": {
"memory": 4096,
"actorId": "johnvc~google-local-api",
"resource": "Actors",
"operation": "Run actor and get dataset",
"customBody": "={{ JSON.stringify({ q: $json.searchTerm, location: $json.location, google_domain: $json.googleDomain, gl: $json.country, hl: 'en', max_pages: 1 }) }}"
},
"typeVersion": 1
},
{
"id": "9a1f4c70-0004-4b04-a004-000000000004",
"name": "Keep searches that returned results",
"type": "n8n-nodes-base.filter",
"position": [
780,
460
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "9a1f4c70-0041-4b41-a041-+1234567890",
"operator": {
"type": "array",
"operation": "notEmpty",
"singleValue": true
},
"leftValue": "={{ $json.local_results }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "9a1f4c70-0005-4b05-a005-000000000005",
"name": "One row per business",
"type": "n8n-nodes-base.splitOut",
"position": [
1040,
460
],
"parameters": {
"include": "selectedOtherFields",
"options": {},
"fieldToSplitOut": "local_results",
"fieldsToInclude": "search_parameters"
},
"typeVersion": 1
},
{
"id": "9a1f4c70-0006-4b06-a006-000000000006",
"name": "Score every rival against you",
"type": "n8n-nodes-base.code",
"position": [
1300,
460
],
"parameters": {
"jsCode": "// Build this week's review scoreboard.\n// Every business Google showed in the local pack becomes one row, and each\n// rival is scored against your own listing on review count and star rating.\nconst config = $('Set your business and search').first().json;\nconst yourName = String(config.yourBusinessName || '').trim().toLowerCase();\nconst weekOf = $now.toFormat('yyyy-MM-dd');\n\nconst rows = $input.all().map((item) => {\n const biz = item.json.local_results || {};\n const params = item.json.search_parameters || {};\n const title = String(biz.title || '');\n return {\n search: params.q || '',\n location: params.location || '',\n rank: biz.position ?? '',\n business: title,\n isYours: yourName !== '' && title.toLowerCase().includes(yourName),\n rating: typeof biz.rating === 'number' ? biz.rating : '',\n reviews: typeof biz.reviews === 'number' ? biz.reviews : '',\n category: biz.type || '',\n phone: biz.phone || '',\n placeId: biz.place_id || '',\n };\n});\n\n// Your own listing, if it ranked for this search. When it did not, the two\n// comparison columns stay blank rather than guessing a baseline.\nconst you = rows.find((r) => r.isYours);\nconst canCompare = (r, field) =>\n you && !r.isYours && r[field] !== '' && you[field] !== '';\n\nreturn rows.map((r) => ({\n json: {\n 'Week of': weekOf,\n Search: r.search,\n Location: r.location,\n 'Rank in pack': r.rank,\n Business: r.business,\n 'Is your business': r.isYours ? 'YES' : '',\n Rating: r.rating,\n Reviews: r.reviews,\n 'Reviews vs you': canCompare(r, 'reviews') ? r.reviews - you.reviews : '',\n 'Rating vs you': canCompare(r, 'rating')\n ? Number((r.rating - you.rating).toFixed(1))\n : '',\n Category: r.category,\n Phone: r.phone,\n 'Place ID': r.placeId,\n },\n}));\n"
},
"typeVersion": 2
},
{
"id": "9a1f4c70-0007-4b07-a007-000000000007",
"name": "Append this week's scoreboard",
"type": "n8n-nodes-base.googleSheets",
"position": [
1560,
460
],
"parameters": {
"columns": {
"value": {},
"mappingMode": "autoMapInputData",
"matchingColumns": []
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": ""
},
"documentId": {
"__rl": true,
"mode": "list",
"value": ""
}
},
"typeVersion": 4.5
},
{
"id": "9a1f4c70-0090-4b90-a090-000000000090",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-620,
40
],
"parameters": {
"width": 520,
"height": 1140,
"content": "## Track competitor Google review counts and star ratings in Google Sheets\n\nNo Google Business Profile connection, no SerpApi or Bright Data account, and no AI model. Every week this workflow reads the Google local pack for your search term and appends one row per business to your sheet: star rating, review count, rank, and how far ahead or behind each rival sits, with your own listing flagged YES.\n\nBecause it reads Google's public local results instead of a listing you own, it picks up your competitors' numbers as easily as your own. That is the part a Google Business Profile integration cannot do.\n\n**Who's it for**\nOwners watching their reputation against the shop down the street, local SEO consultants reporting to clients, and agencies pitching review generation work.\n\n**How it works**\n1. A schedule trigger fires once a week\n2. One Set node holds your business name, search term, and city\n3. The Apify node pulls the whole local pack for that search\n4. A Code node scores every rival against you, and the rows land in your sheet\n\n**Setup**\n1. Create a free Apify account and add your API token to the Apify credential\n2. Connect your Google account in the Sheets node and pick a spreadsheet\n3. Replace the example business name, search term, and location, then run once to test\n\n**Good to know**\nAbout 2 cents per run, so roughly 9 cents a month on a weekly schedule.\nOne run reads one page of Google's local results, which is about 20 businesses on desktop.\nThis records star rating and review count, not the text of individual reviews.\nActor: https://apify.com/johnvc/google-local-api?fpr=9n7kx3&fp_sid=n8n"
},
"typeVersion": 1
},
{
"id": "9a1f4c70-0091-4b91-a091-000000000091",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-40,
60
],
"parameters": {
"color": 7,
"width": 240,
"height": 240,
"content": "### 1. Schedule\nRuns every Monday morning. Change the cadence, or swap in a manual trigger while you test."
},
"typeVersion": 1
},
{
"id": "9a1f4c70-0092-4b92-a092-000000000092",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
220,
60
],
"parameters": {
"color": 7,
"width": 240,
"height": 240,
"content": "### 2. Your input\nYour business name, search term, and city. This is the only node you edit."
},
"typeVersion": 1
},
{
"id": "9a1f4c70-0093-4b93-a093-000000000093",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
480,
60
],
"parameters": {
"color": 7,
"width": 240,
"height": 240,
"content": "### 3. Search\nRuns the Google Local API actor on your search term. Add your Apify credential here."
},
"typeVersion": 1
},
{
"id": "9a1f4c70-0094-4b94-a094-000000000094",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
740,
60
],
"parameters": {
"color": 7,
"width": 240,
"height": 240,
"content": "### 4. Clean\nSkips the run when Google returned no local results, so blank rows never reach the sheet."
},
"typeVersion": 1
},
{
"id": "9a1f4c70-0095-4b95-a095-000000000095",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
1000,
60
],
"parameters": {
"color": 7,
"width": 240,
"height": 240,
"content": "### 5. Unpack\nSplits the local pack into one item per business."
},
"typeVersion": 1
},
{
"id": "9a1f4c70-0096-4b96-a096-000000000096",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
1260,
60
],
"parameters": {
"color": 7,
"width": 240,
"height": 240,
"content": "### 6. Score\nFlags your listing and works out the review and rating gap to every rival."
},
"typeVersion": 1
},
{
"id": "9a1f4c70-0097-4b97-a097-000000000097",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
1520,
60
],
"parameters": {
"color": 7,
"width": 240,
"height": 240,
"content": "### 7. Deliver\nPick your spreadsheet and tab. Columns map automatically."
},
"typeVersion": 1
},
{
"id": "9a1f4c70-0080-4b80-a080-000000000080",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"position": [
220,
760
],
"parameters": {
"color": 7,
"width": 380,
"height": 220,
"content": "### Your business not in the pack?\nThe two comparison columns stay blank when your listing does not rank for that search. That is a finding worth logging: try a closer search term, or a city you actually rank in."
},
"typeVersion": 1
},
{
"id": "9a1f4c70-0081-4b81-a081-000000000081",
"name": "Sticky Note9",
"type": "n8n-nodes-base.stickyNote",
"position": [
640,
760
],
"parameters": {
"color": 7,
"width": 380,
"height": 220,
"content": "### Self-hosting n8n?\nThere is also a dedicated community node for this actor: `n8n-nodes-google-local-api` on npm."
},
"typeVersion": 1
}
],
"settings": {
"executionOrder": "v1"
},
"connections": {
"Every Monday morning": {
"main": [
[
{
"node": "Set your business and search",
"type": "main",
"index": 0
}
]
]
},
"One row per business": {
"main": [
[
{
"node": "Score every rival against you",
"type": "main",
"index": 0
}
]
]
},
"Search the Google local pack": {
"main": [
[
{
"node": "Keep searches that returned results",
"type": "main",
"index": 0
}
]
]
},
"Set your business and search": {
"main": [
[
{
"node": "Search the Google local pack",
"type": "main",
"index": 0
}
]
]
},
"Score every rival against you": {
"main": [
[
{
"node": "Append this week's scoreboard",
"type": "main",
"index": 0
}
]
]
},
"Keep searches that returned results": {
"main": [
[
{
"node": "One row per business",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
No Google Business Profile connection and no SerpApi or Bright Data account. This template runs weekly review tracking across the whole Google local pack for your search term, appending one row per business to Google Sheets: star rating, review count, rank, and the gap to each…
Source: https://n8n.io/workflows/17596/ — 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.
No rank tracker subscription and no SERP API key. This template checks where your business ranks in Google's local results for the keywords you choose, every week, and appends one row per listing to G
No Firecrawl API key and no OpenAI key. This template checks every week whether any member of Congress disclosed a trade in the stocks you follow, and appends one row per transaction to Google Sheets:
No IP watch service and no per-seat subscription. Every week this searches Google Patents for the technologies you follow and appends one row per patent to Google Sheets: title, assignee, inventor, pu
This workflow runs every Monday morning, searches Google Shopping for a list of products using Apify, summarizes credible weekly pricing metrics per product, and appends the results to a Google Sheets
No stock agency monitoring service and no per-image fee. Every week this looks up the images you list and appends one row per page carrying that exact image to Google Sheets: the site, the page title,