# Restaurant Menu Photos to Dish JSON — Managed AI (`nomad-agent/ai-menu-parser-managed`) Actor

Turn JPEG/PNG/WebP menu photos into dish JSON with names, prices and categories. Upload files or pass image URLs/base64; no AI API key. Translated names plus AI-estimated ingredients, allergens and nutrition. PDF pages must be converted to images first.

- **URL**: https://apify.com/nomad-agent/ai-menu-parser-managed.md
- **Developed by:** [Nomad Dev](https://apify.com/nomad-agent) (community)
- **Categories:** AI, Automation
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.20 / 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.

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

## Restaurant Menu Photos to Dish JSON — Managed AI

Turn JPEG, PNG or WebP menu photos into dish JSON with printed names, prices and categories. Upload photos or pass accessible image URLs/base64; no AI API key is required. Convert PDF pages to images first. Ingredients, allergens and nutrition are AI estimates; verify them with the venue.

### 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. No Gemini key is required: the Actor owner pays for AI. Use JPEG, PNG or WebP images; convert PDFs to images first.

Free-tier event rates checked 2026-10-04: `actor-start` $5e-05; `result` $0.0002.

**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.

Input and output below were read from the same successful run `t36MQ9D8a5YUfLJs0` (2026-09-07, immutable build `TQVh4sXSgbtGo9God`). This is an observed example, not a guarantee that repeating it returns this row. It used an earlier build; current-build execution has not been proved by this example.

**Input JSON**

```json
{
  "imageUrls": [
    "https://raw.githubusercontent.com/Exdenta/traveleat-support/main/docs/assets/menu-demo-small.jpg"
  ],
  "geminiModel": "gemini-2.5-flash",
  "language": "es"
}
```

**Matching output excerpt**

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

```json
{
  "recordType": "DISH",
  "name": "Desayuno estilo Cracovia",
  "originalName": "KRAKOWSKIE",
  "category": "Desayunos",
  "price": "34 zł",
  "composition": "Obwarzanek, pasta de huevo con cebollino, requesón con atún, hummus",
  "description": "Un desayuno tradicional polaco que combina sabores salados y frescos, servido con un pan crujiente y untables cremosos.",
  "ingredients": [
    {
      "name": "pretzel",
      "display_name": "Obwarzanek",
      "explanation": "Un tipo de pan trenzado, similar a un pretzel, tradicional de Cracovia.",
      "allergens": [
        {
          "name": "gluten",
          "confidence": "high"
        }
      ]
    },
    {
      "name": "egg pasta",
      "display_name": "Pasta de huevo",
      "explanation": null,
      "allergens": [
        {
          "name": "gluten",
          "confidence": "high"
        },
        {
          "name": "eggs",
          "confidence": "high"
        }
      ]
    }
  ],
  "dietaryType": "Pescetarian",
  "dietaryTypeExplanation": "Contiene atún (pescado) y productos lácteos (requesón).",
  "allergens": "Gluten, Huevos, Leche, Pescado, Sésamo",
  "type": "dish",
  "isAlcoholic": false,
  "story": "El obwarzanek es un pan tradicional polaco, similar a un bagel o pretzel, que es un símbolo culinario de Cracovia y se vende comúnmente en las calles de la ciudad.",
  "nutritionInfo": {
    "serving_size_grams": "400-500g",
    "calories": "600-800 kcal",
    "protein": "30-40g",
    "fat": "30-45g",
    "carbs": "50-70g"
  },
  "sourceImageUrls": [
    "https://raw.githubusercontent.com/Exdenta/traveleat-support/main/docs/assets/menu-demo-small.jpg"
  ],
  "sourceImageRefs": [
    "https://raw.githubusercontent.com/Exdenta/traveleat-support/main/docs/assets/menu-demo-small.jpg"
  ]
}
```

Ingredients, allergens, nutrition and translations are AI estimates. Verify dietary safety with the venue; the example is not medical or allergy advice.

Upload menu photos (or send URLs/base64 through JSON), get back the menu as
**structured JSON** — one record per dish. **No AI-provider key or provider signup required**: the AI runs on our key and its cost is already included in the
per-dish price.

- `name` (translated to your language) + `originalName` (as printed)
- `category`, `price` (with currency, as shown)
- `ingredients` — atomic base ingredients (composite preparations like
  pesto or hummus are decomposed), each with an English database name,
  translated display name, and **EU-14 allergens with confidence levels**
- `dietaryType` — Vegan / Vegetarian / Pescetarian / Other, with explanation
- `nutritionInfo` — estimated serving size, calories, protein, fat, carbs
- `story` — origin story / cultural significance
- `isAlcoholic` for beverages

15 output languages. The prompt is the production pipeline of a
dietary-restrictions travel app — battle-tested on real menus worldwide.

### Input example

```json
{
  "imageUrls": ["https://example.com/menu-page-1.jpg", "https://example.com/menu-page-2.jpg"],
  "language": "en"
}
```

That's the whole input. Run it.

### Pricing and empty runs

Check this Actor’s **Pricing** tab for the current charges for your Apify plan. Actor-start and per-dish events apply to successful live output. Your first live run waives up to 10 per-dish charges; the actor-start charge still applies. The exact untouched prefilled sample returns a clearly marked DEMO row without calling Gemini and creates no Actor billing events; check Pricing for separately billed platform usage.

Empty and failed parses produce a `diagnostic: true` row with a human-readable
`message` and create no Apify billing events.

### Notes

- The Console accepts local JPEG, PNG, or WebP uploads directly. API callers
  may use HTTP(S) URLs, base64 data URIs, or raw base64 in `imageUrls`.
- Each decoded image is limited to 10 MiB. Inline payloads and signed URL
  credentials are replaced with safe references in output records and logs.
- **First live run allowance**: up to 10 per-dish charges are waived; the
  actor-start charge still applies. The untouched prefilled DEMO is separate
  and completely free.
- Up to 20 images per run, parsed together as one menu.
- Unreadable items are skipped rather than guessed; empty results produce a
  non-billed diagnostic row explaining why.
- Don't have menu photos yet? The companion **Google Maps Menu Scraper**
  actor finds them from a Google Maps place URL and parses them in one run.
- Prefer to pay Google directly and control your own quota? The
  **AI Restaurant Menu Parser (BYO Gemini key)** Actor lets you supply
  a `geminiApiKey` and manage provider usage directly. Compare its Pricing
  tab and your provider charges before choosing.

### Safety

Allergen, dietary, ingredient and nutrition fields are AI-generated estimates.
They can be wrong and do not account reliably for substitutions or kitchen
cross-contact. Verify critical information with the restaurant; do not rely on
this output as medical advice or as the sole safeguard for a severe allergy.

### 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-ai-menu-parser-managed)
- [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)
- [Dish Photo Matcher — Google Maps Food Photos to Menu Items](https://apify.com/nomad-agent/dish-photo-matcher-managed)

### Current costs

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

| Event | Free | Bronze | Silver | Gold | Platinum | Diamond |
|---|---:|---:|---:|---:|---:|---:|
| Actor start (`actor-start`) | $5e-05 | $5e-05 | $5e-05 | $5e-05 | $5e-05 | $5e-05 |
| Dish extracted (`result`) | $0.0002 | $0.0002 | $0.0002 | $0.0002 | $0.0002 | $0.0002 |

For example, 1 × `actor-start`, 100 × `result` totals **$0.02005 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.

# Actor input Schema

## `imageUrls` (type: `array`):

Upload menu photos or provide direct image URLs (JPEG/PNG/WebP, 10 MiB per image). API/JSON callers may also pass base64 data URIs or raw base64 strings in imageUrls. All images are parsed as one menu — up to 20 per run. The untouched owned sample returns a free, clearly marked DEMO preview; replace it with your own images for a live paid parse.

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

Model used to read the menu photos. The AI cost is included in the price either way.

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

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

## Actor input object example

```json
{
  "imageUrls": [
    "https://raw.githubusercontent.com/Exdenta/traveleat-support/main/docs/assets/menu-demo-small.jpg"
  ],
  "geminiModel": "gemini-2.5-flash",
  "language": "en"
}
```

# 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 = {
    "imageUrls": [
        "https://raw.githubusercontent.com/Exdenta/traveleat-support/main/docs/assets/menu-demo-small.jpg"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("nomad-agent/ai-menu-parser-managed").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 = { "imageUrls": ["https://raw.githubusercontent.com/Exdenta/traveleat-support/main/docs/assets/menu-demo-small.jpg"] }

# Run the Actor and wait for it to finish
run = client.actor("nomad-agent/ai-menu-parser-managed").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 '{
  "imageUrls": [
    "https://raw.githubusercontent.com/Exdenta/traveleat-support/main/docs/assets/menu-demo-small.jpg"
  ]
}' |
apify call nomad-agent/ai-menu-parser-managed --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nomad-agent/ai-menu-parser-managed"
        }
    }
}
```

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/vU3BLmDBOHLrGEW3S/builds/FKmMBB1RglXwoo7L7/openapi.json
