# Google Maps Photos Scraper (`fetch_cat/google-maps-photos-scraper`) Actor

Extract public Google Maps place photos, thumbnails, URLs, and visible metadata from place URLs or search queries.

- **URL**: https://apify.com/fetch_cat/google-maps-photos-scraper.md
- **Developed by:** [Fetch Cat](https://apify.com/fetch_cat) (community)
- **Categories:** Lead generation, Business, Marketing
- **Stats:** 19 total users, 7 monthly users, 99.8% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.82 / 1,000 photo extracteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Google Maps Photos Scraper

Google Maps Photos Scraper exports public **Google Maps place photos** from URLs, share links, Place IDs, and search queries to JSON, CSV, Excel, or an API.

### What does Google Maps Photos Scraper do?

Google Maps Photos Scraper exports public Google-hosted photo URLs and visible place metadata from Google Maps place pages and search results. It captures both visible gallery images and the photo metadata delivered to the browser, while keeping the visible-page path as a fallback. Runs deduplicate photos, save progress, and report target-level warnings instead of discarding valid results when one place fails.

### Who is it for? Common use cases

- Local SEO agencies auditing business profile photo coverage
- Hospitality, restaurant, and retail teams monitoring public place media
- Lead generation teams enriching place lists with visual signals
- Reputation/media auditors comparing competitor photos by location
- Analysts building datasets of public Maps photo links for review

### What data can it export?

- Public Google-hosted photo URLs and thumbnail URLs
- Stable photo IDs for deduplication across places and retries
- Place name and resolved Google Maps URL
- Query or URL that produced each record
- Photo order/rank, visible dimensions, captions, and contributor labels when shown
- Google Maps identifiers when present in the public URL

### Input recipes

#### Single landmark or business

```json
{
  "queries": ["Statue of Liberty National Monument"],
  "maxPhotosPerPlace": 10,
  "includeSearchDiscovery": true,
  "maxConcurrency": 1,
  "proxyConfiguration": { "useApifyProxy": false }
}
```

#### Category and location monitoring

```json
{
  "queries": ["pizza near Times Square New York"],
  "maxPhotosPerPlace": 25,
  "includeSearchDiscovery": true,
  "maxConcurrency": 1
}
```

#### Existing Google Maps URLs

```json
{
  "startUrls": [
    { "url": "https://www.google.com/maps/search/Eiffel+Tower" }
  ],
  "maxPhotosPerPlace": 10
}
```

#### Place ID with original-resolution URLs

```json
{
  "placeIds": ["ChIJLU7jZClu5kcR4PcOOO6p3I0"],
  "imageSize": "original",
  "language": "en",
  "country": "FR",
  "maxPhotosPerPlace": 20
}
```

### Example output

```json
{
  "placeName": "Statue of Liberty",
  "placeUrl": "https://www.google.com/maps/place/...",
  "placeId": "0x89c25090129c363d:0x40c6a5770d25022b",
  "cid": null,
  "query": "Statue of Liberty National Monument",
  "rank": 1,
  "photoId": "79d631fd633b36afc9bf1218",
  "photoUrl": "https://lh3.googleusercontent.com/...=w2048-h2048-k-no",
  "thumbnailUrl": "https://lh3.googleusercontent.com/...=w320-h320-k-no",
  "imageWidth": 408,
  "imageHeight": 544,
  "category": null,
  "caption": "Photo of Statue of Liberty",
  "contributorName": null,
  "extractionSource": "photometa",
  "scrapedAt": "2026-07-10T10:00:00.000Z"
}
```

### Input settings

| Field | Type | Description |
| --- | --- | --- |
| `startUrls` | array | Google Maps place URLs, search URLs, or `maps.app.goo.gl` share links. |
| `placeIds` | array | Place IDs (`ChIJ...`), feature IDs (`0x...:0x...`), or numeric CIDs. |
| `queries` | array | Place names or category + location searches. |
| `maxPhotosPerPlace` | integer | Maximum photo records to save per input. |
| `imageSize` | string | `thumbnail`, `medium`, `large` (the backward-compatible default), or `original`. |
| `includeSearchDiscovery` | boolean | Include visible search-result thumbnails before a result resolves to a single place. |
| `language` | string | Google Maps language code, such as `en`, `de`, or `pt`. |
| `country` | string | Two-letter country code used to regionalize results. |
| `allowEmptyResults` | boolean | Allow a successful zero-row run. Disabled by default so blocks and source changes are not hidden. |
| `maxRunSeconds` | integer | Work deadline from 60 to 270 seconds; the Actor reserves 30 seconds for checkpointing. |
| `maxConcurrency` | integer | Browser pages in parallel; keep low for Google Maps reliability. |
| `proxyConfiguration` | object | Optional Apify Proxy settings. Start without proxy or with datacenter; use residential only if your run is blocked. |

### Output fields

| Field | Description |
| --- | --- |
| `placeName` | Visible Google Maps place name when available. |
| `placeUrl` | Resolved Maps URL used for extraction. |
| `placeId`, `cid` | Google Maps identifiers when present in the URL. |
| `query` | Query that produced the record, if any. |
| `rank` | Photo order within the input page. |
| `photoId` | Deterministic photo identifier used for cross-target and retry deduplication. |
| `photoUrl` | Google-hosted photo URL at the requested resolution. |
| `thumbnailUrl` | Google-hosted 320 px preview URL. |
| `imageWidth`, `imageHeight` | Visible image dimensions when available. |
| `category` | Visible album/category label when available. |
| `caption` | Visible alt text or aria label when available. |
| `contributorName` | Public contributor/owner label when visible. |
| `extractionSource` | `dom` for a visible image or `photometa` for browser-delivered photo metadata. |
| `scrapedAt` | ISO timestamp for the scrape. |

### Pricing

This Actor uses pay-per-event pricing. A one-time run-start event covers initialization, and a photo event is charged only for each successfully saved photo row. Failed targets, duplicate photos, and error or status messages are not charged as photo records.

See the live [Pricing tab](https://apify.com/fetch_cat/google-maps-photos-scraper/pricing) for current event rates and subscription-tier discounts.

### Tips for best results

- Use specific place names with city/location, such as `Hotel Chelsea New York`.
- For category monitoring, use queries such as `coffee shops near Shibuya Tokyo` and keep `includeSearchDiscovery` enabled.
- Keep `maxPhotosPerPlace` low for first tests, then scale after confirming output quality.
- Use `placeIds` when you need deterministic place resolution across scheduled runs.
- Leave `allowEmptyResults` disabled unless an empty gallery is a valid business result.
- If Google blocks requests in your region, enable Apify Proxy in the input.

### Limits and legality

This Actor extracts public photo URLs and visible public metadata. It does not log in, bypass paywalls, download private content, or collect hidden account data. Run it only for workloads you are authorized to process, and follow applicable platform terms, privacy requirements, and local law. Google Maps can change its public interface or limit traffic; all-empty runs therefore fail by default instead of silently appearing successful.

### API usage

#### Node.js

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('fetch_cat/google-maps-photos-scraper').call({
  queries: ['Statue of Liberty National Monument'],
  maxPhotosPerPlace: 10
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient('YOUR_APIFY_TOKEN')
run = client.actor('fetch_cat/google-maps-photos-scraper').call(run_input={
    'queries': ['Statue of Liberty National Monument'],
    'maxPhotosPerPlace': 10,
})
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

#### cURL

```bash
curl -X POST 'https://api.apify.com/v2/acts/fetch_cat~google-maps-photos-scraper/runs?token=YOUR_APIFY_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"queries":["Statue of Liberty National Monument"],"maxPhotosPerPlace":10}'
```

### MCP and agent usage

Use this actor from agents through Apify MCP:

```text
https://mcp.apify.com?tools=fetch_cat/google-maps-photos-scraper
```

Claude CLI example:

```bash
claude mcp add apify https://mcp.apify.com?tools=fetch_cat/google-maps-photos-scraper
```

JSON configuration example:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=fetch_cat/google-maps-photos-scraper"
    }
  }
}
```

Example prompts:

- "Collect public Google Maps photos for these five hotel URLs."
- "Find visible photo thumbnails for pizza places near Times Square."
- "Export Maps photo URLs for this landmark query as JSON."

### Related actors

#### More Google scrapers

- [Google Hotels Scraper](https://apify.com/fetch_cat/google-hotels-scraper)
- [Google News Scraper](https://apify.com/fetch_cat/google-news-scraper)
- [Google Scholar Profiles Scraper](https://apify.com/fetch_cat/google-scholar-profiles-scraper)
- [Google Autocomplete Scraper](https://apify.com/fetch_cat/google-autocomplete-scraper)
- [Google People Also Ask & Related Questions Scraper](https://apify.com/fetch_cat/google-people-also-ask-scraper)

### FAQ

**Does it download image files?**\
No. It exports public image URLs and thumbnails; you can download files separately if your use case allows it.

**Can it scrape private photos?**\
No. Only public Google Maps media visible without login is in scope.

**Why are some fields empty?**\
Google Maps does not expose every label, contributor, or category in every visible page state. Empty optional fields mean the value was not public/visible during the run.

**Why did a zero-photo run fail?**
An all-empty result can mean an unavailable place, a consent or traffic block, or a Google Maps interface change. The Actor fails so monitoring workflows notice. Set `allowEmptyResults` only when zero photos is expected.

**Can a stopped run continue safely?**
Yes. Multi-target runs store `RUN_CHECKPOINT` with pending targets and seen photo IDs. A resurrected run resumes without charging the start event again or saving the same photo twice.

### Support

If you need help, open an issue on the Apify actor page and include:

- Input JSON you used
- Expected output
- Actual output or dataset sample
- Reproducible public URL (for example, a public Google Maps URL) or query
- Run ID and error message, if any

# Changelog

This Actor's version history is a separate document: https://apify.com/fetch_cat/google-maps-photos-scraper/changelog.md

# Actor input Schema

## `startUrls` (type: `array`):

Public Google Maps place URLs, search URLs, or maps.app.goo.gl share links. Up to 100 unique targets can be combined across all input lists.

## `placeIds` (type: `array`):

Google Place IDs (`ChIJ...`), feature IDs (`0x...:0x...`), or numeric CIDs. You can combine these with URLs and queries.

## `queries` (type: `array`):

Place names or category + location searches, for example `pizza near Times Square New York`.

## `includeSearchDiscovery` (type: `boolean`):

When enabled, search pages can return visible discovery thumbnails. Disable it to resolve the first matching place before collecting its gallery.

## `language` (type: `string`):

Language code used by Google Maps, for example `en`, `de`, `fr`, or `pt`.

## `country` (type: `string`):

Two-letter country code used to regionalize search results, for example `US`, `GB`, `DE`, or `PT`.

## `maxPhotosPerPlace` (type: `integer`):

Maximum number of unique photo records to save from each URL, place ID, or query.

## `imageSize` (type: `string`):

Choose the requested Google-hosted image size. `large` preserves the Actor's previous 2048 px behavior; `original` requests the original image.

## `allowEmptyResults` (type: `boolean`):

When disabled, the Actor fails if every target is empty, blocked, or unavailable. Enable only when zero photos is an expected result for your workflow.

## `maxConcurrency` (type: `integer`):

Number of Google Maps targets processed in parallel. Keep this low to reduce blocking and retry amplification.

## `proxyConfiguration` (type: `object`):

Optional Apify Proxy settings. Start without a proxy or with datacenter traffic; use residential traffic only when your authorized workload requires it.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.google.com/maps/place/Eiffel+Tower/"
    }
  ],
  "placeIds": [],
  "queries": [
    "Statue of Liberty National Monument"
  ],
  "includeSearchDiscovery": true,
  "language": "en",
  "country": "US",
  "maxPhotosPerPlace": 10,
  "imageSize": "large",
  "allowEmptyResults": false,
  "maxConcurrency": 1,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `runSummary` (type: `string`):

No description

## `runCheckpoint` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "startUrls": [
        {
            "url": "https://www.google.com/maps/place/Eiffel+Tower/"
        }
    ],
    "queries": [
        "Statue of Liberty National Monument"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("fetch_cat/google-maps-photos-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "startUrls": [{ "url": "https://www.google.com/maps/place/Eiffel+Tower/" }],
    "queries": ["Statue of Liberty National Monument"],
}

# Run the Actor and wait for it to finish
run = client.actor("fetch_cat/google-maps-photos-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "startUrls": [
    {
      "url": "https://www.google.com/maps/place/Eiffel+Tower/"
    }
  ],
  "queries": [
    "Statue of Liberty National Monument"
  ]
}' |
apify call fetch_cat/google-maps-photos-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fetch_cat/google-maps-photos-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/LNaCS08ADvud96hIn/builds/U5JXjMzSXZMCWi5wl/openapi.json
