# Google Maps Menu Scraper (No AI Markup) + Allergens (`traveleat/google-maps-menu-scraper`) Actor

$0.1/1K dishes | Turn a Google Maps place into structured dishes: names, prices, ingredients, dietary type and AI-estimated EU-14 allergens and nutrition. Uses your Gemini key; an Outscraper key is advised for photos. Not affiliated with Google.

- **URL**: https://apify.com/traveleat/google-maps-menu-scraper.md
- **Developed by:** [Travel Eat](https://apify.com/traveleat) (community)
- **Categories:** AI, Travel
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.05 / 1,000 dish 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 Menu Scraper (No AI Markup) + Allergens

$0.1/1K dishes | Turn a Google Maps place into structured dishes: names, prices, ingredients, dietary type and AI-estimated EU-14 allergens and nutrition. Uses your Gemini key; an Outscraper key is advised for photos. Not affiliated with Google.

### Google Maps Menu Bulk Scraper

Our scraper takes a Google Maps place and returns the restaurant's menu as one structured record per dish. It reads the place's Menu photos, falls back to the menu on the restaurant's own website when there are none, and parses the menu with AI. Each dish carries a translated name, the printed price, ingredients, a dietary type, estimated EU-14 allergens and nutrition ranges. It is ideal for allergen-aware food apps, delivery and ordering platforms, menu price research and travel products.

- Already have menu photo URLs? Use [AI Restaurant Menu Parser](https://apify.com/traveleat/ai-menu-parser) and skip the Maps step.
- Want the place's food photos matched to the dishes? Chain [Restaurant Dish Photo Matcher](https://apify.com/traveleat/dish-photo-matcher).
- Browse all our scrapers: https://apify.com/traveleat

#### Key Benefits

- Your key, your AI bill: menu parsing runs on your own Google AI Studio key, so you choose the model and control the quota, and Google bills that part to you directly.
- Low pricing: **$0.10 per 1,000 dishes**, plus a $0.00005 start fee per run. Your first successful live run waives up to ten dish charges.
- Allergen-aware rows: estimated EU-14 allergens with a confidence score, a dietary type with an explanation, and nutrition ranges.
- 15 output languages: dish names and descriptions come back translated, with the printed name kept in `originalName`.
- Free to try: the untouched Console run returns one clearly marked demo row, needs no keys and is not billed. A live run with only diagnostic rows has no Actor charge either.

### How It Works

1. Paste one or more Google Maps place URLs into `placeUrls` (e.g., `https://www.google.com/maps/place/Katz's+Delicatessen,+205+E+Houston+St,+New+York`). Short `maps.app.goo.gl` links, place IDs and plain place names work too.
2. Add your keys for a live run:
   - (required for live runs) `geminiApiKey`, a free key from Google AI Studio.
   - (recommended) `outscraperApiKey`. Google hides the Maps photo gallery from automated browsers, so this is the reliable way to fetch a place's Menu photos. Without it the Actor falls back to browser scraping, which currently reaches only the cover photo.
3. Click Start. With the form untouched you get one marked demo row at no cost. Change the input and add your keys to parse a real menu.

More settings:

- `language` - Output language for dish names, descriptions and allergen summaries. Default is `en`.
- `maxMenuPhotos` - Menu photos sent to the AI, from 1 to 20. Default is 8, which covers most menus.
- `geminiModel` - Model that reads the photos. Default is `gemini-2.5-flash`.

Ingredient, allergen, dietary and nutrition fields are AI estimates from the published menu and typical recipes. Verify them with the restaurant or the product label before making allergy, medical or compliance decisions.

A place with no Menu photos and no menu on its website returns a diagnostic row that explains why, with no dish charge.

#### Data You'll Receive

- Dish: translated name, original printed name, category, price as shown (with currency) and a short description.
- Ingredients: base ingredients with an English database name and a translated display name, each with estimated EU-14 allergens and a confidence.
- Diet and nutrition: Vegan, Vegetarian, Pescetarian or Other with an explanation; estimated serving size, calories, protein, fat and carbs; `isAlcoholic` for drinks.
- Context: a short cultural story when the model is confident, otherwise `null`.
- Source: the place URL, the menu photo URLs used and where the menu came from.

#### Sample output data

Here is the example output of the untouched Console run. It is a marked demo row, not a live extraction:

```json
{
  "recordType": "DEMO",
  "isDemo": true,
  "demoSource": "owned-default-prefill",
  "demoNote": "Deterministic preview only: no live source, photo scrape, or Gemini call occurred, and the row was not billed. Customize the input for live output; BYOK listings also require their provider credentials.",
  "name": "DEMO SAMPLE — Margherita Pizza",
  "originalName": "Margherita Pizza",
  "category": "Pizza",
  "price": "$18.00",
  "composition": "Tomato, mozzarella and basil",
  "description": "Example structured menu record; not a live extraction.",
  "ingredients": [],
  "dietaryType": "Vegetarian",
  "dietaryTypeExplanation": "Example classification for preview only.",
  "allergens": "Milk (preview example)",
  "type": "dish",
  "isAlcoholic": false,
  "story": null,
  "nutritionInfo": null,
  "place": "https://www.google.com/maps/place/Katz's+Delicatessen,+205+E+Houston+St,+New+York",
  "menuPhotoUrls": [],
  "menuPhotosFound": 0,
  "menuSource": "demo"
}
```

### Google Maps Menu API

Results are stored in a dataset that you can export as CSV, JSON or Excel, or read through the Apify API. Connect it to Make, n8n or Zapier, or let an agent call it through the Apify MCP server.

#### Support and Feedback

We improve these scrapers from your feedback. If something breaks or you need a field:

- Open an issue on the Actor's Issues tab.
- If this Actor saved you time, a short review on the Store helps other people find it.

### Run evidence

#### Start with one input and output

An Apify account is required. Use your Apify API token when calling the API; Console runs do not need that token pasted into the input. The unchanged default preview requires no provider key and makes no live AI or source call. A customized live run requires your own Gemini key; Maps/Outscraper collection also requires your own Outscraper key. Those providers bill separately.

Free-tier event rates checked 2026-10-08: `result` $0.0001; `actor-start` $0.00005.

**Cost:** Total = Actor event charges + platform usage if separately billed + any BYO-provider charges. See “Current costs” for your event rates, plan tiers and a calculation. A sample does not promise future billable volume.

This matching input/output pair is a **marked DEMO preview**, observed in run `Jo6rq2kFzRKxK3oa0` (immutable build `gXbU98WkRf2D8aiMn`). It demonstrates the output shape and makes no live source or AI-provider call. It does not verify a live parse or synchronization. Keep the preview unchanged; customize it and supply the documented credentials for live work.

**Input JSON**

```json
{
  "placeUrls": [
    "https://www.google.com/maps/place/Katz's+Delicatessen,+205+E+Houston+St,+New+York"
  ],
  "geminiModel": "gemini-2.5-flash",
  "language": "en",
  "maxMenuPhotos": 8,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

**Matching output excerpt**

Long strings and arrays are shortened for display; this is not a complete dataset fixture.

```json
{
  "recordType": "DEMO",
  "isDemo": true,
  "demoSource": "owned-default-prefill",
  "demoNote": "Deterministic preview only: no live source, photo scrape, or Gemini call occurred, and the row was not billed. Customize the input for live output; BYOK listings also require their provider credentials.",
  "name": "DEMO SAMPLE — Margherita Pizza",
  "originalName": "Margherita Pizza",
  "category": "Pizza",
  "price": "$18.00",
  "composition": "Tomato, mozzarella and basil",
  "description": "Example structured menu record; not a live extraction.",
  "ingredients": [],
  "dietaryType": "Vegetarian",
  "dietaryTypeExplanation": "Example classification for preview only.",
  "allergens": "Milk (preview example)",
  "type": "dish",
  "isAlcoholic": false,
  "story": null,
  "nutritionInfo": null,
  "place": "https://www.google.com/maps/place/Katz's+Delicatessen,+205+E+Houston+St,+New+York",
  "menuPhotoUrls": [],
  "menuPhotosFound": 0,
  "menuSource": "demo"
}
```

Give it a Google Maps place URL (or place ID/name) and get back the restaurant's
**menu as structured data**. The actor first collects the place's **Menu**
photos; if none are available, it checks the restaurant website for menu images
or PDFs. It AI-parses the discovered menu into one record per dish:

- `name` (translated to your language) + `originalName` (as printed)
- `category`, `price` (with currency, as shown)
- `ingredients` — AI-inferred base ingredients, each with an English database
  name, translated display name, and **estimated EU-14 allergens with confidence**
  (gluten, crustaceans, eggs, fish, peanuts, soy, milk, nuts, celery,
  mustard, sesame, sulfites, lupin, molluscs)
- `dietaryType` — Vegan / Vegetarian / Pescetarian / Other, with explanation
- `nutritionInfo` — estimated serving size, calories, protein, fat, carbs
- `story` — well-established cultural context when confident, otherwise `null`
- `isAlcoholic` for beverages

#### Why this actor

Generic Google Maps scrapers focus on reviews and opening hours. This actor
turns a published menu into a richer structured research dataset with
AI-estimated ingredient and dietary fields, allergen confidence scores,
nutrition ranges, and translations in 15 languages.

#### Bring your own Gemini key

Menu parsing runs on **your** Google AI Studio key
([get one free](https://aistudio.google.com/apikey)) — you control the AI
cost and quota. A typical menu runs a few cents on Gemini 2.5 Flash, or a
fraction of that on Flash-Lite.

#### Input example

```json
{
  "placeUrls": ["https://www.google.com/maps/place/Katz's+Delicatessen,+205+E+Houston+St,+New+York"],
  "geminiApiKey": "AIza…",
  "language": "en",
  "maxMenuPhotos": 8
}
```

#### Photo source: add an Outscraper key (recommended)

Since 2026 Google's signed-out "limited view" hides the Maps photo gallery
from automated browsers, so set the `outscraperApiKey` input
([free tier available](https://app.outscraper.com/profile)) — the actor then
fetches the place's full tagged photo set (including the Menu photos) via
Outscraper's API, no browser or proxy involved. Without it, the actor falls
back to browser scraping, which currently reaches only the cover photo.

#### Notes

- The untouched keyless Console run returns one deterministic row labelled
  `recordType: "DEMO"` / `isDemo: true`. It makes no Maps, Outscraper or
  Gemini call and is not billed. Customize the input and add your Gemini key
  (plus an Outscraper key for reliable place-photo retrieval) for live output.
- Live pricing is listed in “Current costs” below. The first successful live run waives up to ten dish events; the actor-start event still applies.
- A live run that produces only diagnostic rows has **$0 in Actor charges**.
  Dishes are saved before any Actor charge is attempted.
- In browser-fallback mode, use the **Apify residential proxy** (default) —
  Google rate-limits datacenter IPs.
- Places with neither Google Maps menu photos nor a website menu yield a
  non-billed diagnostic row explaining why.
- `maps.app.goo.gl` short links are resolved to a trusted Google Maps URL.
  Output keeps the original `place` and exposes the canonical URL as
  `resolvedPlaceUrl` when resolution was needed.
- Ingredient, allergen, dietary, and nutrition fields are AI estimates from
  the published menu and typical recipes. Verify them with the restaurant or
  product label before making allergy, medical, or compliance decisions.
- Already have menu photo URLs? Use the companion **AI Restaurant Menu
  Parser** actor and skip the browser. Want the place's food photos matched
  to these dishes? Chain the **Restaurant Dish Photo Matcher** actor.
- Don't want to manage API keys at all? The
  [managed twin](https://apify.com/traveleat/google-maps-menu-scraper-managed)
  is the same scraper with photo fetching and AI cost included in its
  per-dish price — zero setup.

#### Support & links

- Questions, bug reports and FAQ:
  [github.com/Exdenta/traveleat-support](https://github.com/Exdenta/traveleat-support)
- This actor runs the same menu pipeline as [Travel Eat](https://traveleat.app) —
  scan a menu, get allergens, ingredients and dietary filters in 36 languages.

#### Product guides and related tools

- [Product overview and public links](https://jobatlas.dev/actors/directory/menus-and-photos#nomad-agent-google-maps-menu-scraper)
- [Public setup guide](https://github.com/Exdenta/jobatlas/blob/main/docs/public-actors-setup.md)
- [Travel Eat menu API guide](https://traveleat.app/blog/ai-menu-parser-api)
- [Menu API documentation and support](https://github.com/Exdenta/traveleat-support)
- [AI Restaurant Menu Parser — Dishes, Prices & Allergens](https://apify.com/traveleat/ai-menu-parser)
- [Restaurant Dish Photo Matcher — Photos to Menu Items](https://apify.com/traveleat/dish-photo-matcher)

#### Current costs

Current Actor event rates, checked 2026-10-08. USD; use the **Pricing** tab for your plan and later changes.

| Event | Free | Bronze | Silver | Gold | Platinum | Diamond |
|---|---:|---:|---:|---:|---:|---:|
| Dish extracted (`result`) | $0.0001 | $0.0001 | $0.0001 | $0.0001 | $0.0001 | $0.0001 |
| Actor start (`actor-start`) | $0.00005 | $0.00005 | $0.00005 | $0.00005 | $0.00005 | $0.00005 |

For example, 100 × `result`, 1 × `actor-start` totals **$0.01005 in Actor event charges on Free**. This is an arithmetic example, before any waiver; actual charged events depend on the run and selected options. It is not a promise of output or a charge for simply setting an item cap.

Your total is the charged Actor events, plus platform usage **only if this Actor’s Pricing tab bills it separately**, plus any external provider you use with your own key. Do not add platform usage twice when it is included. Apify credits and plan discounts affect your invoice. Set a run cost limit in Console before starting.

As documented, the first successful live run waives up to ten per-dish events; the actor-start event still applies. The untouched prefilled sample is a marked demo, not a live parse. Empty/failed diagnostic output creates no Actor billing events.

#### Agent setup skill

Use the maintained [SKILL.md](https://github.com/Exdenta/jobatlas/blob/main/.agents/skills/public-apify-actors/SKILL.md) to configure the documented inputs, select `latest`, record the immutable build and distinguish source results from preview or diagnostic rows. Check the current Pricing tab before starting a run.

***

**Independent tool.** We built and run this Actor ourselves. Google does not operate, sponsor or endorse it, and its name is used only to say which service the data comes from.

# Actor input Schema

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

Paste one or more full Google Maps place URLs. maps.app.goo.gl short links are resolved automatically; bare place IDs and names are also accepted. The untouched default returns one clearly marked, $0 demo row.

## `geminiApiKey` (type: `string`):

Your Google AI Studio API key — get a free one at <a href='https://aistudio.google.com/apikey'>aistudio.google.com/apikey</a>. Menu parsing runs on YOUR key, so you control the AI cost (a menu typically costs well under $0.01 on Gemini Flash).

## `outscraperApiKey` (type: `string`):

API key from <a href='https://app.outscraper.com/profile'>app.outscraper.com</a> (free tier available). Google's signed-out "limited view" hides the Maps photo gallery from browsers, so this is the reliable way to fetch a place's tagged photos. Without it, the actor falls back to browser scraping, which currently reaches only the cover photo.

## `geminiModel` (type: `string`):

Model used to read the menu photos.

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

Language for dish names, descriptions, stories and allergen summaries (ingredient database names stay English).

## `maxMenuPhotos` (type: `integer`):

How many of the place's menu photos are sent to the AI. 8 covers most menus; raise it for very long menus.

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

Proxy used to open Google Maps. Google rate-limits datacenter IPs, so the Apify residential proxy is recommended.

## Actor input object example

```json
{
  "placeUrls": [
    "https://www.google.com/maps/place/Katz's+Delicatessen,+205+E+Houston+St,+New+York"
  ],
  "geminiModel": "gemini-2.5-flash",
  "language": "en",
  "maxMenuPhotos": 8,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `items` (type: `string`):

The run's dataset items (see the dataset schema for the field-by-field structure).

# 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": [
        "https://www.google.com/maps/place/Katz's+Delicatessen,+205+E+Houston+St,+New+York"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("traveleat/google-maps-menu-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": ["https://www.google.com/maps/place/Katz's+Delicatessen,+205+E+Houston+St,+New+York"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("traveleat/google-maps-menu-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 '{
  "placeUrls": [
    "https://www.google.com/maps/place/Katz'\''s+Delicatessen,+205+E+Houston+St,+New+York"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call traveleat/google-maps-menu-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,traveleat/google-maps-menu-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/40ta5VDhcUsSbBMHl/builds/RTuTplu5ZntBernYN/openapi.json
