{
  "data": {
    "id": "97AjPnapucPrZpz9l",
    "actId": "d1d5hOcDg4pByYO0X",
    "userId": "zq8lKbpLzTjGDayPC",
    "startedAt": "2026-10-29T21:17:56.303Z",
    "finishedAt": "2026-10-29T21:18:08.490Z",
    "status": "SUCCEEDED",
    "meta": {
      "origin": "CLI"
    },
    "stats": {
      "durationMillis": 12111,
      "runTimeSecs": 12.111,
      "computeUnits": 0.013456666666666667,
      "imageSizeBytes": 318917632
    },
    "options": {
      "useCache": true,
      "betaPackages": false,
      "memoryMbytes": 4096,
      "diskMbytes": 8192
    },
    "createdByOrganizationMemberUserId": "GK9YjZRyQZVzOdoH5",
    "exitCode": 0,
    "inputSchema": "{\n  \"title\": \"Google Maps Similar Places Input\",\n  \"description\": \"Find related places Google Maps shows for a business, or discover same-category competitors near it.\",\n  \"type\": \"object\",\n  \"schemaVersion\": 1,\n  \"properties\": {\n    \"mode\": {\n      \"title\": \"Mode\",\n      \"type\": \"string\",\n      \"description\": \"Choose how to enter the source places.\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"byPlace\",\n        \"byQuery\"\n      ],\n      \"enumTitles\": [\n        \"By place URL or Place ID\",\n        \"By place name and location\"\n      ],\n      \"default\": \"byPlace\",\n      \"prefill\": \"byPlace\"\n    },\n    \"placeUrls\": {\n      \"title\": \"Place URLs or IDs\",\n      \"type\": \"array\",\n      \"description\": \"Google Maps place URLs, canonical ChIJ Place IDs, or legacy 0x…:0x… feature IDs. Mixed values are allowed (mode=byPlace).\",\n      \"editor\": \"stringList\",\n      \"prefill\": [\n        \"https://www.google.com/maps/place/The+Ritz+London/@51.5070782,-0.1416273,17z/data=!3m1!4b1!4m6!3m5!1s0x48760529d30fc857:0x596135811e044014!8m2!3d51.5070782!4d-0.1416273!16zL20vMDQ3enJ2?hl=en\"\n      ],\n      \"example\": [\n        \"ChIJ8Q2WSpJZwokRQz-bYYgEskM\",\n        \"https://maps.app.goo.gl/example\"\n      ]\n    },\n    \"searchQueries\": {\n      \"title\": \"Place names\",\n      \"type\": \"array\",\n      \"description\": \"Business, hotel, or landmark names to resolve and analyze (mode=byQuery).\",\n      \"editor\": \"stringList\",\n      \"example\": [\n        \"Joe's Pizza\",\n        \"The Ritz London\"\n      ]\n    },\n    \"location\": {\n      \"title\": \"Location\",\n      \"type\": \"string\",\n      \"description\": \"City or area appended to every place name (mode=byQuery).\",\n      \"editor\": \"textfield\",\n      \"example\": \"New York\"\n    },\n    \"maxItems\": {\n      \"title\": \"Max results\",\n      \"type\": \"integer\",\n      \"description\": \"Maximum number of similar places to return across all sources.\",\n      \"minimum\": 1,\n      \"maximum\": 500,\n      \"default\": 100,\n      \"prefill\": 3\n    },\n    \"similaritySource\": {\n      \"title\": \"Related places source\",\n      \"type\": \"string\",\n      \"description\": \"Auto uses Google's related carousel and falls back to same-category nearby places when the carousel has fewer than Min similar. Carousel never uses the fallback. Same category skips the carousel.\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"auto\",\n        \"carousel\",\n        \"sameCategory\"\n      ],\n      \"enumTitles\": [\n        \"Auto (carousel, then same category)\",\n        \"Google carousel only\",\n        \"Same category nearby only\"\n      ],\n      \"default\": \"auto\",\n      \"prefill\": \"auto\"\n    },\n    \"minSimilar\": {\n      \"title\": \"Min similar\",\n      \"type\": \"integer\",\n      \"description\": \"In auto mode, use the same-category fallback when the carousel has fewer usable rows than this number and cannot already fill Max results.\",\n      \"minimum\": 0,\n      \"maximum\": 20,\n      \"default\": 5,\n      \"prefill\": 1\n    },\n    \"categoryOverride\": {\n      \"title\": \"Category override\",\n      \"type\": \"string\",\n      \"description\": \"Use this category for the same-category fallback instead of the source place's own category.\",\n      \"editor\": \"textfield\",\n      \"example\": \"Pizza restaurant\"\n    },\n    \"minRating\": {\n      \"title\": \"Minimum rating\",\n      \"type\": \"number\",\n      \"description\": \"Drop related places rated below this value. Places without a published rating are dropped when this is above zero.\",\n      \"minimum\": 0,\n      \"maximum\": 5,\n      \"example\": 4.5\n    },\n    \"minReviews\": {\n      \"title\": \"Minimum reviews\",\n      \"type\": \"integer\",\n      \"description\": \"Drop related places with fewer than this many reviews.\",\n      \"minimum\": 0,\n      \"maximum\": 1000000,\n      \"example\": 1000\n    },\n    \"maxDistanceKm\": {\n      \"title\": \"Maximum distance (km)\",\n      \"type\": \"number\",\n      \"description\": \"Keep only related places within this straight-line distance from the source. Requires published coordinates.\",\n      \"minimum\": 0.1,\n      \"maximum\": 50,\n      \"example\": 2\n    },\n    \"categoryFilter\": {\n      \"title\": \"Category contains\",\n      \"type\": \"string\",\n      \"description\": \"Keep only places whose category list contains this text (case-insensitive).\",\n      \"editor\": \"textfield\",\n      \"example\": \"Hotel\"\n    },\n    \"sortBy\": {\n      \"title\": \"Sort by\",\n      \"type\": \"string\",\n      \"description\": \"Order of the returned rows. Recommended keeps Google's carousel and search order.\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"recommended\",\n        \"rating\",\n        \"reviews\",\n        \"distance\"\n      ],\n      \"enumTitles\": [\n        \"Recommended (Google order)\",\n        \"Highest rating\",\n        \"Most reviews\",\n        \"Closest first\"\n      ],\n      \"default\": \"recommended\",\n      \"prefill\": \"recommended\"\n    },\n    \"deduplicate\": {\n      \"title\": \"Remove duplicates\",\n      \"type\": \"boolean\",\n      \"description\": \"Keep one row per place, using the canonical Place ID, then the feature ID, then name and coordinates.\",\n      \"default\": true,\n      \"prefill\": true\n    },\n    \"includeDetails\": {\n      \"title\": \"Include details\",\n      \"type\": \"boolean\",\n      \"description\": \"Look up each returned place's own page for its canonical Place ID, address, website, phone, categories, plus code, photo count, and image. Adds one request per row and slows dense runs.\",\n      \"default\": true,\n      \"prefill\": false\n    },\n    \"includeMedia\": {\n      \"title\": \"Include images\",\n      \"type\": \"boolean\",\n      \"description\": \"Include the image URL when Google publishes one.\",\n      \"default\": true,\n      \"prefill\": true\n    },\n    \"language\": {\n      \"title\": \"Language\",\n      \"type\": \"string\",\n      \"description\": \"Google Maps interface language. Affects names, categories, and the fallback category query.\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"en\",\n        \"es\",\n        \"fr\",\n        \"de\",\n        \"it\",\n        \"pt\",\n        \"ja\",\n        \"ko\",\n        \"zh\",\n        \"ar\",\n        \"ru\"\n      ],\n      \"enumTitles\": [\n        \"English\",\n        \"Spanish\",\n        \"French\",\n        \"German\",\n        \"Italian\",\n        \"Portuguese\",\n        \"Japanese\",\n        \"Korean\",\n        \"Chinese\",\n        \"Arabic\",\n        \"Russian\"\n      ],\n      \"default\": \"en\",\n      \"prefill\": \"en\"\n    }\n  },\n  \"required\": []\n}",
    "readme": "# Google Maps Related Place & Competitor Finder\n\nFind the places Google Maps treats as related to a business, hotel, or landmark — and keep going when Google shows no carousel by discovering same-category places around the same pin. Enter many URLs, Place IDs, or place names in one run, filter and sort the results, and get an explicit `relationMode` on every row so you always know whether Google recommended the place or it was found nearby.\n\n## What it does\n\n- **Two entry modes:** `byPlace` accepts Google Maps URLs, canonical `ChIJ` Place IDs, and legacy `0x…:0x…` feature IDs; `byQuery` accepts business names plus an optional city or area. Batch both.\n- **Carousel first, nearby fallback second:** reads Google's related-place carousel when it exists, then fills short results with places from the source's own category around the same coordinates.\n- **Explicit provenance:** every row says `googleCarousel` or `sameCategoryNearby`; fallback rows are never presented as Google recommendations.\n- **Filters and order:** minimum rating, minimum reviews, maximum straight-line distance, category text, and sort by recommended order, rating, reviews, or distance.\n- **Identity, contacts, and distance:** canonical Place ID, legacy feature ID, CID, KG MID, address, website, phone, plus code, photo count, coordinates, image, and computed `distanceMeters`.\n- **Empty fields are omitted** rather than sent as `null` or guessed.\n\n## Services\n\n| Service | What it returns | Used by |\n|---|---|---|\n| Google Maps place record | Source name, canonical and legacy IDs, category, address, rating, reviews, website, phone, coordinates | both modes |\n| Google Maps related carousel | Up to the cards Google publishes for that place, with names, ratings, reviews, coordinates, images, and visible card text | `byPlace`, `byQuery` |\n| Google Maps same-category search | Ranked places in the source category around the source coordinates, 20 per page | fallback in both modes |\n| Google Maps place details | Canonical Place ID, address, contacts, categories, plus code, photo count, image for one returned place | optional enrichment |\n\n## How it works\n\n1. **Resolve the source.** A place URL provides its feature ID and coordinates directly. A canonical `ChIJ` ID is resolved through Google's public place page in one request. A name query is resolved through Google's map search, preferring the focused result and requiring a name match otherwise.\n2. **Read the source record and carousel.** The same place response carries the source business data and, when Google exposes one, the related-place carousel.\n3. **Decide whether to fall back.** In `auto` mode the fallback runs when the carousel has fewer usable rows than `minSimilar` and the carousel cannot already fill `maxItems`. `carousel` never falls back; `sameCategory` skips the carousel entirely.\n4. **Search the same category nearby.** The fallback uses the source's first category (or `categoryOverride`) anchored at the source coordinates, page by page, until enough places pass the filters, the result window is exhausted, or `maxItems` is reached. Sorting by rating, reviews, or distance considers the full window before the cap is applied.\n5. **Clean the result set.** The source place is removed, filters are applied, identities are deduplicated, and rows are sorted.\n6. **Optionally enrich.** `includeDetails=true` looks up each emitted place's own page for its canonical Place ID, contacts, category, plus code, photo count, and image.\n7. **Push immediately.** Records are emitted as they are finalised, with the global `maxItems` cap. Unresolved inputs are skipped and reported without failing the whole run.\n\n## Input\n\n| Field | Type | Default | Description |\n|---|---|---|---|\n| `mode` | string | `byPlace` | `byPlace` accepts URLs or IDs; `byQuery` accepts place names |\n| `placeUrls` | array | – | Google Maps URLs, `ChIJ…` IDs, or `0x…:0x…` feature IDs (mode=`byPlace`) |\n| `searchQueries` | array | – | Business, hotel, or landmark names (mode=`byQuery`) |\n| `location` | string | – | City or area appended to every name (mode=`byQuery`) |\n| `maxItems` | integer | `100` | Global cap on returned rows (1–500) |\n| `similaritySource` | string | `auto` | `auto`, `carousel`, or `sameCategory` |\n| `minSimilar` | integer | `5` | In `auto`, fall back when the carousel has fewer usable rows than this and cannot fill `maxItems` (0–20) |\n| `categoryOverride` | string | – | Category used by the fallback instead of the source's own |\n| `minRating` | number | – | Drop places below this rating (0–5) |\n| `minReviews` | integer | – | Drop places below this review count |\n| `maxDistanceKm` | number | – | Keep places within this straight-line distance (0.1–50 km) |\n| `categoryFilter` | string | – | Keep places whose category list contains this text |\n| `sortBy` | string | `recommended` | `recommended`, `rating`, `reviews`, or `distance` |\n| `deduplicate` | boolean | `true` | Keep one row per place identity |\n| `includeDetails` | boolean | `true` | Look up each returned place's own page for extra fields |\n| `includeMedia` | boolean | `true` | Include image URLs when Google publishes them |\n| `language` | string | `en` | Maps language: `en`, `es`, `fr`, `de`, `it`, `pt`, `ja`, `ko`, `zh`, `ar`, `ru` |\n\n### Example: related hotels for one place URL\n\n```json\n{\n  \"mode\": \"byPlace\",\n  \"placeUrls\": [\n    \"https://www.google.com/maps/place/The+Ritz+London/@51.5070782,-0.1416273,17z/data=!3m1!4b1!4m6!3m5!1s0x48760529d30fc857:0x596135811e044014!8m2!3d51.5070782!4d-0.1416273!16zL20vMDQ3enJ2?hl=en\"\n  ],\n  \"maxItems\": 20,\n  \"similaritySource\": \"auto\",\n  \"minSimilar\": 5\n}\n```\n\n### Example: competitors for a restaurant with no carousel\n\n```json\n{\n  \"mode\": \"byPlace\",\n  \"placeUrls\": [\"ChIJ8Q2WSpJZwokRQz-bYYgEskM\"],\n  \"similaritySource\": \"sameCategory\",\n  \"maxItems\": 50,\n  \"includeDetails\": true\n}\n```\n\n### Example: several names in one city, filtered and sorted\n\n```json\n{\n  \"mode\": \"byQuery\",\n  \"searchQueries\": [\"Joe's Pizza\", \"Peter Luger Steak House\"],\n  \"location\": \"New York\",\n  \"minRating\": 4.2,\n  \"minReviews\": 500,\n  \"maxDistanceKm\": 5,\n  \"sortBy\": \"rating\",\n  \"maxItems\": 30\n}\n```\n\n### Example: carousel only, no fallback\n\n```json\n{\n  \"mode\": \"byPlace\",\n  \"placeUrls\": [\"ChIJ4fRwZb25yhQRpHwVijb3LeU\"],\n  \"similaritySource\": \"carousel\",\n  \"includeMedia\": false,\n  \"maxItems\": 10\n}\n```\n\n## Output\n\nEvery row is one related place:\n\n- `relationMode` — `googleCarousel` or `sameCategoryNearby`\n- `relationQuery` — category used by the fallback, when applicable\n- `relatedSectionType` — Google's own section label when the response exposes one\n- `rank` — 1-based position in the returned order\n- `name` — related place name\n- `placeId` — canonical `ChIJ…` Place ID, only when Google publishes one\n- `featureId` — legacy `0x…:0x…` feature ID, never used in place of `placeId`\n- `cid`, `kgmid` — other observed identities\n- `googleMapsUrl` — link to the related place\n- `categoryName`, `categories` — primary category and full observed list\n- `totalScore`, `reviewsCount` — rating and review count\n- `address`, `website`, `phone` — contacts when Google publishes them\n- `plusCode`, `photoCount` — detail fields when enrichment is enabled\n- `price` — visible carousel price string, kept exactly as shown\n- `description` — visible carousel comparison text\n- `distance` — visible carousel distance badge\n- `distanceMeters` — straight-line distance from the source coordinates, in metres\n- `latitude`, `longitude` — related place coordinates\n- `image` — image URL at a larger size, when available\n- `sourceBusinessName`, `sourcePlaceId`, `sourceFeatureId`, `sourcePlaceUrl` — the place you searched\n- `sourceCategory`, `sourceAddress`, `sourceLatitude`, `sourceLongitude` — source context\n- `sourceUrl` — alias of `sourcePlaceUrl` for older integrations\n- `recordType` — always `similarPlace`\n- `scrapedAt` — ISO timestamp\n\n## Use cases\n\n- **Local SEO and competitive analysis** — compare the places Google associates with a client's listing, or the competitors around its pin.\n- **Market and category research** — expand a handful of seed businesses into a wider set of nearby places in the same category.\n- **Lead and partner discovery** — collect contacts, websites, and ratings for businesses around a target area.\n- **Data enrichment** — attach canonical Place IDs, categories, and coordinates to an existing list of businesses.\n- **Recommendation feeds** — build a \"places like this\" list from Google's own related signal plus a transparent fallback.\n\n## Usage cost\n\n- No Google API key, no billing account, and no paid API calls are required.\n- The actor runs in 1024 MB and needs no browser.\n- A small run with `includeDetails=false` returns in seconds. `includeDetails=true` adds one place lookup per returned row, so large `maxItems` values take longer.\n- `maxItems` is a hard cap: the actor stops when it reaches it, when Google's result window is exhausted, or when every input is resolved. Filters are counted before the cap, so they do not shorten the result set while eligible places remain.\n- `sortBy=rating`, `reviews`, or `distance` reads the full nearby window before selecting rows; `recommended` stops as soon as the cap is met.\n\n## FAQ\n\n**Why did `carousel` mode return no rows?** Google does not show a related-place carousel for many signed-out place pages. `carousel` is truthful about that; use `auto` or `sameCategory` when you need rows.\n\n**Are fallback rows Google recommendations?** No. They are places in the source's category near the source coordinates. `relationMode` says `sameCategoryNearby`, and `relationQuery` shows the category used.\n\n**How many carousel results can I get?** Google typically publishes 3–5 cards, and sometimes none. That is the whole carousel; no setting can make Google show more.\n\n**How many same-category places are available?** Google returns 20 per page and the observed window is around 104 unique places for a dense query. Sparse categories or small towns exhaust sooner.\n\n**Why is `address` or `website` missing from a carousel row?** The carousel does not carry contacts. Turn on `includeDetails` to look up each place's own page; if Google still does not publish the field, it is omitted.\n\n**Why does `distanceMeters` differ from the distance badge on the card?** The badge is Google's own display string. `distanceMeters` is a straight-line calculation from the source coordinates to the related place coordinates.\n\n**Why are prices in an unexpected currency?** The carousel price is Google's localized display string for the request location. It is kept raw, not converted or normalised.\n\n**Can I use a Place ID instead of a URL?** Yes. Canonical `ChIJ…` IDs work in `placeUrls`, and legacy `0x…:0x…` feature IDs are accepted too.\n\n**Do I need a proxy or cookies?** No. The actor reads public place data and selects a working connection automatically.\n\n**What happens if one input is invalid?** That input is skipped and reported in the status message; the other inputs still run. If no input resolves, the run fails with a clear message instead of returning an empty success.\n\n## Notes\n\n- `price`, `description`, `distance`, and `relatedSectionType` are emitted only when Google's response actually carries them.\n- A canonical `ChIJ…` value always goes to `placeId`; a legacy `0x…:0x…` value always goes to `featureId`. They are never relabelled.\n- `sourceUrl` remains an alias of `sourcePlaceUrl` so older integrations keep working.\n- Duplicate identities are removed by default: canonical Place ID first, then feature ID, then name plus rounded coordinates.\n- In `auto` mode, carousel rows and fallback rows can both appear; `relationMode` separates them.\n\n## Limitations\n\n- **The carousel is conditional.** Most signed-out place pages show no related carousel at all. The actor cannot create one; it uses the honest same-category fallback instead.\n- **Fallback relevance depends on category.** If the source category is broad or wrong, nearby results can be broad too. Use `categoryOverride` or `categoryFilter` to narrow them.\n- **The nearby window is finite.** Google stops returning new places after roughly 100 unique results for a dense query, and sooner for sparse categories.\n- **No similarity score.** Google does not publish one, and the actor does not invent one.\n- **Detail fields are optional and conditional.** `includeDetails` improves coverage, but a field Google does not publish is omitted rather than fabricated.\n",
    "actorDefinition": {
      "actorSpecification": 1,
      "name": "google-maps-related-place-and-competitor-finder",
      "title": "Google Maps Related Place & Competitor Finder",
      "description": "Find places Google Maps shows as related to a business, hotel, or landmark, or discover same-category places near it. Batch URLs, Place IDs, or name queries and get ratings, reviews, contacts, images, distance, and explicit relation provenance.",
      "version": "1.0",
      "buildTag": "latest",
      "dockerfile": "./Dockerfile",
      "readme": "# Google Maps Related Place & Competitor Finder\n\nFind the places Google Maps treats as related to a business, hotel, or landmark — and keep going when Google shows no carousel by discovering same-category places around the same pin. Enter many URLs, Place IDs, or place names in one run, filter and sort the results, and get an explicit `relationMode` on every row so you always know whether Google recommended the place or it was found nearby.\n\n## What it does\n\n- **Two entry modes:** `byPlace` accepts Google Maps URLs, canonical `ChIJ` Place IDs, and legacy `0x…:0x…` feature IDs; `byQuery` accepts business names plus an optional city or area. Batch both.\n- **Carousel first, nearby fallback second:** reads Google's related-place carousel when it exists, then fills short results with places from the source's own category around the same coordinates.\n- **Explicit provenance:** every row says `googleCarousel` or `sameCategoryNearby`; fallback rows are never presented as Google recommendations.\n- **Filters and order:** minimum rating, minimum reviews, maximum straight-line distance, category text, and sort by recommended order, rating, reviews, or distance.\n- **Identity, contacts, and distance:** canonical Place ID, legacy feature ID, CID, KG MID, address, website, phone, plus code, photo count, coordinates, image, and computed `distanceMeters`.\n- **Empty fields are omitted** rather than sent as `null` or guessed.\n\n## Services\n\n| Service | What it returns | Used by |\n|---|---|---|\n| Google Maps place record | Source name, canonical and legacy IDs, category, address, rating, reviews, website, phone, coordinates | both modes |\n| Google Maps related carousel | Up to the cards Google publishes for that place, with names, ratings, reviews, coordinates, images, and visible card text | `byPlace`, `byQuery` |\n| Google Maps same-category search | Ranked places in the source category around the source coordinates, 20 per page | fallback in both modes |\n| Google Maps place details | Canonical Place ID, address, contacts, categories, plus code, photo count, image for one returned place | optional enrichment |\n\n## How it works\n\n1. **Resolve the source.** A place URL provides its feature ID and coordinates directly. A canonical `ChIJ` ID is resolved through Google's public place page in one request. A name query is resolved through Google's map search, preferring the focused result and requiring a name match otherwise.\n2. **Read the source record and carousel.** The same place response carries the source business data and, when Google exposes one, the related-place carousel.\n3. **Decide whether to fall back.** In `auto` mode the fallback runs when the carousel has fewer usable rows than `minSimilar` and the carousel cannot already fill `maxItems`. `carousel` never falls back; `sameCategory` skips the carousel entirely.\n4. **Search the same category nearby.** The fallback uses the source's first category (or `categoryOverride`) anchored at the source coordinates, page by page, until enough places pass the filters, the result window is exhausted, or `maxItems` is reached. Sorting by rating, reviews, or distance considers the full window before the cap is applied.\n5. **Clean the result set.** The source place is removed, filters are applied, identities are deduplicated, and rows are sorted.\n6. **Optionally enrich.** `includeDetails=true` looks up each emitted place's own page for its canonical Place ID, contacts, category, plus code, photo count, and image.\n7. **Push immediately.** Records are emitted as they are finalised, with the global `maxItems` cap. Unresolved inputs are skipped and reported without failing the whole run.\n\n## Input\n\n| Field | Type | Default | Description |\n|---|---|---|---|\n| `mode` | string | `byPlace` | `byPlace` accepts URLs or IDs; `byQuery` accepts place names |\n| `placeUrls` | array | – | Google Maps URLs, `ChIJ…` IDs, or `0x…:0x…` feature IDs (mode=`byPlace`) |\n| `searchQueries` | array | – | Business, hotel, or landmark names (mode=`byQuery`) |\n| `location` | string | – | City or area appended to every name (mode=`byQuery`) |\n| `maxItems` | integer | `100` | Global cap on returned rows (1–500) |\n| `similaritySource` | string | `auto` | `auto`, `carousel`, or `sameCategory` |\n| `minSimilar` | integer | `5` | In `auto`, fall back when the carousel has fewer usable rows than this and cannot fill `maxItems` (0–20) |\n| `categoryOverride` | string | – | Category used by the fallback instead of the source's own |\n| `minRating` | number | – | Drop places below this rating (0–5) |\n| `minReviews` | integer | – | Drop places below this review count |\n| `maxDistanceKm` | number | – | Keep places within this straight-line distance (0.1–50 km) |\n| `categoryFilter` | string | – | Keep places whose category list contains this text |\n| `sortBy` | string | `recommended` | `recommended`, `rating`, `reviews`, or `distance` |\n| `deduplicate` | boolean | `true` | Keep one row per place identity |\n| `includeDetails` | boolean | `true` | Look up each returned place's own page for extra fields |\n| `includeMedia` | boolean | `true` | Include image URLs when Google publishes them |\n| `language` | string | `en` | Maps language: `en`, `es`, `fr`, `de`, `it`, `pt`, `ja`, `ko`, `zh`, `ar`, `ru` |\n\n### Example: related hotels for one place URL\n\n```json\n{\n  \"mode\": \"byPlace\",\n  \"placeUrls\": [\n    \"https://www.google.com/maps/place/The+Ritz+London/@51.5070782,-0.1416273,17z/data=!3m1!4b1!4m6!3m5!1s0x48760529d30fc857:0x596135811e044014!8m2!3d51.5070782!4d-0.1416273!16zL20vMDQ3enJ2?hl=en\"\n  ],\n  \"maxItems\": 20,\n  \"similaritySource\": \"auto\",\n  \"minSimilar\": 5\n}\n```\n\n### Example: competitors for a restaurant with no carousel\n\n```json\n{\n  \"mode\": \"byPlace\",\n  \"placeUrls\": [\"ChIJ8Q2WSpJZwokRQz-bYYgEskM\"],\n  \"similaritySource\": \"sameCategory\",\n  \"maxItems\": 50,\n  \"includeDetails\": true\n}\n```\n\n### Example: several names in one city, filtered and sorted\n\n```json\n{\n  \"mode\": \"byQuery\",\n  \"searchQueries\": [\"Joe's Pizza\", \"Peter Luger Steak House\"],\n  \"location\": \"New York\",\n  \"minRating\": 4.2,\n  \"minReviews\": 500,\n  \"maxDistanceKm\": 5,\n  \"sortBy\": \"rating\",\n  \"maxItems\": 30\n}\n```\n\n### Example: carousel only, no fallback\n\n```json\n{\n  \"mode\": \"byPlace\",\n  \"placeUrls\": [\"ChIJ4fRwZb25yhQRpHwVijb3LeU\"],\n  \"similaritySource\": \"carousel\",\n  \"includeMedia\": false,\n  \"maxItems\": 10\n}\n```\n\n## Output\n\nEvery row is one related place:\n\n- `relationMode` — `googleCarousel` or `sameCategoryNearby`\n- `relationQuery` — category used by the fallback, when applicable\n- `relatedSectionType` — Google's own section label when the response exposes one\n- `rank` — 1-based position in the returned order\n- `name` — related place name\n- `placeId` — canonical `ChIJ…` Place ID, only when Google publishes one\n- `featureId` — legacy `0x…:0x…` feature ID, never used in place of `placeId`\n- `cid`, `kgmid` — other observed identities\n- `googleMapsUrl` — link to the related place\n- `categoryName`, `categories` — primary category and full observed list\n- `totalScore`, `reviewsCount` — rating and review count\n- `address`, `website`, `phone` — contacts when Google publishes them\n- `plusCode`, `photoCount` — detail fields when enrichment is enabled\n- `price` — visible carousel price string, kept exactly as shown\n- `description` — visible carousel comparison text\n- `distance` — visible carousel distance badge\n- `distanceMeters` — straight-line distance from the source coordinates, in metres\n- `latitude`, `longitude` — related place coordinates\n- `image` — image URL at a larger size, when available\n- `sourceBusinessName`, `sourcePlaceId`, `sourceFeatureId`, `sourcePlaceUrl` — the place you searched\n- `sourceCategory`, `sourceAddress`, `sourceLatitude`, `sourceLongitude` — source context\n- `sourceUrl` — alias of `sourcePlaceUrl` for older integrations\n- `recordType` — always `similarPlace`\n- `scrapedAt` — ISO timestamp\n\n## Use cases\n\n- **Local SEO and competitive analysis** — compare the places Google associates with a client's listing, or the competitors around its pin.\n- **Market and category research** — expand a handful of seed businesses into a wider set of nearby places in the same category.\n- **Lead and partner discovery** — collect contacts, websites, and ratings for businesses around a target area.\n- **Data enrichment** — attach canonical Place IDs, categories, and coordinates to an existing list of businesses.\n- **Recommendation feeds** — build a \"places like this\" list from Google's own related signal plus a transparent fallback.\n\n## Usage cost\n\n- No Google API key, no billing account, and no paid API calls are required.\n- The actor runs in 1024 MB and needs no browser.\n- A small run with `includeDetails=false` returns in seconds. `includeDetails=true` adds one place lookup per returned row, so large `maxItems` values take longer.\n- `maxItems` is a hard cap: the actor stops when it reaches it, when Google's result window is exhausted, or when every input is resolved. Filters are counted before the cap, so they do not shorten the result set while eligible places remain.\n- `sortBy=rating`, `reviews`, or `distance` reads the full nearby window before selecting rows; `recommended` stops as soon as the cap is met.\n\n## FAQ\n\n**Why did `carousel` mode return no rows?** Google does not show a related-place carousel for many signed-out place pages. `carousel` is truthful about that; use `auto` or `sameCategory` when you need rows.\n\n**Are fallback rows Google recommendations?** No. They are places in the source's category near the source coordinates. `relationMode` says `sameCategoryNearby`, and `relationQuery` shows the category used.\n\n**How many carousel results can I get?** Google typically publishes 3–5 cards, and sometimes none. That is the whole carousel; no setting can make Google show more.\n\n**How many same-category places are available?** Google returns 20 per page and the observed window is around 104 unique places for a dense query. Sparse categories or small towns exhaust sooner.\n\n**Why is `address` or `website` missing from a carousel row?** The carousel does not carry contacts. Turn on `includeDetails` to look up each place's own page; if Google still does not publish the field, it is omitted.\n\n**Why does `distanceMeters` differ from the distance badge on the card?** The badge is Google's own display string. `distanceMeters` is a straight-line calculation from the source coordinates to the related place coordinates.\n\n**Why are prices in an unexpected currency?** The carousel price is Google's localized display string for the request location. It is kept raw, not converted or normalised.\n\n**Can I use a Place ID instead of a URL?** Yes. Canonical `ChIJ…` IDs work in `placeUrls`, and legacy `0x…:0x…` feature IDs are accepted too.\n\n**Do I need a proxy or cookies?** No. The actor reads public place data and selects a working connection automatically.\n\n**What happens if one input is invalid?** That input is skipped and reported in the status message; the other inputs still run. If no input resolves, the run fails with a clear message instead of returning an empty success.\n\n## Notes\n\n- `price`, `description`, `distance`, and `relatedSectionType` are emitted only when Google's response actually carries them.\n- A canonical `ChIJ…` value always goes to `placeId`; a legacy `0x…:0x…` value always goes to `featureId`. They are never relabelled.\n- `sourceUrl` remains an alias of `sourcePlaceUrl` so older integrations keep working.\n- Duplicate identities are removed by default: canonical Place ID first, then feature ID, then name plus rounded coordinates.\n- In `auto` mode, carousel rows and fallback rows can both appear; `relationMode` separates them.\n\n## Limitations\n\n- **The carousel is conditional.** Most signed-out place pages show no related carousel at all. The actor cannot create one; it uses the honest same-category fallback instead.\n- **Fallback relevance depends on category.** If the source category is broad or wrong, nearby results can be broad too. Use `categoryOverride` or `categoryFilter` to narrow them.\n- **The nearby window is finite.** Google stops returning new places after roughly 100 unique results for a dense query, and sooner for sparse categories.\n- **No similarity score.** Google does not publish one, and the actor does not invent one.\n- **Detail fields are optional and conditional.** `includeDetails` improves coverage, but a field Google does not publish is omitted rather than fabricated.\n",
      "minMemoryMbytes": 1024,
      "maxMemoryMbytes": 1024,
      "input": {
        "title": "Google Maps Similar Places Input",
        "description": "Find related places Google Maps shows for a business, or discover same-category competitors near it.",
        "type": "object",
        "schemaVersion": 1,
        "properties": {
          "mode": {
            "title": "Mode",
            "type": "string",
            "description": "Choose how to enter the source places.",
            "editor": "select",
            "enum": [
              "byPlace",
              "byQuery"
            ],
            "enumTitles": [
              "By place URL or Place ID",
              "By place name and location"
            ],
            "default": "byPlace",
            "prefill": "byPlace"
          },
          "placeUrls": {
            "title": "Place URLs or IDs",
            "type": "array",
            "description": "Google Maps place URLs, canonical ChIJ Place IDs, or legacy 0x…:0x… feature IDs. Mixed values are allowed (mode=byPlace).",
            "editor": "stringList",
            "prefill": [
              "https://www.google.com/maps/place/The+Ritz+London/@51.5070782,-0.1416273,17z/data=!3m1!4b1!4m6!3m5!1s0x48760529d30fc857:0x596135811e044014!8m2!3d51.5070782!4d-0.1416273!16zL20vMDQ3enJ2?hl=en"
            ],
            "example": [
              "ChIJ8Q2WSpJZwokRQz-bYYgEskM",
              "https://maps.app.goo.gl/example"
            ]
          },
          "searchQueries": {
            "title": "Place names",
            "type": "array",
            "description": "Business, hotel, or landmark names to resolve and analyze (mode=byQuery).",
            "editor": "stringList",
            "example": [
              "Joe's Pizza",
              "The Ritz London"
            ]
          },
          "location": {
            "title": "Location",
            "type": "string",
            "description": "City or area appended to every place name (mode=byQuery).",
            "editor": "textfield",
            "example": "New York"
          },
          "maxItems": {
            "title": "Max results",
            "type": "integer",
            "description": "Maximum number of similar places to return across all sources.",
            "minimum": 1,
            "maximum": 500,
            "default": 100,
            "prefill": 3
          },
          "similaritySource": {
            "title": "Related places source",
            "type": "string",
            "description": "Auto uses Google's related carousel and falls back to same-category nearby places when the carousel has fewer than Min similar. Carousel never uses the fallback. Same category skips the carousel.",
            "editor": "select",
            "enum": [
              "auto",
              "carousel",
              "sameCategory"
            ],
            "enumTitles": [
              "Auto (carousel, then same category)",
              "Google carousel only",
              "Same category nearby only"
            ],
            "default": "auto",
            "prefill": "auto"
          },
          "minSimilar": {
            "title": "Min similar",
            "type": "integer",
            "description": "In auto mode, use the same-category fallback when the carousel has fewer usable rows than this number and cannot already fill Max results.",
            "minimum": 0,
            "maximum": 20,
            "default": 5,
            "prefill": 1
          },
          "categoryOverride": {
            "title": "Category override",
            "type": "string",
            "description": "Use this category for the same-category fallback instead of the source place's own category.",
            "editor": "textfield",
            "example": "Pizza restaurant"
          },
          "minRating": {
            "title": "Minimum rating",
            "type": "number",
            "description": "Drop related places rated below this value. Places without a published rating are dropped when this is above zero.",
            "minimum": 0,
            "maximum": 5,
            "example": 4.5
          },
          "minReviews": {
            "title": "Minimum reviews",
            "type": "integer",
            "description": "Drop related places with fewer than this many reviews.",
            "minimum": 0,
            "maximum": 1000000,
            "example": 1000
          },
          "maxDistanceKm": {
            "title": "Maximum distance (km)",
            "type": "number",
            "description": "Keep only related places within this straight-line distance from the source. Requires published coordinates.",
            "minimum": 0.1,
            "maximum": 50,
            "example": 2
          },
          "categoryFilter": {
            "title": "Category contains",
            "type": "string",
            "description": "Keep only places whose category list contains this text (case-insensitive).",
            "editor": "textfield",
            "example": "Hotel"
          },
          "sortBy": {
            "title": "Sort by",
            "type": "string",
            "description": "Order of the returned rows. Recommended keeps Google's carousel and search order.",
            "editor": "select",
            "enum": [
              "recommended",
              "rating",
              "reviews",
              "distance"
            ],
            "enumTitles": [
              "Recommended (Google order)",
              "Highest rating",
              "Most reviews",
              "Closest first"
            ],
            "default": "recommended",
            "prefill": "recommended"
          },
          "deduplicate": {
            "title": "Remove duplicates",
            "type": "boolean",
            "description": "Keep one row per place, using the canonical Place ID, then the feature ID, then name and coordinates.",
            "default": true,
            "prefill": true
          },
          "includeDetails": {
            "title": "Include details",
            "type": "boolean",
            "description": "Look up each returned place's own page for its canonical Place ID, address, website, phone, categories, plus code, photo count, and image. Adds one request per row and slows dense runs.",
            "default": true,
            "prefill": false
          },
          "includeMedia": {
            "title": "Include images",
            "type": "boolean",
            "description": "Include the image URL when Google publishes one.",
            "default": true,
            "prefill": true
          },
          "language": {
            "title": "Language",
            "type": "string",
            "description": "Google Maps interface language. Affects names, categories, and the fallback category query.",
            "editor": "select",
            "enum": [
              "en",
              "es",
              "fr",
              "de",
              "it",
              "pt",
              "ja",
              "ko",
              "zh",
              "ar",
              "ru"
            ],
            "enumTitles": [
              "English",
              "Spanish",
              "French",
              "German",
              "Italian",
              "Portuguese",
              "Japanese",
              "Korean",
              "Chinese",
              "Arabic",
              "Russian"
            ],
            "default": "en",
            "prefill": "en"
          }
        },
        "required": []
      },
      "output": {
        "actorOutputSchemaVersion": 1,
        "title": "Google Maps Related Place & Competitor Finder Output",
        "description": "One row per related place, with its explicit relation provenance (Google carousel or same-category nearby), canonical and legacy identifiers, category, rating, reviews, contacts, coordinates, image, straight-line distance, and a back-reference to the source place.",
        "properties": {
          "similarPlaces": {
            "type": "string",
            "title": "Similar Places",
            "description": "Each item is one related place. relationMode says whether Google recommended it (googleCarousel) or it was found nearby in the same category (sameCategoryNearby). Fields Google does not publish are omitted.",
            "template": "{{links.apiDefaultDatasetUrl}}/items"
          }
        }
      },
      "storages": {
        "dataset": {
          "actorSpecification": 1,
          "views": {
            "overview": {
              "title": "Similar Places",
              "transformation": {
                "fields": [
                  "recordType",
                  "relationMode",
                  "relationQuery",
                  "relatedSectionType",
                  "rank",
                  "name",
                  "placeId",
                  "featureId",
                  "kgmid",
                  "cid",
                  "categoryName",
                  "categories",
                  "totalScore",
                  "reviewsCount",
                  "address",
                  "website",
                  "phone",
                  "photoCount",
                  "plusCode",
                  "distanceMeters",
                  "distance",
                  "price",
                  "description",
                  "latitude",
                  "longitude",
                  "image",
                  "sourceBusinessName",
                  "sourcePlaceId",
                  "sourceFeatureId",
                  "sourceCategory",
                  "sourceLongitude",
                  "sourceLatitude",
                  "sourceAddress",
                  "sourcePlaceUrl",
                  "googleMapsUrl",
                  "sourceUrl",
                  "scrapedAt"
                ]
              },
              "display": {
                "component": "table",
                "properties": {
                  "relationMode": {
                    "label": "Relation",
                    "format": "text"
                  },
                  "rank": {
                    "label": "Rank",
                    "format": "number"
                  },
                  "name": {
                    "label": "Related Place",
                    "format": "text"
                  },
                  "categoryName": {
                    "label": "Category",
                    "format": "text"
                  },
                  "totalScore": {
                    "label": "Rating",
                    "format": "number"
                  },
                  "reviewsCount": {
                    "label": "Reviews",
                    "format": "number"
                  },
                  "distanceMeters": {
                    "label": "Distance (m)",
                    "format": "number"
                  },
                  "address": {
                    "label": "Address",
                    "format": "text"
                  },
                  "website": {
                    "label": "Website",
                    "format": "link"
                  },
                  "phone": {
                    "label": "Phone",
                    "format": "text"
                  },
                  "sourceBusinessName": {
                    "label": "Source Business",
                    "format": "text"
                  },
                  "googleMapsUrl": {
                    "label": "Maps URL",
                    "format": "link"
                  },
                  "scrapedAt": {
                    "label": "Scraped At",
                    "format": "datetime"
                  }
                }
              }
            }
          }
        }
      },
      "environmentVariables": {}
    },
    "buildNumber": "1.0.2",
    "imageDigest": "5860f085b23c7cca3345c78d063ed272bf917c0085f15e57880f60e25df91d5e",
    "actVersion": {
      "sourceType": "SOURCE_FILES",
      "buildTag": "latest",
      "versionNumber": "1.0"
    },
    "usage": {
      "ACTOR_COMPUTE_UNITS": 0.013456666666666667
    }
  }
}