# Video to Recipe API: YouTube Recipe Extractor & Nutrition (`messnomore/video-to-recipe`) Actor

Turn cooking videos into structured recipes: ingredients with quantities, steps, servings scaling, metric or imperial units, USDA nutrition per serving and an aisle-grouped shopping list. Works with YouTube links, audio or video file URLs and pasted TikTok or Instagram Reels captions.

- **URL**: https://apify.com/messnomore/video-to-recipe.md
- **Developed by:** [Wong Xian Qi](https://apify.com/messnomore) (community)
- **Categories:** AI, Videos, Social media
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $28.00 / 1,000 extracted recipes

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

### What does Video to Recipe API do?

**Video to Recipe API** turns cooking videos into clean, structured recipes: a title, every ingredient with its
quantity and unit, numbered steps, servings, prep and cook times, an **estimated nutrition per serving** and an
**aisle-grouped shopping list**. Give it YouTube links, direct audio or video file links, or captions you pasted
from **TikTok** or **Instagram Reels**, and get one JSON recipe per video in your language and unit system.

Use it in Apify Console with no code, or as a **recipe extractor API** for your meal planner, grocery app, food blog
or AI assistant.

### Why use Video to Recipe API?

Recipes in short videos are hard to reuse: the amounts are spoken, half of them are in the description, servings
are rarely stated and nothing is in grams. Video to Recipe API does the boring part for you:

- 🧾 **Structured ingredients**: quantity, unit, preparation note and the original line from the video, so you can
  check every value against the source.
- ⚖️ **Servings scaling**: set `servings` and every amount is scaled for you (2 → 4 servings doubles everything).
- 📏 **Metric or imperial**: amounts converted to grams and millilitres or to ounces, pounds and cups, rounded the way
  cooks measure (1/2 cup, 1 1/2 tbsp).
- 🥗 **Nutrition per serving**: calories, protein, fat and carbs estimated from
  [USDA FoodData Central](https://fdc.nal.usda.gov/), with the matched USDA food for each ingredient.
- 🛒 **Shopping list by aisle**: duplicates merged (1 tbsp + 1 tsp soy sauce becomes one line), water left out,
  grouped in store-walk order with aisle names in your language.
- 🌏 **12 output languages**: English, Chinese (Simplified), Malay, Indonesian, Thai, Vietnamese, Japanese, Korean,
  Spanish, French, German and Portuguese, whatever language the video is in.
- 🔍 **Honest about gaps**: `missingInfo` lists what the video does not say (servings, times, amounts), and
  `confidence` tells you how complete the recipe is. Nothing is invented: no amount is guessed.
- 🤖 **Apify platform features**: run it by API, on a schedule, or send results to Google Sheets, Make, Zapier or a
  webhook with [integrations](https://docs.apify.com/platform/integrations).

Who uses it: **meal planner and grocery app developers**, **food bloggers and recipe sites**, **nutrition and diet
coaches**, and **anyone who saves recipes from YouTube Shorts, TikTok and Reels**.

### What data does Video to Recipe API return?

| Field                                                      | Description                                                                                                                                                                                       |
| ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `title`, `cuisine`                                         | Dish name in your output language, and the cuisine (for example `malaysian`)                                                                                                                      |
| `servings`, `originalServings`, `scaleFactor`              | Servings of the result, of the source recipe, and the scaling applied                                                                                                                             |
| `prepMinutes`, `cookMinutes`, `totalMinutes`               | Times stated in the video, or estimated from the steps (see `estimatedFields`)                                                                                                                    |
| `ingredients`                                              | Name, English name, `quantity` + `unit`, `normalizedQuantity` + `normalizedUnit` + `normalizedText`, preparation, grocery aisle, optional flag, estimated grams, USDA match and the original line |
| `steps`                                                    | Numbered steps with a duration when the video states one                                                                                                                                          |
| `nutritionPerServing`                                      | `kcal`, `protein_g`, `fat_g`, `carbs_g`, how many ingredients were matched, and the data source                                                                                                   |
| `shoppingList`                                             | Aisles in store-walk order, each with merged items and display amounts                                                                                                                            |
| `confidence`, `missingInfo`, `estimatedFields`, `warnings` | How complete the recipe is and what is missing or estimated                                                                                                                                       |
| `sourceUrl`, `sourceType`, `dataSources`                   | Where the recipe came from and which texts were read                                                                                                                                              |
| `youtube`, `media`                                         | Video ID and channel for YouTube links; duration and billed extra minutes for media files                                                                                                         |

### How to extract a recipe from a video

1. Click **Try for free** and open the **Input** tab.
2. Paste **YouTube video links**, **audio or video file links**, or put pasted captions in **Captions and mixed
   items** (the example caption works as it is).
3. For YouTube links, add your own free **YouTube Data API key** (see the FAQ for the 2-minute setup).
4. Optionally choose **Scale to servings**, **Units** and **Output language**.
5. Click **Start**. A caption or YouTube recipe takes about 20–40 seconds; a media file takes longer because the speech
   is transcribed first. Open the **Output** tab for the recipes, nutrition and shopping lists.

### How much does it cost to turn a video into a recipe?

Video to Recipe API uses **pay-per-event pricing**:

- **$0.04 per recipe** returned. This includes up to **3 minutes** of audio or video.
- **$0.015 per extra started minute** of a media file beyond those 3 minutes.
- A start fee of $0.00005 per run. There is no charge for compute time.

Examples: 10 recipes from captions or YouTube links cost **$0.40**. A 10-minute video file costs
$0.04 + 7 × $0.015 = **$0.145**.

- **Failed items are free**: a video that is not a recipe, a link that cannot be read or a file that is too long is
  not charged.
- **Maximum recipes** is a hard cap, and Apify stops the run at the maximum cost you set. The extra minutes of a media
  file are reserved from your remaining budget first; a file longer than the budget covers is skipped without charge.
- On the Apify free plan, a run returns up to **3 recipes** and accepts media files up to **5 minutes**.

### Input

See the **Input** tab for every option. Example input:

```json
{
    "youtubeUrls": ["https://www.youtube.com/watch?v=VIDEO_ID"],
    "youtubeApiKey": "YOUR_YOUTUBE_API_KEY",
    "mediaFileUrls": ["https://example.com/videos/pad-thai.mp4"],
    "items": [
        {
            "captionText": "Garlic butter shrimp (serves 2)\n300g shrimp, peeled\n3 tbsp butter\n4 cloves garlic, minced\n...",
            "sourceUrl": "https://www.tiktok.com/@example/video/123"
        }
    ],
    "servings": 4,
    "unitSystem": "metric",
    "outputLanguage": "en",
    "includeNutrition": true,
    "maxRecipes": 100,
    "maxMediaMinutes": 20
}
```

- **items**: one entry per recipe. An entry is an object with any of `youtubeUrl`, `mediaFileUrl`, `captionText` and
  `sourceUrl`, or a plain string (a YouTube link, a media file link or the caption text). When an entry has several
  sources, they are merged into one recipe (for example a YouTube description plus your pasted caption). Through MCP,
  use the object form (`{"captionText": "..."}`): MCP clients reject plain strings in this list.
- **sourceUrl** is kept in the output for your reference and is never opened.
- **mediaFileUrls** must be direct links to files you have the right to process (mp4, webm, mov, mp3, m4a, wav and
  other formats ffmpeg reads), up to 200 MB. Links to YouTube, TikTok, Instagram, Facebook and other platform pages
  or CDNs are refused.
- **youtubeApiKey** is stored as a secret input and is used only to call the official YouTube Data API.

### Output

You can download the dataset in various formats such as **JSON, HTML, CSV or Excel**. A real result for the example
caption above, scaled from 2 to 4 servings (ingredient, step and shopping-list arrays shortened here):

```json
{
    "inputIndex": 0,
    "sourceUrl": "https://www.tiktok.com/@example/video/123",
    "sourceType": "caption",
    "title": "Garlic butter shrimp",
    "servings": 4,
    "originalServings": 2,
    "scaleFactor": 2,
    "prepMinutes": 5,
    "cookMinutes": 5,
    "totalMinutes": 10,
    "ingredients": [
        {
            "name": "shrimp",
            "nameEn": "shrimp",
            "quantity": 600,
            "unit": "g",
            "normalizedQuantity": 600,
            "normalizedUnit": "g",
            "normalizedText": "600 g",
            "preparation": "peeled",
            "groceryAisle": "seafood",
            "optional": false,
            "estimatedGrams": 600,
            "nutritionMatch": { "fdcId": 175179, "description": "Crustaceans, shrimp, raw", "dataType": "SR Legacy" },
            "originalText": "300g shrimp, peeled"
        },
        {
            "name": "butter",
            "quantity": 6,
            "unit": "tbsp",
            "normalizedText": "6 tbsp",
            "groceryAisle": "dairy_eggs",
            "estimatedGrams": 85,
            "originalText": "3 tbsp butter"
        }
    ],
    "steps": [
        {
            "order": 1,
            "text": "Melt 2 tbsp butter in a pan, cook the shrimp 1–2 minutes per side until just cooked through, then transfer the shrimp to a plate and set aside.",
            "durationMinutes": 4
        }
    ],
    "nutritionPerServing": {
        "kcal": 294,
        "protein_g": 30.9,
        "fat_g": 18.2,
        "carbs_g": 3.3,
        "estimated": true,
        "matchedIngredients": 5,
        "totalIngredients": 5,
        "source": "USDA FoodData Central (...), public domain (CC0)"
    },
    "shoppingList": [
        {
            "aisle": "produce",
            "aisleLabel": "Produce",
            "items": [
                { "name": "garlic", "quantity": 8, "unit": "clove", "amountText": "8 clove", "optional": false },
                { "name": "lemon", "quantity": 1, "unit": "piece", "amountText": "1", "optional": false }
            ]
        }
    ],
    "confidence": 0.96,
    "missingInfo": ["prepMinutes", "cookMinutes"],
    "estimatedFields": ["prepMinutes", "cookMinutes"],
    "warnings": [],
    "language": "en",
    "unitSystem": "metric",
    "media": null,
    "extractionVersion": 1
}
```

Each run also saves a **SUMMARY** record in its key-value store: items received, recipes delivered and failed,
extra media minutes charged, the limit that applied, and the reason for each failed item.

### Use Video to Recipe API as a recipe API

```bash
curl -X POST "https://api.apify.com/v2/acts/messnomore~video-to-recipe/run-sync-get-dataset-items" \
  -H "Authorization: Bearer YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"items": ["2 eggs, 2 tomatoes, 1 tsp sugar, salt. Fry the eggs, add the tomatoes and sugar, season."], "servings": 2, "outputLanguage": "en"}'
```

See the **API** tab for clients in JavaScript and Python. You can also run it from AI assistants through the
[Apify MCP server](https://docs.apify.com/platform/integrations/mcp).

### Tips for better results

- Give the YouTube link **and** paste the pinned comment or caption in `captionText` of the same item when the
  amounts are only in a comment: all texts are merged into one recipe.
- For TikTok and Reels, copy the caption text (and the video link as `sourceUrl`). If the amounts are only spoken,
  give a direct link to the video file in `mediaFileUrl`.
- Check `missingInfo` before cooking: `quantity:<ingredient>` means the video never said how much.
- Use `servings` to normalize every recipe to the same household size for a weekly meal plan.
- When a video does not say how many it serves, the servings are estimated from typical single portions (about
  120–150 g meat, 80–100 g dry pasta or 2 eggs per person) and scaling starts from that estimate. The record says so
  in `warnings` and `estimatedFields`, so check it before you shop.

### Related guides

- [How do you turn a cooking video into a written recipe with amounts, steps and nutrition?](https://wong13977-oss.github.io/cooking-video-to-recipe/)
- [中文指南：做菜视频怎么转成带用量、步骤和营养的文字菜谱？](https://wong13977-oss.github.io/zh/cooking-video-to-recipe/)

### FAQ

#### How does the recipe extraction work?

The Actor reads the texts you give it: the YouTube title and description (through the official YouTube Data API),
the speech of a media file (transcribed with OpenAI speech-to-text) and your pasted caption. An AI model (OpenAI)
turns them into a structured recipe, copying each ingredient line from the source so you can check it. Amounts are
then scaled and converted by code, and each ingredient is matched to a USDA FoodData Central food for the nutrition
estimate (text embeddings find candidates, and a small AI model picks the closest one).

#### Which platforms are supported? Can I paste a TikTok or Instagram link?

- **YouTube** videos, Shorts and live links, with your own YouTube Data API key.
- **TikTok, Instagram Reels, Facebook, Xiaohongshu** and others: paste the caption text. The Actor does not open
  pages on those platforms or download from them.
- **Any direct audio or video file** you have the right to process, such as files from your own storage or CDN.

#### Why do I need my own YouTube API key?

The YouTube Data API terms require each developer to use their own key. A key is free: in
[Google Cloud Console](https://console.cloud.google.com/), create a project, open **APIs & Services → Library**,
enable **YouTube Data API v3**, then **Credentials → Create credentials → API key**. Each video uses 1 of your
10,000 free daily quota units. The Actor reads only the public details of the videos you list (title, description,
channel name, publish date and duration); it does not download YouTube videos or captions.

#### How accurate is the nutrition estimate?

It is an estimate. Each ingredient is matched to a USDA FoodData Central food, its weight is computed from the
amount (USDA portion weights for cups and pieces), and the totals are divided by the servings. Ingredients without
an amount, marked optional, or used for deep-frying are left out, and `nutritionPerServing` is `null` when fewer than
half of the ingredients have both an amount and a match. Weights of bone-in meat ("1.2 kg whole chicken") count the
bones as meat, so those recipes show more calories than you eat.

#### Which languages are supported?

Videos and captions can be in any language the AI and the transcription understand, including English, Chinese,
Malay, Indonesian, Thai, Vietnamese, Japanese and Korean. The output is written in one of the 12 output languages;
Chinese output always uses Simplified characters. When a Japanese or Korean source leaves a few words untranslated,
the record carries a warning.

#### Why did I get fewer recipes than videos?

Items that are not recipes (a vlog, an ad, "recipe in the comments"), links that cannot be read, and media files that
are too long, too large or silent are skipped and not charged. The **SUMMARY** record lists each one with its reason.
A run also stops at **Maximum recipes**, at your maximum cost per run, on the free plan after 3 recipes, and early
when many items in a row fail (for example several long media files that contain no recipe).

#### Is my input stored or shared?

Your captions, the YouTube texts and the speech of your media files are sent to the OpenAI API only to transcribe
them, extract the recipe and match the ingredients to USDA foods. Media files are downloaded to a temporary folder for the run and deleted right after.
The Actor does not write your input or your API key to its logs, and it keeps no cache of YouTube data. Like every
Apify run, your input and results stay in your own run storage, which you can delete at any time.

#### Is it legal to extract recipes from videos?

You decide what the Actor reads: only the YouTube videos you list (public title and description through the official
API, under the [YouTube Terms of Service](https://www.youtube.com/t/terms)), files you have the right to process,
and text you paste. YouTube data is handled under the
[Google Privacy Policy](https://policies.google.com/privacy); you can stop the Actor's access at any time by removing
the key from your input or deleting it in Google Cloud Console. If you keep results from YouTube videos for more than 30 days, refresh or delete them as
the YouTube API Services Terms require. A list of ingredients is generally not protected by copyright, but the
creator's wording, photos and videos are: credit and link the original creator when you publish a recipe.
Video to Recipe API is not affiliated with YouTube, Google, TikTok or Meta.

#### Privacy policy

The Actor processes the input of each run only to produce that run's results. Third-party processors: the OpenAI API
(extraction and transcription) and, for YouTube links, the YouTube Data API with your own key. The developer does not
receive, sell or share your input or results; they stay in your Apify account under
[Apify's privacy policy](https://apify.com/privacy-policy). Questions: open the **Issues** tab.

#### I found a wrong amount or a missing ingredient. What can I do?

Open the **Issues** tab and include the video link and the run ID. Feedback and feature requests are welcome there too.

# Actor input Schema

## `items` (type: `array`):

One entry per recipe. An entry is an object with any of "youtubeUrl", "mediaFileUrl", "captionText" and "sourceUrl" (a link kept for your reference, never opened), or a plain string: a YouTube link, a media file link or the caption text itself. Paste TikTok or Instagram Reels captions as "captionText"; links to TikTok or Instagram pages are not read. AI assistants using MCP: send objects such as {"captionText": "..."}, not plain strings.

## `youtubeUrls` (type: `array`):

YouTube videos, Shorts or live links. The title and description are read with the official YouTube Data API, so add your own API key below.

## `mediaFileUrls` (type: `array`):

Direct links to audio or video files (mp4, webm, mov, mp3, m4a, wav...) that you have the right to process. The speech is transcribed. Links to web pages, YouTube, TikTok or Instagram are refused.

## `youtubeApiKey` (type: `string`):

Your own free key from Google Cloud Console (APIs & Services → enable "YouTube Data API v3" → Credentials → Create API key). Needed only for YouTube links. Each video uses 1 unit of your free 10,000 daily units.

## `servings` (type: `integer`):

Scale every recipe to this many servings. Leave empty to keep the servings stated in the video.

## `unitSystem` (type: `string`):

Unit system of the normalized amounts and the shopping list. Spoons stay spoons in both.

## `outputLanguage` (type: `string`):

Language of titles, ingredient names, steps and shopping-list labels, whatever the video's language.

## `includeNutrition` (type: `boolean`):

Estimate calories, protein, fat and carbs per serving from USDA FoodData Central. Switch off to skip the matching.

## `maxRecipes` (type: `integer`):

Stop after this many recipes. Failed items are not charged and do not count.

## `maxMediaMinutes` (type: `integer`):

Longer audio or video files are skipped without charge. The first 3 minutes of every file are included in the recipe price.

## Actor input object example

```json
{
  "items": [
    {
      "captionText": "Garlic butter shrimp (serves 2)\n300g shrimp, peeled\n3 tbsp butter\n4 cloves garlic, minced\n1/2 tsp chili flakes\njuice of 1/2 lemon\nsalt to taste\n\nMelt 2 tbsp butter, cook the shrimp 1-2 min per side and set aside. Add the rest of the butter and the garlic, cook 30 sec, add chili flakes and lemon juice, return the shrimp and toss.",
      "sourceUrl": "https://www.tiktok.com/@example/video/123"
    }
  ],
  "youtubeUrls": [],
  "mediaFileUrls": [],
  "unitSystem": "metric",
  "outputLanguage": "en",
  "includeNutrition": true,
  "maxRecipes": 100,
  "maxMediaMinutes": 20
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `summary` (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 = {
    "items": [
        {
            "captionText": "Garlic butter shrimp (serves 2)\n300g shrimp, peeled\n3 tbsp butter\n4 cloves garlic, minced\n1/2 tsp chili flakes\njuice of 1/2 lemon\nsalt to taste\n\nMelt 2 tbsp butter, cook the shrimp 1-2 min per side and set aside. Add the rest of the butter and the garlic, cook 30 sec, add chili flakes and lemon juice, return the shrimp and toss.",
            "sourceUrl": "https://www.tiktok.com/@example/video/123"
        }
    ],
    "youtubeUrls": [],
    "mediaFileUrls": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("messnomore/video-to-recipe").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 = {
    "items": [{
            "captionText": """Garlic butter shrimp (serves 2)
300g shrimp, peeled
3 tbsp butter
4 cloves garlic, minced
1/2 tsp chili flakes
juice of 1/2 lemon
salt to taste

Melt 2 tbsp butter, cook the shrimp 1-2 min per side and set aside. Add the rest of the butter and the garlic, cook 30 sec, add chili flakes and lemon juice, return the shrimp and toss.""",
            "sourceUrl": "https://www.tiktok.com/@example/video/123",
        }],
    "youtubeUrls": [],
    "mediaFileUrls": [],
}

# Run the Actor and wait for it to finish
run = client.actor("messnomore/video-to-recipe").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 '{
  "items": [
    {
      "captionText": "Garlic butter shrimp (serves 2)\\n300g shrimp, peeled\\n3 tbsp butter\\n4 cloves garlic, minced\\n1/2 tsp chili flakes\\njuice of 1/2 lemon\\nsalt to taste\\n\\nMelt 2 tbsp butter, cook the shrimp 1-2 min per side and set aside. Add the rest of the butter and the garlic, cook 30 sec, add chili flakes and lemon juice, return the shrimp and toss.",
      "sourceUrl": "https://www.tiktok.com/@example/video/123"
    }
  ],
  "youtubeUrls": [],
  "mediaFileUrls": []
}' |
apify call messnomore/video-to-recipe --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,messnomore/video-to-recipe"
        }
    }
}
```

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/bb7V3P4aGwTarLLu1/builds/KujOXmi8NxFN4ijAX/openapi.json
