{
  "name": "Track a business's Google Maps rank on a geo-grid every week in Google Sheets",
  "nodes": [
    {
      "parameters": {
        "content": "## Track a business's Google Maps rank on a geo-grid every week in Google Sheets\n\n### Who's it for\nLocal SEO agencies and business owners who want a weekly geo-grid report (like Local Falcon) without a monthly plan: where the business shows up on Google Maps around its location, for the keywords that matter, and who takes the local pack where it does not.\n\n### How it works\n1. Every Monday the Schedule Trigger starts the workflow.\n2. The **Settings** node holds the business (name and city, Google Maps link or place ID), the keywords, the grid size and the spacing between points.\n3. The **Google Maps Rank Tracker** Actor on Apify (`plainrows/google-maps-rank-tracker`) searches Google Maps from every point of the grid and returns the rank at each point, plus one summary per keyword.\n4. A Code node keeps the summaries: one dated row per keyword with the average rank, the share of points in the top 3 (share of local voice), the points where the business ranks and the competitor ranked first most often.\n5. The rows are appended to the `Local rank` tab, so you can chart the trend week after week.\n\n### Requirements\n- An Apify account (free plan available, limited to 1 keyword and a 3x3 grid) and its API token.\n- A Google Sheets account and a spreadsheet with a `Local rank` tab.\n- The Apify node is the verified community node `@apify/n8n-nodes-apify` (available on n8n Cloud; on self-hosted n8n install it from Settings > Community nodes).\n\n### How to customize\n- Edit `business`, `keywords`, `gridSize` (3, 5, 7 or 9) and `gridSpacingKm` in **Settings**. A place ID is the surest way to name the business.\n- Keep the same grid and zoom from week to week to compare like with like.\n- Add a Slack message when the share of local voice drops below last week's.\n",
        "height": 760,
        "width": 520
      },
      "id": "ea5a32fb-597b-5cb9-9d83-ae93eca37be8",
      "name": "Description",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -660,
        -340
      ]
    },
    {
      "parameters": {
        "content": "### Setup\n1. In **Settings**, put the `business` (name and city, Google Maps link or place ID), the `keywords` (one per line, without the city), `gridSize` and `gridSpacingKm`.\n2. Add your Apify credential (free account at apify.com) to *Scan the grid*.\n3. Connect Google Sheets in *Append to sheet* and pick a spreadsheet with a `Local rank` tab.\n4. Run once by hand to check the rows.\n\n**Cost:** a price per grid point and keyword (see the Actor's Pricing tab); the node caps each run with *Maximum Cost per Run*.",
        "height": 340,
        "width": 420,
        "color": 7
      },
      "id": "6740fe63-7136-5baf-80f0-3865ece29191",
      "name": "Setup",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        440,
        -340
      ]
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 7
            }
          ]
        }
      },
      "id": "24b89fa8-fbd4-555e-bc8b-738876528aff",
      "name": "Every Monday",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        120
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "b8de4aa9-892f-516c-9b09-319fdf429d54",
              "name": "business",
              "value": "Monmouth Coffee Company, Borough, London",
              "type": "string"
            },
            {
              "id": "0b9dce08-7882-51e7-be17-a32b0bd2989e",
              "name": "keywords",
              "value": "coffee shop\nespresso",
              "type": "string"
            },
            {
              "id": "ec9f5823-9190-5b10-9a7e-fb60b0ea9d4b",
              "name": "gridSize",
              "value": "5",
              "type": "string"
            },
            {
              "id": "6313139f-15e7-5315-973c-82a93fd0329c",
              "name": "gridSpacingKm",
              "value": "1",
              "type": "string"
            },
            {
              "id": "2db622b5-344d-5bc2-a658-007df0dc4348",
              "name": "country",
              "value": "GB",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "7204187c-a79b-5703-a282-14e27c4640e0",
      "name": "Settings",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        220,
        120
      ]
    },
    {
      "parameters": {
        "resource": "Actors",
        "operation": "Run actor and get dataset",
        "actorId": "plainrows~google-maps-rank-tracker",
        "customBody": "={{ JSON.stringify({ business: $json.business, keywords: $json.keywords.split('\\n').map((k) => k.trim()).filter(Boolean), gridSize: String($json.gridSize), gridSpacingKm: String($json.gridSpacingKm), country: $json.country }) }}",
        "maxTotalChargeUsd": 1
      },
      "id": "f8972b9a-2905-579f-be24-ec1f7362ab91",
      "name": "Scan the grid",
      "type": "@apify/n8n-nodes-apify.apify",
      "typeVersion": 1,
      "position": [
        440,
        120
      ],
      "credentials": {
        "apifyApi": {
          "id": "",
          "name": "Apify account"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// One dated row per keyword from the free summary rows; the per-point rows stay in the Apify dataset.\nconst week = new Date().toISOString().slice(0, 10);\nreturn $input.all()\n  .map((i) => i.json)\n  .filter((r) => r.type === 'keyword-summary')\n  .map((r) => ({\n    json: {\n      week,\n      business: r.businessName,\n      keyword: r.keyword,\n      grid: `${r.gridSize}x${r.gridSize}, ${r.gridSpacingKm} km`,\n      averageRankWhereFound: r.averageRankWhereFound,\n      averageRankAllPoints: r.averageRankAllPoints,\n      shareOfLocalVoiceTop3Pct: r.shareOfLocalVoiceTop3Pct,\n      pointsFound: `${r.pointsFound}/${r.pointsTotal}`,\n      topCompetitor: r.topCompetitor ? r.topCompetitor.name : '',\n    },\n  }));"
      },
      "id": "ad303235-54e7-516e-a2c8-80df1441eeb9",
      "name": "One row per keyword",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        660,
        120
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "",
          "mode": "url"
        },
        "sheetName": {
          "__rl": true,
          "value": "Local rank",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "autoMapInputData",
          "value": {},
          "matchingColumns": [],
          "schema": []
        },
        "options": {}
      },
      "id": "1a0caa66-661e-52f5-898e-74c32e3f5c86",
      "name": "Append to sheet",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        880,
        120
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "",
          "name": "Google Sheets account"
        }
      }
    }
  ],
  "connections": {
    "Every Monday": {
      "main": [
        [
          {
            "node": "Settings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Settings": {
      "main": [
        [
          {
            "node": "Scan the grid",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scan the grid": {
      "main": [
        [
          {
            "node": "One row per keyword",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "One row per keyword": {
      "main": [
        [
          {
            "node": "Append to sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "templateCredsSetupCompleted": false
  }
}
