Bulk Google Maps Photo Download, One Row Per Photo
Every photo a place has on Google Maps, as structured rows: full-size URL, thumbnail, gallery position, and a stable ID you can dedupe on.
When to use this skill
- The user wants to "download google maps photos" for a business, or for many businesses at once.
- They need imagery for a directory, listings site, travel app, or training dataset.
- They want a "google maps images api" or "place photos api" they can call from code.
- They already have Google Maps URLs or place identifiers and want the galleries behind them.
Not for: Street View and 360 panoramas (use the companion apify-google-street-view-api skill), place details like ratings and hours (johnvc/google-maps-places-api), or review text (johnvc/google-maps-contributor-reviews-api). See references/actor-index.md.
What you get
One dataset row per photo. result_type separates the row kinds:
image (full-size URL) and thumbnail (smaller preview of the same shot)
position, where it sits in the place's gallery
photo_id, stable across runs, which is what makes scheduled refreshes cheap
data_id and place_title, the place the photo belongs to
category_id when a gallery filter was applied
- one
place_summary row per place with photos_returned, pages_fetched, and place_categories
It does not return captions, EXIF, contributor names, or upload dates.
Prerequisites
The Actor
Run it with the Apify CLI
One place by name:
apify actors call "johnvc/google-maps-photos-api" -i '{"searchTerm":"Mozart Coffee Roasters, Austin TX","maxPlacesPerSearch":1,"maxPhotosPerPlace":20}' \
--json \
--user-agent apify-awesome-skills/apify-google-maps-photo-download \
2>/dev/null
Sweep a category across a city:
apify actors call "johnvc/google-maps-photos-api" -i '{"searchTerm":"coffee shops in Austin, TX","maxPlacesPerSearch":10,"maxPhotosPerPlace":20}' \
--json \
--user-agent apify-awesome-skills/apify-google-maps-photo-download \
2>/dev/null
Skip the search charge with URLs you already hold:
apify actors call "johnvc/google-maps-photos-api" -i '{"placeUrls":["https://www.google.com/maps/place/..."],"maxPhotosPerPlace":40}' \
--json \
--user-agent apify-awesome-skills/apify-google-maps-photo-download \
2>/dev/null
Confirm live pricing and the input schema before a large batch:
apify actors info "johnvc/google-maps-photos-api" --json \
--user-agent apify-awesome-skills/apify-google-maps-photo-download \
2>/dev/null
Every call carries the three flags this repo expects: --json, --user-agent apify-awesome-skills/apify-google-maps-photo-download, and 2>/dev/null.
Run it from Claude or another AI agent (MCP)
The Actor is MCP-ready. Add the hosted server URL:
https://mcp.apify.com/?tools=actors,docs,johnvc/google-maps-photos-api
Then ask, for example: "Download every photo for the three highest-rated ramen places in Austin and list the full-size URLs." MCP setup docs: https://docs.apify.com/platform/integrations/mcp
Workflow
- Pick the cheapest way in. A Google Maps URL or a place identifier costs nothing to resolve; a
searchTerm adds one search charge.
- Bound the sweep with
maxPlacesPerSearch (default 3, max 20) and the depth with maxPhotosPerPlace (default 20).
- Run, then split rows on
result_type: photo, place_summary, error.
- Store
photo_id alongside each image. On the next run, skip IDs you already hold.
- Re-host anything you plan to display; the Google-hosted URLs can rotate.
Inputs
searchTerm (string): a place name, or a category plus a city
searchTerms (array): several searches in one run
placeUrls (array): Google Maps URLs, parsed locally at no API cost
dataId / dataIds (string, array): place identifiers you already hold
maxPlacesPerSearch (integer, default 3, max 20): how wide a search sweeps
maxPhotosPerPlace (integer, default 20, max 1000): how deep per place
photoCategory (enum all, latest, videos, by_owner, street_view, menu, food_and_drink, vibe, default all)
categoryId (string): a venue-specific section ID taken from a place_summary row
hl (string, default en): interface language
Cost
Billing is pay per event, plus a negligible platform fee per dataset row. Prices below are the BRONZE tier at the time of writing; confirm live prices with the info command above.
- About $0.0015 per photo returned.
- About $0.012 per search term, and nothing when you pass URLs or identifiers instead.
- About $0.001 to start a run.
- A 10-place sweep at 20 photos each is about $0.32.
Suggested confirmation thresholds: warn the user over about $5; get explicit confirmation over about $20. Present cost as "around $X", never a guarantee.
Honest limits
- Gallery size varies enormously, from a handful at a small office to several hundred at a busy restaurant. Photos arrive in blocks of twenty.
menu, food_and_drink, and vibe exist only on food and drink venues; the other five categories work anywhere.
- No captions, EXIF, contributor names, or upload dates, so there is no way to filter by when a photo was taken.
- No historical imagery. This returns the current gallery, not what the place looked like years ago.
- Image URLs are Google-hosted and can rotate, so hotlinking them long term is unreliable.
Troubleshooting
- Fewer photos than
maxPhotosPerPlace: the place has that many, and photos_returned on the summary row confirms it.
- A category returns nothing: it is probably food-venue only. Read
place_categories on the summary row to see what that place actually offers.
- Search matched the wrong place: add the city and state to
searchTerm, or pass the Google Maps URL directly.
- An
error row: clean failure, stated plainly; retry once before investigating.
See references/gotchas.md for cost guardrails and error recovery, and references/actor-index.md for the Actor routing table.
Related Actors
1---2name: apify-google-maps-photo-download3description: Bulk google maps photo download with the Apify Google Maps Photos API Actor (johnvc/google-maps-photos-api). Name a place, paste a Google Maps URL, or search a category and city, and get one row per photo with the full-size image url, a thumbnail, its gallery position, and a stable photo id you can de-duplicate on across runs. One run sweeps up to 20 places, so a whole neighbourhood of businesses comes back in a single pass instead of one right-click at a time. Filter to a gallery section when you only want menus, interiors, or owner uploads. Use when the user wants to download google maps photos, bulk place images, a google maps images api, place photos api access, or imagery for a directory, listings site, or dataset. Pay per photo returned, MCP-ready for Claude and other AI agents.4license: MIT5---67# Bulk Google Maps Photo Download, One Row Per Photo89Every photo a place has on Google Maps, as structured rows: full-size URL, thumbnail, gallery position, and a stable ID you can dedupe on.1011## When to use this skill1213- The user wants to "download google maps photos" for a business, or for many businesses at once.14- They need imagery for a directory, listings site, travel app, or training dataset.15- They want a "google maps images api" or "place photos api" they can call from code.16- They already have Google Maps URLs or place identifiers and want the galleries behind them.1718Not for: Street View and 360 panoramas (use the companion apify-google-street-view-api skill), place details like ratings and hours (`johnvc/google-maps-places-api`), or review text (`johnvc/google-maps-contributor-reviews-api`). See `references/actor-index.md`.1920## What you get2122One dataset row per photo. `result_type` separates the row kinds:2324- `image` (full-size URL) and `thumbnail` (smaller preview of the same shot)25- `position`, where it sits in the place's gallery26- `photo_id`, stable across runs, which is what makes scheduled refreshes cheap27- `data_id` and `place_title`, the place the photo belongs to28- `category_id` when a gallery filter was applied29- one `place_summary` row per place with `photos_returned`, `pages_fetched`, and `place_categories`3031It does not return captions, EXIF, contributor names, or upload dates.3233## Prerequisites3435- Apify account (sign up at https://apify.com?fpr=9n7kx3&fp_sid=awesomeskills).36- Authentication via `apify login`, or an `APIFY_TOKEN` environment variable (Apify Console, Settings, Integrations).3738## The Actor3940- Store page: https://apify.com/johnvc/google-maps-photos-api?fpr=9n7kx3&fp_sid=awesomeskills41- Actor ID: `johnvc/google-maps-photos-api`42- Pricing: pay per event; see the cost section below and `references/gotchas.md` for live-price commands.4344## Run it with the Apify CLI4546One place by name:4748```bash49apify actors call "johnvc/google-maps-photos-api" -i '{"searchTerm":"Mozart Coffee Roasters, Austin TX","maxPlacesPerSearch":1,"maxPhotosPerPlace":20}' \50 --json \51 --user-agent apify-awesome-skills/apify-google-maps-photo-download \52 2>/dev/null53```5455Sweep a category across a city:5657```bash58apify actors call "johnvc/google-maps-photos-api" -i '{"searchTerm":"coffee shops in Austin, TX","maxPlacesPerSearch":10,"maxPhotosPerPlace":20}' \59 --json \60 --user-agent apify-awesome-skills/apify-google-maps-photo-download \61 2>/dev/null62```6364Skip the search charge with URLs you already hold:6566```bash67apify actors call "johnvc/google-maps-photos-api" -i '{"placeUrls":["https://www.google.com/maps/place/..."],"maxPhotosPerPlace":40}' \68 --json \69 --user-agent apify-awesome-skills/apify-google-maps-photo-download \70 2>/dev/null71```7273Confirm live pricing and the input schema before a large batch:7475```bash76apify actors info "johnvc/google-maps-photos-api" --json \77 --user-agent apify-awesome-skills/apify-google-maps-photo-download \78 2>/dev/null79```8081Every call carries the three flags this repo expects: `--json`, `--user-agent apify-awesome-skills/apify-google-maps-photo-download`, and `2>/dev/null`.8283## Run it from Claude or another AI agent (MCP)8485The Actor is MCP-ready. Add the hosted server URL:8687`https://mcp.apify.com/?tools=actors,docs,johnvc/google-maps-photos-api`8889Then ask, for example: "Download every photo for the three highest-rated ramen places in Austin and list the full-size URLs." MCP setup docs: https://docs.apify.com/platform/integrations/mcp9091## Workflow92931. Pick the cheapest way in. A Google Maps URL or a place identifier costs nothing to resolve; a `searchTerm` adds one search charge.942. Bound the sweep with `maxPlacesPerSearch` (default 3, max 20) and the depth with `maxPhotosPerPlace` (default 20).953. Run, then split rows on `result_type`: `photo`, `place_summary`, `error`.964. Store `photo_id` alongside each image. On the next run, skip IDs you already hold.975. Re-host anything you plan to display; the Google-hosted URLs can rotate.9899## Inputs100101- `searchTerm` (string): a place name, or a category plus a city102- `searchTerms` (array): several searches in one run103- `placeUrls` (array): Google Maps URLs, parsed locally at no API cost104- `dataId` / `dataIds` (string, array): place identifiers you already hold105- `maxPlacesPerSearch` (integer, default 3, max 20): how wide a search sweeps106- `maxPhotosPerPlace` (integer, default 20, max 1000): how deep per place107- `photoCategory` (enum `all`, `latest`, `videos`, `by_owner`, `street_view`, `menu`, `food_and_drink`, `vibe`, default `all`)108- `categoryId` (string): a venue-specific section ID taken from a `place_summary` row109- `hl` (string, default `en`): interface language110111## Cost112113Billing is pay per event, plus a negligible platform fee per dataset row. Prices below are the BRONZE tier at the time of writing; confirm live prices with the info command above.114115- About $0.0015 per photo returned.116- About $0.012 per search term, and nothing when you pass URLs or identifiers instead.117- About $0.001 to start a run.118- A 10-place sweep at 20 photos each is about $0.32.119120Suggested confirmation thresholds: warn the user over about $5; get explicit confirmation over about $20. Present cost as "around $X", never a guarantee.121122## Honest limits123124- Gallery size varies enormously, from a handful at a small office to several hundred at a busy restaurant. Photos arrive in blocks of twenty.125- `menu`, `food_and_drink`, and `vibe` exist only on food and drink venues; the other five categories work anywhere.126- No captions, EXIF, contributor names, or upload dates, so there is no way to filter by when a photo was taken.127- No historical imagery. This returns the current gallery, not what the place looked like years ago.128- Image URLs are Google-hosted and can rotate, so hotlinking them long term is unreliable.129130## Troubleshooting131132- Fewer photos than `maxPhotosPerPlace`: the place has that many, and `photos_returned` on the summary row confirms it.133- A category returns nothing: it is probably food-venue only. Read `place_categories` on the summary row to see what that place actually offers.134- Search matched the wrong place: add the city and state to `searchTerm`, or pass the Google Maps URL directly.135- An `error` row: clean failure, stated plainly; retry once before investigating.136137See `references/gotchas.md` for cost guardrails and error recovery, and `references/actor-index.md` for the Actor routing table.138139## Related Actors140141- Google Maps Places API: https://apify.com/johnvc/google-maps-places-api?fpr=9n7kx3&fp_sid=awesomeskills142- Google Maps Contributor Reviews API: https://apify.com/johnvc/google-maps-contributor-reviews-api?fpr=9n7kx3&fp_sid=awesomeskills143- Google Maps Directions API: https://apify.com/johnvc/google-maps-directions-api?fpr=9n7kx3&fp_sid=awesomeskills144- Apple Maps API: https://apify.com/johnvc/apple-maps-api?fpr=9n7kx3&fp_sid=awesomeskills