# Google Maps Business Photo Annotator — AI Vision (`rainminer/google-maps-images-annotator`) Actor

Fetch Google Maps business photos and annotate each image with AI vision — scene type, caption, tags, OCR text, dishes, amenities, ambiance, colors, and quality scores. Paste a place ID, search query, or Maps URL; export structured JSON for listings, hospitality research, and local SEO workflows.

- **URL**: https://apify.com/rainminer/google-maps-images-annotator.md
- **Developed by:** [rainminer](https://apify.com/rainminer) (community)
- **Categories:** AI, Agents, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $9.90 / 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

The **Google Maps Business Photo Annotator** is an Apify Actor that turns **Google Maps business photos** into structured, machine-readable annotations. Provide a place ID, search query, or Maps URL — the Actor fetches photos and analyzes each image with **Gemini vision AI**. Every photo becomes a dataset row with scene type, caption, tags, OCR text, dishes, amenities, ambiance, dominant colors, quality score, and safety flags.

Run it on the Apify platform for **API access**, **scheduling**, **monitoring**, and **integrations** — no browser or proxy setup required.

---

### Key Features

- **Google Maps photo fetching** — retrieves business photos from place IDs, search queries, or Maps URLs.
- **AI vision annotations** — Gemini analyzes each photo for scene, caption, tags, OCR, dishes, and amenities.
- **Flexible queries** — place IDs, search text, google_id, CID, or full Maps URLs.
- **Photo filters** — fetch all photos, latest, menu-tagged, or owner-uploaded images.
- **Custom prompts and schemas** — tune the AI vision prompt or supply your own JSON Schema for output.
- **Graceful failure handling** — skips broken image URLs and continues.
- **Pay-per-event pricing** — billed per successfully annotated photo.

---

### Why Annotate Google Maps Business Photos?

Google Maps is the largest local-business photo pool on the web, but raw photo URLs tell you little about **what is actually in the image**. Restaurants, hotels, retail, and service businesses upload photos of food, interiors, menus, and signage — valuable signals for:

- **Hospitality and retail research** — cuisine style, decor, seating, cleanliness cues.
- **Local SEO and listings QA** — audit photo quality and relevance before publishing.
- **Competitive intelligence** — compare visual positioning across nearby businesses.
- **Menu and signage OCR** — extract readable text from menu boards and price lists.
- **Dataset enrichment** — add vision metadata to existing Google Maps place datasets.

---

### How to Use Google Maps Business Photo Annotator

1. **Create a free Apify account** at [apify.com](https://apify.com/).
2. **Open the Actor** in Apify Console and go to the **Input** tab.
3. **Add one or more queries** — a Google place ID, search string (e.g. `pizza brooklyn`), or Maps URL.
4. **Set photos per place** — start with `3–10` for testing to control cost.
5. **Run the Actor** and download results from the **Output** tab as JSON, CSV, or Excel.

---

### Input

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `queries` | string[] | — | **Required.** Place ID, search text, google_id, CID, or Maps URL. |
| `photosLimit` | integer | `10` | Max photos to fetch and annotate per place. |
| `placesPerQuery` | integer | `1` | Max places returned per query. |
| `tag` | enum | `all` | Photo filter: `all`, `latest`, `menu`, or `by_owner`. |
| `prompt` | string | (see default) | System prompt for Gemini vision annotation. |
| `annotationSchema` | object | — | Optional custom JSON Schema for AI output. |

**Example input:**

```json
{
  "queries": ["ChIJZ2rw6ac5qBQRKgoWMAqIY3E"],
  "photosLimit": 5,
  "placesPerQuery": 1,
  "tag": "all"
}
````

***

### Output

Each dataset row represents **one annotated photo**:

```json
{
  "name": "Example Restaurant",
  "placeId": "ChIJZ2rw6ac5qBQRKgoWMAqIY3E",
  "googleId": "0x865b39a69a2c3667",
  "fullAddress": "123 Main St, Austin, TX",
  "locationLink": "https://www.google.com/maps/place/?q=place_id:ChIJ...",
  "photoId": "CIHM0ogK...",
  "photoUrl": "https://lh5.googleusercontent.com/...",
  "latitude": 30.2672,
  "longitude": -97.7431,
  "tag": "all",
  "query": "ChIJZ2rw6ac5qBQRKgoWMAqIY3E",
  "sceneType": "food",
  "caption": "Plated pasta on a wooden table",
  "tags": ["pasta", "italian", "fine_dining"],
  "detectedText": "Spaghetti Carbonara — €14",
  "dishes": ["spaghetti carbonara"],
  "amenities": ["outdoor_seating"],
  "ambiance": "cozy, dim lighting",
  "dominantColors": ["#3b2f2f", "#d9c2a3"],
  "qualityScore": 0.82,
  "hasPeople": false,
  "safetyFlag": "none",
  "annotatedAt": "2026-06-13T12:00:00.000Z"
}
```

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

***

### Data Fields

| Field | Description |
| --- | --- |
| `name` | Business name from Google Maps |
| `placeId` | Google place ID |
| `photoUrl` | High-resolution photo URL |
| `sceneType` | Scene category: interior, exterior, food, menu, etc. |
| `caption` | One-sentence description of the photo |
| `tags` | Searchable keyword tags |
| `detectedText` | OCR text read from the image |
| `dishes` | Food or drink items visible |
| `amenities` | Visible amenities (seating, bar, parking, etc.) |
| `ambiance` | Decor and lighting description |
| `dominantColors` | Hex color codes |
| `qualityScore` | Photo quality score from 0 to 1 |
| `hasPeople` | Whether people are visible |
| `safetyFlag` | Content safety flag |
| `annotatedAt` | ISO timestamp of annotation |

***

### Pricing

The Actor uses **pay-per-event** pricing — one **image-annotated** event per successfully annotated photo. Start with a low `photosLimit` (3–5) to estimate costs before scaling. Keep query count and `placesPerQuery` modest for faster runs.

***

### Tips

- Use **place IDs** for the most precise results; text searches may return multiple businesses when `placesPerQuery` > 1.
- Set `tag` to `menu` for restaurants when you only want menu board photos.
- Keep `photosLimit` low during testing to control annotation volume.
- For custom workflows, supply `annotationSchema` to define your own JSON output shape, or edit `prompt` to steer the AI.

***

### FAQ and Support

**Do I need a Google Maps API key?** No. The Actor handles photo retrieval internally.

**Do I need a Gemini API key?** No. AI annotation uses the platform secret configured for this Actor.

**What if a photo URL fails to download?** The Actor logs a warning and continues with the next photo.

**Is scraping Google Maps legal?** This Actor analyzes publicly available business photos. Ensure your use complies with applicable laws and terms of service.

For issues or feature requests, use the **Issues** tab on Apify Store. Need a custom annotation schema or batch pipeline? Contact us through Apify support.

### Image Credit

Image credit: [Google Maps](https://www.google.com/maps/)

# Actor input Schema

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

Google Maps search text, place\_id, google\_id, CID, or Maps URL. Up to 1000 per run.

## `photosLimit` (type: `integer`):

Maximum number of photos to fetch and annotate per place.

## `placesPerQuery` (type: `integer`):

Maximum number of places returned per query.

## `tag` (type: `string`):

Which Google Maps photo tag to fetch.

## `prompt` (type: `string`):

System prompt for Gemini vision annotation. Annotate only what is visible; use null for uncertain fields.

## `annotationSchema` (type: `object`):

Optional JSON Schema for custom per-image AI output. When omitted, a fixed annotation schema is used.

## Actor input object example

```json
{
  "queries": [
    "ChIJZ2rw6ac5qBQRKgoWMAqIY3E"
  ],
  "photosLimit": 10,
  "placesPerQuery": 1,
  "tag": "all",
  "prompt": "You are an expert visual analyst of Google Maps business photos. Annotate only what is clearly visible in the image. Use null for fields when information is not visible or uncertain. Do not infer cuisine, brand names, or text that is not readable. For OCR (detectedText), transcribe only text you can actually read. For dishes, list only food items clearly shown. Rate qualityScore from 0 to 1 based on sharpness, lighting, and usefulness for a business listing. Set hasPeople true only when people are clearly visible (faces may be blurred). Set safetyFlag to sensitive only for clearly inappropriate content; otherwise none. Analyze this Google Maps business photo and return structured annotations for everything clearly visible."
}
```

# Actor output Schema

## `overview` (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 = {
    "queries": [
        "ChIJZ2rw6ac5qBQRKgoWMAqIY3E"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("rainminer/google-maps-images-annotator").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 = { "queries": ["ChIJZ2rw6ac5qBQRKgoWMAqIY3E"] }

# Run the Actor and wait for it to finish
run = client.actor("rainminer/google-maps-images-annotator").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 '{
  "queries": [
    "ChIJZ2rw6ac5qBQRKgoWMAqIY3E"
  ]
}' |
apify call rainminer/google-maps-images-annotator --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Google Maps Business Photo Annotator — AI Vision",
        "description": "Fetch Google Maps business photos and annotate each image with AI vision — scene type, caption, tags, OCR text, dishes, amenities, ambiance, colors, and quality scores. Paste a place ID, search query, or Maps URL; export structured JSON for listings, hospitality research, and local SEO workflows.",
        "version": "1.0",
        "x-build-id": "iiHlPeCK55HVqIsFC"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/rainminer~google-maps-images-annotator/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-rainminer-google-maps-images-annotator",
                "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/rainminer~google-maps-images-annotator/runs": {
            "post": {
                "operationId": "runs-sync-rainminer-google-maps-images-annotator",
                "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/rainminer~google-maps-images-annotator/run-sync": {
            "post": {
                "operationId": "run-sync-rainminer-google-maps-images-annotator",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "queries"
                ],
                "properties": {
                    "queries": {
                        "title": "Queries",
                        "type": "array",
                        "description": "Google Maps search text, place_id, google_id, CID, or Maps URL. Up to 1000 per run.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "photosLimit": {
                        "title": "Photos per place",
                        "minimum": 1,
                        "maximum": 100,
                        "type": "integer",
                        "description": "Maximum number of photos to fetch and annotate per place.",
                        "default": 10
                    },
                    "placesPerQuery": {
                        "title": "Places per query",
                        "minimum": 1,
                        "maximum": 500,
                        "type": "integer",
                        "description": "Maximum number of places returned per query.",
                        "default": 1
                    },
                    "tag": {
                        "title": "Photo tag filter",
                        "enum": [
                            "all",
                            "latest",
                            "menu",
                            "by_owner"
                        ],
                        "type": "string",
                        "description": "Which Google Maps photo tag to fetch.",
                        "default": "all"
                    },
                    "prompt": {
                        "title": "AI vision prompt",
                        "type": "string",
                        "description": "System prompt for Gemini vision annotation. Annotate only what is visible; use null for uncertain fields.",
                        "default": "You are an expert visual analyst of Google Maps business photos. Annotate only what is clearly visible in the image. Use null for fields when information is not visible or uncertain. Do not infer cuisine, brand names, or text that is not readable. For OCR (detectedText), transcribe only text you can actually read. For dishes, list only food items clearly shown. Rate qualityScore from 0 to 1 based on sharpness, lighting, and usefulness for a business listing. Set hasPeople true only when people are clearly visible (faces may be blurred). Set safetyFlag to sensitive only for clearly inappropriate content; otherwise none. Analyze this Google Maps business photo and return structured annotations for everything clearly visible."
                    },
                    "annotationSchema": {
                        "title": "Custom annotation schema",
                        "type": "object",
                        "description": "Optional JSON Schema for custom per-image AI output. When omitted, a fixed annotation schema is used."
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
