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

Download every photo from any Google Maps place: full-resolution image URLs, dimensions, videos, and Street View panoramas. Filter by gallery tab (menu, food & drink, by owner), find places by URL, Place ID, or search, and export as CSV, JSON, or Excel.

- **URL**: https://apify.com/beatanalytics/google-maps-photos-scraper.md
- **Developed by:** [Beat Analytics](https://apify.com/beatanalytics) (community)
- **Categories:** Developer tools, Travel, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.50 / 1,000 photos

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

### Google Maps Photos Scraper -- Download Every Place Photo with Full-Resolution URLs

Extract the complete photo gallery of any Google Maps place -- every image, at full resolution, with width, height, videos, and Street View panoramas. This Google Maps photos scraper paginates through the entire media library (not a bundled sample of 10), filters by gallery tab (menu, food & drink, by owner, and more), and deduplicates photos that appear in multiple tabs. Find places by URL, Place ID, or built-in search, and export your data as JSON, CSV, Excel, XML, or HTML. Use it to download Google Maps photos for local-SEO audits, storefront monitoring, hospitality datasets, or computer-vision training sets.

- [Why use this Google Maps photos scraper?](#why-use-this-google-maps-photos-scraper)
- [What data can you extract from Google Maps photos?](#what-data-can-you-extract-from-google-maps-photos)
- [How to scrape Google Maps photos](#how-to-scrape-google-maps-photos)
- [Input parameters](#input-parameters)
- [Output example](#output-example)
- [How much does it cost to scrape Google Maps photos?](#how-much-does-it-cost-to-scrape-google-maps-photos)
- [Use cases for Google Maps photo data](#use-cases-for-google-maps-photo-data)
- [Integrations and API access](#integrations-and-api-access)
- [Frequently asked questions](#frequently-asked-questions)
- [Related actors](#related-actors)

### Why use this Google Maps photos scraper?

- 🖼️ **The complete gallery, not a sample** -- popular places carry thousands of photos, but general scrapers return only a handful. This scraper paginates through the entire Google Maps media library to exhaustion, so you get every photo the place has -- or exactly as many as you cap it at.
- 🔍 **Full-resolution image URLs** -- every result includes a direct, publicly fetchable image URL at Google's original resolution, along with the exact pixel width and height. No thumbnails, no cropping.
- 🗂️ **Filter by gallery tab** -- scrape a specific Google Maps photo tab: `menu`, `food & drink`, `by owner`, `vibe`, `rooms`, `amenities`, `exterior`, `latest`, and more. Tabs a place doesn't have are skipped automatically.
- 🔄 **Cross-tab deduplication** -- the same photo often appears under several tabs. When you select multiple categories, each photo is returned only once, so you never process or pay for duplicates.
- 🎬 **Photos, videos, and Street View** -- Google galleries mix stills, customer videos (with a direct MP4 URL and duration), and 360° panoramas. Get all of them with a `type` field, or narrow down to photos only.
- 👤 **Owner vs. customer photos** -- use the `by_owner` category to pull only business-uploaded photos, or `from_visitors` for customer uploads.
- 📍 **Built-in place search** -- find places by search query and location (e.g. "hotels" in "Miami") without needing URLs first. All query × location combinations are searched automatically.
- 🔗 **Bulk multi-location input** -- scrape galleries from dozens or hundreds of places in a single run. Provide Google Maps URLs, share links, Place IDs, or Feature IDs -- mix and match freely.
- 💰 **Cost control built in** -- set `maxPhotosPerPlace` to cap spend on high-volume places, and pay only for the media items you actually receive (charging happens after deduplication and filtering).
- 🛡️ **Automatic place deduplication** -- places found through multiple search queries or inputs are scraped only once.
- 💾 **Export as JSON, CSV, Excel, XML, or HTML** -- download your Google Maps photo data in whichever format your workflow requires, all available out of the box on the Apify platform.

### What data can you extract from Google Maps photos?

Google Maps Photos Scraper returns one dataset item per media item, each carrying the image URL, its dimensions, and full place context. Here is the complete list of fields:

**Place information:**

- **placeName** -- name of the Google Maps place (e.g. "Joe's Pizza Broadway")
- **placeFeatureId** -- Google Maps internal feature ID (e.g. `0x89c259ab3c1ef289:0x3b67a41175949f55`)
- **placePlaceId** -- Google Place ID (e.g. `ChIJifIePKtZwokRVZ-UdRGkZzs`)
- **placeUrl** -- canonical Google Maps URL for the place

**Photo data:**

- **category** -- the gallery tab the photo was fetched under (`all`, `menu`, `by_owner`, etc.)
- **type** -- media type: `photo`, `video`, or `streetview`
- **photoId** -- Google's unique identifier for the photo (also the deduplication key)
- **photoUrl** -- full-resolution image URL (the poster frame for videos), publicly fetchable
- **width** -- image width in pixels
- **height** -- image height in pixels
- **videoUrl** -- progressive MP4 URL for videos (null for photos and Street View)
- **duration** -- video duration in milliseconds (null for photos)
- **photoIndex** -- 0-based order of the item within the place

> **Note:** This scraper returns photo **URLs and metadata**, not the image files themselves. The URLs are public and can be downloaded directly with any HTTP client, so you can fetch the bytes yourself if you need them.

### How to scrape Google Maps photos

Getting started takes less than two minutes. Follow these steps to extract your first gallery:

**Step 1: Create a free Apify account**

Sign up at [apify.com](https://apify.com) if you do not have an account yet. Every new account includes free platform credits -- enough to download thousands of Google Maps photos at no cost.

**Step 2: Open the Google Maps Photos Scraper**

Navigate to the [Google Maps Photos Scraper](https://apify.com/beatanalytics/google-maps-photos-scraper) actor page on the Apify Store and click "Try for free" to open it in your Apify Console. A working example (one restaurant URL) is prefilled, so you can get results immediately.

**Step 3: Add your places or search queries**

You have three ways to specify which places to scrape photos for:

- **Place URLs** -- paste Google Maps URLs like `https://www.google.com/maps/place/...` or share links like `https://maps.app.goo.gl/...`
- **Place IDs** -- enter Google Place IDs (e.g. `ChIJifIePKtZwokRVZ-UdRGkZzs`) or Feature IDs (e.g. `0x89c259ab3c1ef289:0x3b67a41175949f55`)
- **Search** -- enter search queries (e.g. "hotels", "restaurants") and locations (e.g. "Miami, FL"). All combinations are searched and every matching place's gallery is scraped.

You can combine all three methods in a single run.

**Step 4: Configure optional settings**

- Set **Max photos per place** to cap how many media items you pull from each place (leave at 0 for the full gallery)
- Choose one or more **Photo categories** to scrape only specific gallery tabs
- Restrict **Media types** to photos, videos, or Street View
- Change the **language** and **country** for the Google region

**Step 5: Click Start and download your data**

Click "Start" to begin. Once the run completes, download your Google Maps photo data in any format: **JSON, CSV, Excel, XML, or HTML**. You can also access the data programmatically via the Apify API, or set up automatic exports to Google Sheets, Dropbox, Amazon S3, and other destinations.

### Input parameters

| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| `placeUrls` | Array of URLs | No* | -- | Google Maps place URLs or share links. Supports full URLs (`google.com/maps/place/...`) and share links (`maps.app.goo.gl/...`). |
| `placeIds` | Array of strings | No* | -- | Google Place IDs (`ChIJ...`) or Feature IDs (`0x...:0x...`). Can be used with or instead of Place URLs. |
| `searchQueries` | Array of strings | No* | -- | Search terms to find places (e.g. `"pizza"`, `"hotels"`). Used together with `searchLocations` -- all combinations are searched. |
| `searchLocations` | Array of strings | No | -- | Locations to search in (e.g. `"New York, NY"`). Used together with `searchQueries`. |
| `maxPlacesPerSearch` | Integer | No | `20` | Maximum number of places to find per search query + location combination. |
| `maxPhotosPerPlace` | Integer | No | `0` (unlimited) | Maximum media items to scrape per place. Set a cap to control cost on high-volume places. |
| `categories` | Array (multi-select) | No | `[]` (all) | Gallery tabs to scrape: `all`, `latest`, `menu`, `food_and_drink`, `vibe`, `rooms`, `amenities`, `exterior`, `from_visitors`, `by_owner`, `videos`, `street_view`. Tabs a place lacks are skipped. |
| `mediaTypes` | Array (multi-select) | No | all | Media types to include: `photo`, `video`, `streetview`. |
| `language` | String | No | `en` | Language code (e.g. `en`, `de`, `es`). Affects category tab names. |
| `country` | String | No | `us` | Country code (e.g. `us`, `de`, `gb`). Affects which Google region is used. |

*At least one of `placeUrls`, `placeIds`, or `searchQueries` (with `searchLocations`) must be provided.

**Category example:** Setting `categories` to `["menu", "by_owner"]` scrapes only the menu tab and owner-uploaded photos, and returns any photo that appears in both only once.

**Cost-control example:** For a landmark with 5,000+ photos, set `maxPhotosPerPlace` to `200` to fetch a representative slice at a predictable cost instead of the entire gallery.

### Output example

Each item in the dataset represents a single photo or video. Results are stored in an Apify dataset and can be exported as **JSON, CSV, Excel, XML, or HTML** directly from the Apify Console, or accessed programmatically via the Apify API. All fields flatten cleanly to tabular formats like CSV and Excel.

```json
{
  "placeName": "Joe's Pizza Broadway",
  "placeFeatureId": "0x89c259ab3c1ef289:0x3b67a41175949f55",
  "placePlaceId": "ChIJifIePKtZwokRVZ-UdRGkZzs",
  "placeUrl": "https://www.google.com/maps/place/?q=place_id:ChIJifIePKtZwokRVZ-UdRGkZzs",
  "category": "all",
  "type": "photo",
  "photoId": "CIABIhDwfabL6z1S16Bd_BwOXpyH",
  "photoUrl": "https://lh3.googleusercontent.com/gps-cs-s/example=w4284-h5712-k-no",
  "width": 4284,
  "height": 5712,
  "videoUrl": null,
  "duration": null,
  "photoIndex": 0
}
````

A video item looks the same, with `type` set to `video` and the video fields populated:

```json
{
  "placeName": "Joe's Pizza Broadway",
  "placeFeatureId": "0x89c259ab3c1ef289:0x3b67a41175949f55",
  "placePlaceId": "ChIJifIePKtZwokRVZ-UdRGkZzs",
  "placeUrl": "https://www.google.com/maps/place/?q=place_id:ChIJifIePKtZwokRVZ-UdRGkZzs",
  "category": "all",
  "type": "video",
  "photoId": "CIHM0ogKEICAgICGgNfJ4wE",
  "photoUrl": "https://lh3.googleusercontent.com/gps-cs-s/example=w1920-h1080-k-no",
  "width": 1920,
  "height": 1080,
  "videoUrl": "https://lh3.googleusercontent.com/gps-cs-s/example=m37",
  "duration": 80340,
  "photoIndex": 12
}
```

### How much does it cost to scrape Google Maps photos?

Google Maps Photos Scraper uses simple, transparent per-result pricing -- you only pay for the media items you actually receive. Charging happens **after** deduplication and filtering, so you are never billed for a photo you don't get.

**$1.50 per 1,000 photos** -- each media item in your dataset counts as one result. A place with 2,000 photos costs **$3.00**. **No actor-start fee** -- unlike some competing scrapers, there is no per-run charge; you pay purely for results.

**Free trial:** Every new Apify account comes with **free platform credits** -- no credit card required. That is enough to download thousands of Google Maps photos at no cost, so you can fully evaluate the scraper and data quality before committing.

**Enterprise plans:** If you need to download Google Maps photos at very high volume -- millions of images across thousands of locations -- reach out to <sales@beatanalytics.org> for custom Enterprise pricing with dedicated support and volume discounts.

### Use cases for Google Maps photo data

Google Maps photo data powers a wide range of business, research, and machine-learning workflows. Here are the most common use cases:

**Local SEO and Google Business Profile audits**

Photo count, freshness, and quality are ranking and conversion factors for local businesses. Audit your own or a client's Google Business Profile gallery, compare owner-uploaded vs. customer photos, and benchmark against competitors found through the built-in search. Track how a gallery grows over time with scheduled runs.

**Storefront and menu monitoring**

Restaurants and retailers can monitor which photos customers are uploading -- menu shots, storefronts, interiors -- and spot outdated or off-brand images. Scrape the `menu` tab to keep an eye on how your menu is represented across customer uploads.

**Hospitality and real-estate datasets**

Hotels, vacation rentals, and venues have rich galleries tagged by room, exterior, and amenities. Use the `rooms`, `exterior`, and `amenities` categories to assemble structured visual datasets for listings, aggregators, or market analysis.

**Computer-vision and ML training sets**

Full-resolution image URLs with width and height metadata make it easy to build large, labeled image datasets for training or fine-tuning models -- food recognition, storefront classification, interior-style detection, and more. Category tabs give you weak labels for free.

**Brand and reputation monitoring**

Track the visual narrative around your brand across locations. Detect inappropriate or misleading photos early, measure the ratio of professional to user-generated content, and keep galleries fresh across every branch or franchise.

**Competitive and market research**

Compare how competitors present themselves visually -- how many photos they have, how recent, and in which categories. Use the search feature to sweep an entire category and location (e.g. "coffee shop" in "Seattle, WA") and pull every gallery in one run.

### Integrations and API access

Google Maps Photos Scraper integrates with the Apify platform ecosystem, giving you programmatic access to your scraped data and the ability to connect it to thousands of external tools.

#### Python

Use the [Apify Python SDK](https://docs.apify.com/sdk/python/) to run the scraper and retrieve results programmatically:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

run_input = {
    "placeUrls": [
        {"url": "https://maps.app.goo.gl/KZLn9FA3aokoiVaP8"}
    ],
    "categories": ["menu", "food_and_drink"],
    "maxPhotosPerPlace": 200,
}

run = client.actor("beatanalytics/google-maps-photos-scraper").call(run_input=run_input)

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"{item['placeName']} - {item['type']} - {item['photoUrl']}")
```

#### JavaScript / Node.js

Use the [Apify JavaScript SDK](https://docs.apify.com/sdk/js/) to integrate Google Maps photo scraping into your Node.js applications:

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

const client = new ApifyClient({ token: "YOUR_API_TOKEN" });

const run = await client.actor("beatanalytics/google-maps-photos-scraper").call({
    searchQueries: ["hotels"],
    searchLocations: ["Miami, FL"],
    maxPlacesPerSearch: 10,
    maxPhotosPerPlace: 100,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.log(`${item.placeName} - ${item.type} - ${item.width}x${item.height}`);
});
```

#### No-code integrations

Connect Google Maps Photos Scraper to thousands of apps without writing code:

- **Make (formerly Integromat)** -- trigger workflows when new photo data is scraped, or schedule regular runs
- **Zapier** -- push photo URLs into Google Sheets, Slack, CRMs, and 5,000+ other apps
- **Webhooks** -- receive an HTTP notification when a run completes, then process the data in your own backend
- **Google Sheets / Amazon S3 / Dropbox** -- export results directly to spreadsheets or cloud storage

#### API endpoints

Every scraper run on Apify exposes RESTful API endpoints for accessing results, checking run status, and managing datasets. See the [Apify API documentation](https://docs.apify.com/api/v2) for the complete reference.

### Frequently asked questions

#### How do I download all photos from a Google Maps place?

Open Google Maps Photos Scraper on Apify, paste the place's Google Maps URL, Place ID, or share link, leave `maxPhotosPerPlace` at 0, and click Start. The scraper paginates through the entire gallery and returns a full-resolution image URL for every photo. Download the results as JSON or CSV, then fetch the image files from the URLs with any HTTP client. See [How to scrape Google Maps photos](#how-to-scrape-google-maps-photos) for a step-by-step guide.

#### Does it download the image files?

No -- the scraper returns image **URLs and metadata** (dimensions, type, category), not the raw image bytes. The `photoUrl` values are public and directly fetchable, so downloading the actual files is a one-line HTTP request per URL in your own code. This keeps runs fast and storage costs low while giving you everything you need to retrieve the images.

#### Is it legal to scrape Google Maps photos?

Web scraping of publicly available data is generally legal in the United States, as affirmed by the 2022 US Ninth Circuit ruling in *hiQ Labs v. LinkedIn*, which established that scraping publicly accessible data does not violate the Computer Fraud and Abuse Act. Google Maps photos are publicly visible without requiring a login or account.

That said, you should always review Google's Terms of Service and consult with legal counsel about your specific use case. Be mindful of copyright and, where applicable, GDPR when photos contain identifiable people. Apify provides the scraping infrastructure, but users are responsible for ensuring their use of scraped data complies with applicable laws and terms of service.

#### How many photos can one place have?

There is no fixed limit -- popular restaurants, hotels, and landmarks routinely have thousands of photos, and major tourist attractions can exceed 10,000. The scraper paginates through the full gallery automatically. For high-volume places, use `maxPhotosPerPlace` to cap how many you pull and control cost.

#### Can I filter to owner photos only?

Yes. Set `categories` to `["by_owner"]` to scrape only business-uploaded photos, or `["from_visitors"]` for customer uploads. You can also target other tabs like `menu`, `food_and_drink`, `rooms`, `exterior`, and `amenities`. Tabs a place doesn't have are skipped automatically.

#### Can I get videos and Street View, or just photos?

The scraper returns photos, customer videos, and Street View / 360° panoramas by default, each tagged with a `type` field. Videos include a direct MP4 `videoUrl` and `duration`. To restrict the output, use the `mediaTypes` parameter -- for example, set it to `["photo"]` for stills only.

#### How is this different from a general Google Maps scraper?

General Google Maps scrapers return a place's full details -- name, address, rating, reviews -- with only a small bundled sample of photos (often just the first 5-10). This actor is a dedicated gallery scraper: it paginates through the **entire** photo library, filters by gallery tab, deduplicates across tabs, and returns per-photo dimensions and video metadata. If you need complete visual coverage of a place, use this scraper; if you need business details or reviews, use the [Google Maps Place Details Scraper](https://apify.com/beatanalytics/google-maps-place-details-scraper) or [Google Maps Reviews Scraper](https://apify.com/beatanalytics/google-maps-reviews-scraper).

#### What export formats are supported?

The scraper outputs data to an Apify dataset. From the Apify Console, you can export the results as **JSON, CSV, Excel (XLSX), XML, or HTML** with a single click. The data is also accessible via the Apify API for programmatic access.

#### Can I scrape photos from multiple places at once?

Yes. Add as many Google Maps URLs, Place IDs, or Feature IDs as you need in a single run, or use the search feature to find many places by query and location. The scraper processes places concurrently and deduplicates any place found through multiple inputs, so bulk photo scraping is fast and efficient with no duplicate work.

#### How often is the data updated?

The scraper fetches live data from Google Maps every time it runs -- no caching, no stale data. To track how a gallery changes over time, schedule the scraper to run on a recurring basis (daily, weekly, or custom cron) using Apify's built-in scheduling feature.

#### What is the difference between Place IDs and Feature IDs?

Google Maps uses two identifier formats. A **Place ID** is a stable identifier that starts with `ChIJ` (e.g. `ChIJifIePKtZwokRVZ-UdRGkZzs`) and is the one used by the Google Places API. A **Feature ID** is an internal identifier in the `0x...:0x...` format found in Google Maps URLs. The scraper accepts both, and it resolves Google Maps URLs and share links automatically.

### Related actors

Building a complete Google Maps dataset? Combine this scraper with our other Google Maps tools:

- **[Google Maps Place Details Scraper](https://apify.com/beatanalytics/google-maps-place-details-scraper)** -- place information (name, address, coordinates, rating, hours, categories, phone, website, attributes), plus search to discover places by query and location.
- **[Google Maps Reviews Scraper](https://apify.com/beatanalytics/google-maps-reviews-scraper)** -- every review for a place with exact ISO 8601 timestamps, star ratings, reviewer info, and business owner responses, plus date-range filtering.

Use the Place Details Scraper to discover places by search query and location, then pass those place URLs to this Photos Scraper and the Reviews Scraper for full visual coverage and customer sentiment.

# Actor input Schema

## `placeUrls` (type: `array`):

Google Maps place URLs or share links to scrape photos for. Supports full URLs (google.com/maps/place/...) and share links (maps.app.goo.gl/...).

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

Google Place IDs (ChIJ...) or Feature IDs (0x...:0x...) to scrape photos for. Can be used instead of or in addition to Place URLs.

## `searchQueries` (type: `array`):

Search terms to find places on Google Maps (e.g. "pizza", "hotels", "dentist"). Used together with Search locations — all combinations of queries and locations are searched.

## `searchLocations` (type: `array`):

Locations to search in (e.g. "New York, NY", "London, UK"). Used together with Search queries — all combinations of queries and locations are searched.

## `maxPlacesPerSearch` (type: `integer`):

Maximum number of places to find per search query + location combination. Each page returns up to 20 results.

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

Maximum number of media items to scrape per place. Leave at 0 to fetch the complete gallery — popular places can have thousands of photos, so set a cap to control cost.

## `categories` (type: `array`):

Which of Google's gallery tabs to scrape. Leave empty (or select "All") for the full gallery. Tabs vary by place type — tabs a place doesn't have are skipped. When multiple tabs are selected, photos appearing in more than one tab are returned only once.

## `mediaTypes` (type: `array`):

Which media types to include. Google galleries mix photos, videos, and Street View / 360° panoramas. Leave all selected for everything, or narrow down to e.g. photos only.

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

Language code (e.g. 'en', 'de', 'es'). Affects the language of category tab names.

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

Country code (e.g. 'us', 'de', 'gb'). Affects which Google region is used for results.

## Actor input object example

```json
{
  "placeUrls": [
    {
      "url": "https://maps.app.goo.gl/KZLn9FA3aokoiVaP8"
    }
  ],
  "maxPlacesPerSearch": 20,
  "maxPhotosPerPlace": 0,
  "categories": [],
  "mediaTypes": [
    "photo",
    "video",
    "streetview"
  ],
  "language": "en",
  "country": "us"
}
```

# Actor output Schema

## `photos` (type: `string`):

All scraped media items with place details, image URLs, and dimensions.

## `csv` (type: `string`):

Photos exported as a CSV file.

# 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 = {
    "placeUrls": [
        {
            "url": "https://maps.app.goo.gl/KZLn9FA3aokoiVaP8"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("beatanalytics/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 = { "placeUrls": [{ "url": "https://maps.app.goo.gl/KZLn9FA3aokoiVaP8" }] }

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

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

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

```

## CLI example

```bash
echo '{
  "placeUrls": [
    {
      "url": "https://maps.app.goo.gl/KZLn9FA3aokoiVaP8"
    }
  ]
}' |
apify call beatanalytics/google-maps-photos-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=beatanalytics/google-maps-photos-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Google Maps Photos Scraper",
        "description": "Download every photo from any Google Maps place: full-resolution image URLs, dimensions, videos, and Street View panoramas. Filter by gallery tab (menu, food & drink, by owner), find places by URL, Place ID, or search, and export as CSV, JSON, or Excel.",
        "version": "1.0",
        "x-build-id": "E4U8X4n892tvLAIWw"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/beatanalytics~google-maps-photos-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-beatanalytics-google-maps-photos-scraper",
                "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/beatanalytics~google-maps-photos-scraper/runs": {
            "post": {
                "operationId": "runs-sync-beatanalytics-google-maps-photos-scraper",
                "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/beatanalytics~google-maps-photos-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-beatanalytics-google-maps-photos-scraper",
                "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",
                "properties": {
                    "placeUrls": {
                        "title": "Place URLs",
                        "type": "array",
                        "description": "Google Maps place URLs or share links to scrape photos for. Supports full URLs (google.com/maps/place/...) and share links (maps.app.goo.gl/...).",
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "placeIds": {
                        "title": "Place IDs",
                        "type": "array",
                        "description": "Google Place IDs (ChIJ...) or Feature IDs (0x...:0x...) to scrape photos for. Can be used instead of or in addition to Place URLs.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "searchQueries": {
                        "title": "Search queries",
                        "type": "array",
                        "description": "Search terms to find places on Google Maps (e.g. \"pizza\", \"hotels\", \"dentist\"). Used together with Search locations — all combinations of queries and locations are searched.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "searchLocations": {
                        "title": "Search locations",
                        "type": "array",
                        "description": "Locations to search in (e.g. \"New York, NY\", \"London, UK\"). Used together with Search queries — all combinations of queries and locations are searched.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxPlacesPerSearch": {
                        "title": "Max places per search",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Maximum number of places to find per search query + location combination. Each page returns up to 20 results.",
                        "default": 20
                    },
                    "maxPhotosPerPlace": {
                        "title": "Max photos per place",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Maximum number of media items to scrape per place. Leave at 0 to fetch the complete gallery — popular places can have thousands of photos, so set a cap to control cost.",
                        "default": 0
                    },
                    "categories": {
                        "title": "Photo categories",
                        "type": "array",
                        "description": "Which of Google's gallery tabs to scrape. Leave empty (or select \"All\") for the full gallery. Tabs vary by place type — tabs a place doesn't have are skipped. When multiple tabs are selected, photos appearing in more than one tab are returned only once.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "all",
                                "latest",
                                "menu",
                                "food_and_drink",
                                "vibe",
                                "rooms",
                                "amenities",
                                "exterior",
                                "from_visitors",
                                "by_owner",
                                "videos",
                                "street_view"
                            ],
                            "enumTitles": [
                                "All",
                                "Latest",
                                "Menu",
                                "Food & drink",
                                "Vibe",
                                "Rooms",
                                "Amenities",
                                "Exterior",
                                "From visitors",
                                "By owner",
                                "Videos",
                                "Street View & 360°"
                            ]
                        },
                        "default": []
                    },
                    "mediaTypes": {
                        "title": "Media types",
                        "type": "array",
                        "description": "Which media types to include. Google galleries mix photos, videos, and Street View / 360° panoramas. Leave all selected for everything, or narrow down to e.g. photos only.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "photo",
                                "video",
                                "streetview"
                            ],
                            "enumTitles": [
                                "Photos",
                                "Videos",
                                "Street View & 360°"
                            ]
                        },
                        "default": [
                            "photo",
                            "video",
                            "streetview"
                        ]
                    },
                    "language": {
                        "title": "Language",
                        "type": "string",
                        "description": "Language code (e.g. 'en', 'de', 'es'). Affects the language of category tab names.",
                        "default": "en"
                    },
                    "country": {
                        "title": "Country",
                        "type": "string",
                        "description": "Country code (e.g. 'us', 'de', 'gb'). Affects which Google region is used for results.",
                        "default": "us"
                    }
                }
            },
            "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
                                    }
                                }
                            },
                            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
