{
  "openapi": "3.0.1",
  "info": {
    "title": "Google Maps Local Rank Tracker with Weekly Change Alerts",
    "description": "Track where a business ranks on Google Maps across a grid, week after week. Get alerted when your Share of Local Voice drops, see which grid points you lost, and get an HTML heatmap. No Google API key.",
    "version": "0.1",
    "x-build-id": "hcZf4Ih9MKErzwctd"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/fayoussef~geo-grid-local-rank-tracker/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-fayoussef-geo-grid-local-rank-tracker",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/fayoussef~geo-grid-local-rank-tracker/runs": {
      "post": {
        "operationId": "runs-sync-fayoussef-geo-grid-local-rank-tracker",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/fayoussef~geo-grid-local-rank-tracker/run-sync": {
      "post": {
        "operationId": "run-sync-fayoussef-geo-grid-local-rank-tracker",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "required": [
          "businessName",
          "keywords"
        ],
        "properties": {
          "businessName": {
            "title": "Business name",
            "type": "string",
            "description": "The business whose Google Maps rank you want to track, exactly as it appears on its Google profile. The actor finds this name in the local results at each grid point."
          },
          "keywords": {
            "title": "Search keywords",
            "type": "array",
            "description": "The searches your customers type, e.g. `coffee shop`, `espresso bar near me`. Each keyword is checked at every grid point. Free plan uses the first keyword only.",
            "items": {
              "type": "string"
            }
          },
          "location": {
            "title": "Location (city, address or area)",
            "type": "string",
            "description": "Centre of the grid, e.g. `San Francisco, CA` or a full street address. It is geocoded automatically. Leave empty only if you set the centre latitude/longitude below."
          },
          "gridSize": {
            "title": "Grid size (N x N)",
            "minimum": 1,
            "maximum": 15,
            "type": "integer",
            "description": "How many points per side. 5 means a 5x5 = 25-point grid. Odd numbers keep the business at the centre point. Bigger grids = finer detail = more scans. Free plan is capped at 3x3.",
            "default": 5
          },
          "radius": {
            "title": "Grid radius",
            "minimum": 1,
            "maximum": 50,
            "type": "integer",
            "description": "Distance from the centre to the edge of the grid, in the unit below. 2-3 miles suits a city neighbourhood; use more for a whole metro.",
            "default": 2
          },
          "distanceUnit": {
            "title": "Distance unit",
            "enum": [
              "miles",
              "km"
            ],
            "type": "string",
            "description": "Unit for the grid radius and reported distances.",
            "default": "miles"
          },
          "maxRank": {
            "title": "Track ranks up to",
            "minimum": 1,
            "maximum": 20,
            "type": "integer",
            "description": "Positions beyond this are treated as \"not found\" at that point. Google's local finder returns up to 20 results per search.",
            "default": 20
          },
          "placeId": {
            "title": "Google place ID (optional)",
            "type": "string",
            "description": "For exact matching when the business name is generic or shared. Format like `0x89c25...:0x...`. If set, it is matched instead of the name."
          },
          "centerLat": {
            "title": "Centre latitude (optional)",
            "type": "number",
            "description": "Set this and the longitude to skip geocoding and pin the grid centre precisely."
          },
          "centerLng": {
            "title": "Centre longitude (optional)",
            "type": "number",
            "description": "Longitude of the grid centre. Used together with the latitude above."
          },
          "language": {
            "title": "Language (hl)",
            "type": "string",
            "description": "Google interface language code, e.g. `en`, `fr`, `es`.",
            "default": "en"
          },
          "countryCode": {
            "title": "Country (gl)",
            "type": "string",
            "description": "Two-letter country code for the search region, e.g. `us`, `gb`, `ca`.",
            "default": "us"
          },
          "trackChanges": {
            "title": "Track changes since the last run",
            "type": "boolean",
            "description": "Compare this run with the previous run of the same watchlist and save the history. The first run saves a baseline. Needs a paid plan. Off by default.",
            "default": false
          },
          "watchlistName": {
            "title": "Watchlist name",
            "type": "string",
            "description": "Names the saved history. Leave empty and it is derived from the business, location, keywords and grid, so a schedule needs no naming. Changing the grid size starts a new baseline."
          },
          "alertSolvChange": {
            "title": "Alert when Share of Local Voice moves by (points)",
            "minimum": 0.5,
            "maximum": 100,
            "type": "number",
            "description": "A keyword counts as dropped or improved when its Share of Local Voice moves by at least this many points since the previous run. Google Maps results shift a little between runs, so small moves are noise. Default 10.",
            "default": 10
          },
          "alertOnlyDrops": {
            "title": "Alert on drops only",
            "type": "boolean",
            "description": "On: send an alert only when a keyword drops. Off: also send one when a keyword improves.",
            "default": true
          },
          "alertWebhookUrl": {
            "title": "Alert webhook URL",
            "type": "string",
            "description": "A Discord, Slack or generic https webhook URL (Make, Zapier, n8n). One message per run, only when a keyword moved. Kept secret. Do not put it in a public task."
          },
          "alertTelegramBotToken": {
            "title": "Telegram bot token",
            "type": "string",
            "description": "Optional. Create a bot with @BotFather on Telegram and paste its token here. Kept secret."
          },
          "alertTelegramChatId": {
            "title": "Telegram chat ID",
            "type": "string",
            "description": "Optional. The chat the bot should message: your own chat ID, or a group or channel the bot was added to."
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Residential proxies are strongly recommended: Google Maps blocks datacenter IPs.",
            "default": {
              "useApifyProxy": true,
              "apifyProxyGroups": [
                "RESIDENTIAL"
              ]
            }
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}