# Menu Translator + EU 14 Allergen Detector for Restaurants (`nebulosa/menu-allergen-translator`) Actor

Translate a restaurant menu into 10 languages and flag the 14 EU allergens (Regulation 1169/2011). Paste text or give a menu URL or PDF. Get structured dishes, prices, allergen codes, translations and a printable allergen matrix.

- **URL**: https://apify.com/nebulosa/menu-allergen-translator.md
- **Developed by:** [Nebulosa Data](https://apify.com/nebulosa) (community)
- **Categories:** AI, Travel, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## 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

## Menu Translator + EU 14 Allergen Detector for restaurants

Translate a **restaurant menu into 10 languages** and detect the **14 EU allergens** (Regulation (EU) No 1169/2011, Annex II) in every dish. Paste the menu text, or give a **menu web page** or **PDF**. You get structured dishes (section, name, description, price), allergen codes, translations, and a **printable allergen matrix** (HTML) you can hand to staff or put next to the menu.

Built for restaurants, bars and hotels with tourists, menu/QR-code platforms, POS integrators, food delivery tools and hospitality agencies.

### Languages

Default output: **English, Spanish, German, French, Italian, Portuguese, Dutch, Polish, Russian, Chinese (Simplified)**. You can request up to 25 languages, e.g. Ukrainian, Catalan, Swedish, Japanese, Korean or Arabic.

### The 14 EU allergens detected

1 Cereals containing gluten · 2 Crustaceans · 3 Eggs · 4 Fish · 5 Peanuts · 6 Soybeans · 7 Milk · 8 Tree nuts · 9 Celery · 10 Mustard · 11 Sesame · 12 Sulphites · 13 Lupin · 14 Molluscs

Detection runs in two layers:

1. A **multilingual rules engine** (EN, ES, DE, FR, IT, PT, NL, PL) with thousands of ingredient and dish terms (*gambas*, *pierogi*, *vongole*, *béchamel*, *tahini*…), exclusions (*nutmeg*, *coconut*, *gluten-free*…) and "may contain" hints for typical recipes (*paella*, *croquetas*, *broths*).
2. An **AI second opinion** (when translation is on) that adds allergens a typical recipe usually contains.

Each allergen comes with `level` (`contains` / `may_contain`), the matched `evidence`, and its `sources` (`rules`, `ai`).

### Output per dish

```json
{
  "section": "ENTRANTES",
  "name": "Gambas al ajillo",
  "description": "con guindilla y pan tostado",
  "price": 12.5, "currency": "EUR",
  "allergenCodes": [1, 2], "mayContainCodes": [12],
  "allergens": [{ "code": 2, "key": "crustaceans", "level": "contains", "evidence": ["gamba"], "sources": ["rules", "ai"], "name": "Crustaceans" }],
  "translations": { "en": { "name": "Garlic prawns", "description": "with chilli and toasted bread", "section": "STARTERS" }, "de": { "name": "Garnelen in Knoblauchöl" } },
  "method": "rules+ai", "needsReview": true
}
```

The key-value store also holds:

- `MENU`: the full menu as one JSON document with an allergen legend in 10 languages.
- `ALLERGEN_MATRIX`: a printable HTML table (dishes × 14 allergens with icons).

### How to use

1. Paste the menu into **Menu text** (one dish per line; prices and headings are detected), or enter a **Menu URL** (HTML page or text PDF; schema.org `Menu` markup is read automatically).
2. Choose **target languages** (or keep the 10 defaults).
3. Run. Download dishes as JSON/CSV/Excel, or open `ALLERGEN_MATRIX`.

Turn **Translate** off for a fast, rules-only allergen check.

### Pricing

Pay per dish: one small fee per dish analysed, plus one per dish translated with our AI. If you **bring your own OpenAI-compatible API key**, translations use your key and the translation fee is not charged.

### Important

This is an assistant, not a certification. Allergen detection is based on dish names and descriptions. Recipes, sauces, frying oil and cross-contamination are invisible to any text tool. The food business operator remains legally responsible for verifying allergen information before publishing it. Translations should be proofread for important menus.

### FAQ

**Scanned PDF or photo menu?** Not yet. Paste the text (any phone OCR works) or use a text-based PDF.

**Does it store my menu?** Only in your own Apify run storage.

**Want a live, QR-code menu with automatic translation and allergen icons?** See MenuDoro (menudoro.com).

# Actor input Schema

## `menuText` (type: `string`):

Paste the menu. One dish per line works best; prices, section headings and description lines under a dish are recognised automatically.

## `menuUrl` (type: `string`):

Used when 'Menu text' is empty. A public menu page (schema.org Menu markup is read when present) or a text-based PDF. Scanned image PDFs are not supported yet. robots.txt is respected.

## `languages` (type: `array`):

ISO 639-1 codes. Default: en, es, de, fr, it, pt, nl, pl, ru, zh. Up to 25 (e.g. uk, ca, sv, ja, ko, ar).

## `sourceLanguage` (type: `string`):

Language the menu is written in. Auto-detect works for en, es, de, fr, it, pt, nl, pl.

## `translate` (type: `boolean`):

Turn off for allergen detection only (cheaper and fully rules-based).

## `displayLanguage` (type: `string`):

Language of allergen names in the output and in the printable allergen matrix.

## `maxDishes` (type: `integer`):

Safety limit on dishes processed per run (you pay per dish).

## `llmApiKey` (type: `string`):

Optional OpenAI-compatible API key. If set, translations use your key and you are not charged the per-dish translation fee.

## `llmBaseUrl` (type: `string`):

OpenAI-compatible base URL for your key, e.g. https://api.openai.com/v1 or https://api.deepseek.com

## `llmModel` (type: `string`):

Model name for your key, e.g. gpt-4o-mini or deepseek-chat.

## Actor input object example

```json
{
  "menuText": "ENTRANTES\nGambas al ajillo 12,50 €\ncon guindilla y pan tostado\nPulpo a la gallega 16,00 €\nPOSTRES\nTarta de queso 6,50 €",
  "languages": [
    "en",
    "es",
    "de",
    "fr",
    "it",
    "pt",
    "nl",
    "pl",
    "ru",
    "zh"
  ],
  "sourceLanguage": "auto",
  "translate": true,
  "displayLanguage": "en",
  "maxDishes": 200
}
```

# Actor output Schema

## `results` (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 = {
    "menuText": `ENTRANTES
Gambas al ajillo 12,50 €
con guindilla y pan tostado
Pulpo a la gallega 16,00 €
POSTRES
Tarta de queso 6,50 €`
};

// Run the Actor and wait for it to finish
const run = await client.actor("nebulosa/menu-allergen-translator").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 = { "menuText": """ENTRANTES
Gambas al ajillo 12,50 €
con guindilla y pan tostado
Pulpo a la gallega 16,00 €
POSTRES
Tarta de queso 6,50 €""" }

# Run the Actor and wait for it to finish
run = client.actor("nebulosa/menu-allergen-translator").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 '{
  "menuText": "ENTRANTES\\nGambas al ajillo 12,50 €\\ncon guindilla y pan tostado\\nPulpo a la gallega 16,00 €\\nPOSTRES\\nTarta de queso 6,50 €"
}' |
apify call nebulosa/menu-allergen-translator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nebulosa/menu-allergen-translator"
        }
    }
}
```

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/aJ2N9rhYblQACWczg/builds/GQgMLEClrfFFnEcv7/openapi.json
