# Recipe Extractor: Ingredients, Steps & Nutrition from Any URL (`larkmoor/recipe-extractor`) Actor

Extract structured recipes from any food blog or recipe site: name, ingredients, step-by-step instructions, prep/cook/total time, servings, nutrition, rating, cuisine, image and video. Paste recipe URLs or discover recipes from a sitemap, feed or category page. $2 per 1,000 recipes.

- **URL**: https://apify.com/larkmoor/recipe-extractor.md
- **Developed by:** [Larkmoor Data](https://apify.com/larkmoor) (community)
- **Categories:** AI, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.70 / 1,000 recipe 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

## Recipe Extractor: Ingredients, Steps & Nutrition from Any Recipe URL

Turn any recipe page into **clean, structured data**: recipe name, ingredient list, step-by-step instructions, prep / cook / total time, servings, calories and full nutrition, star rating and review count, cuisine, category, diet tags, author, main image and video link.

It works on **almost every food blog and recipe website**, because those sites publish their recipes in the standard schema.org Recipe format that search engines read (WP Recipe Maker, Tasty Recipes, Mediavine Create, Yoast and most custom sites). Paste recipe URLs, or point the actor at a site's sitemap, RSS feed or category page and let it find the recipes for you.

### What does Recipe Extractor do?

- Reads the recipe markup each page already publishes (JSON-LD first, microdata as a fallback).
- Normalizes it into the same columns for every site: `ingredients` (list), `instructions` (list of steps, optionally with section names), times in **minutes**, `servings` as a number, nutrition in grams / mg.
- Resolves linked data (authors and images stored elsewhere on the page) so you get names, not IDs.
- **Discovers recipes** from sitemaps (including sitemap indexes), RSS/Atom feeds and category pages, recipe links first.
- Respects each site's robots.txt and skips pages without a recipe — **those are never charged**.
- Retries pages that block simple requests through a proxy (on the Apify platform).

### Who is it for?

- **Recipe and meal-planning apps** that import recipes users paste in.
- **AI and LLM developers** building cooking assistants, RAG datasets or fine-tuning data.
- **Food bloggers and SEO agencies** auditing recipe markup across a site (missing nutrition, times or ratings).
- **Grocery and food-tech companies** mapping recipes to ingredients and shopping lists.
- **Researchers** studying cuisines, nutrition or ingredient trends.

### Input

| Field | What it does |
|---|---|
| `recipeUrls` | recipe pages, one per line |
| `discoverFrom` | sitemaps, feeds or category pages to find recipes on |
| `maxRecipesPerSite` | cap per site / source (default 50) |
| `maxRecipes` | cap for the whole run |
| `keepSections` | keep instruction section names ("For the dough") |
| `includeRawSchema` | add the full original schema.org object |
| `skipFailed` | hide pages without a recipe |
| `respectRobotsTxt` | on by default |
| `useResidentialProxy` | retry blocked pages through residential proxy (proxy traffic billed by Apify) |

```json
{
  "recipeUrls": ["https://minimalistbaker.com/easy-vegan-fried-rice/"],
  "discoverFrom": ["https://pinchofyum.com/feed"],
  "maxRecipesPerSite": 20
}
```

### Output

```json
{
  "name": "Chicken with Cajun Sauce",
  "siteName": "Pinch of Yum",
  "author": "Lindsay Ostrom",
  "totalTimeMinutes": 40,
  "prepTimeMinutes": 10,
  "cookTimeMinutes": 30,
  "servings": 4,
  "recipeYield": "4 servings",
  "cuisine": "Cajun",
  "category": "Dinner",
  "ingredientCount": 12,
  "ingredients": ["1 lb. chicken breasts", "1 tablespoon Cajun seasoning", "..."],
  "stepCount": 6,
  "instructions": ["Season the chicken...", "..."],
  "calories": 288,
  "proteinGrams": 27,
  "ratingValue": 5,
  "ratingCount": 19,
  "image": "https://...jpg",
  "videoUrl": "https://www.youtube.com/watch?v=...",
  "url": "https://pinchofyum.com/chicken-with-cajun-cream-sauce",
  "markup": "json-ld"
}
```

Other columns: `description`, `datePublished`, `keywords`, `suitableForDiet`, `fatGrams`, `saturatedFatGrams`, `carbohydrateGrams`, `sugarGrams`, `fiberGrams`, `sodiumMg`, `nutritionServingSize`, `finalUrl`. Pages without a recipe come back with an `error` explaining why (no markup, blocked, robots.txt) and are free.

Export as JSON, CSV, Excel or HTML, or read results through the Apify API.

### How much does it cost?

- **$2.00 per 1,000 recipes extracted** (pages without a recipe are free)
- $0.001 per run start

Worked examples:

1. **Import 50 recipes users pasted into your app:** 50 × $0.002 = **$0.10**.
2. **A food blog's whole archive from its sitemap, 1,200 recipes:** **about $2.40**.
3. **A 10,000-recipe training dataset from 20 sites:** **about $20**.

Bronze, Silver and Gold Apify plans pay less per recipe. Compute is small (256 MB, plain HTTP, no browser).

### Tips

- **Whole site:** most WordPress recipe blogs have `/post-sitemap.xml` or `/wp-sitemap.xml`; put that in `discoverFrom` and raise `maxRecipesPerSite`.
- **Fresh recipes only:** use the site's RSS feed (`/feed`) — it lists the newest posts first.
- **Markup audit:** run a site's sitemap with `skipFailed` off; rows with `no recipe markup`, or with empty `calories` / `totalTimeMinutes`, show which posts need their recipe card fixed for Google rich results.
- **Shopping lists:** `ingredients` keeps each line as written ("2 cups flour, sifted"), ready for your own parser.

### FAQ

**Which sites work?**
Any site that publishes schema.org Recipe markup — the vast majority of recipe blogs and many big publishers. A few large publishers block datacenter IPs; those pages are reported as blocked and not charged. Turn on `useResidentialProxy` to retry them through Apify residential proxy (tested: Allrecipes works that way).

**Is it legal?**
The actor reads publicly available pages you choose, follows robots.txt, and returns the structured data the sites themselves publish for search engines and recipe apps. Ingredient lists are facts; respect each site's copyright if you republish instructions or photos — store a link back to the source (`url`).

**Does it need a browser?**
No. Recipe markup is in the page source, so plain HTTP requests are enough — fast and cheap.

**Why are times in minutes?**
Sites publish ISO 8601 durations like `PT1H15M`; the actor converts them so you can sort and filter. If only prep and cook time are given, total time is their sum.

**Can I get the exact original data?**
Turn on `includeRawSchema` to receive the complete schema.org object next to the normalized columns.

### Integrations

Send recipes to Google Sheets, Airtable, Notion or your database with Apify integrations, run it from Make, Zapier or n8n, call it from Python or JavaScript with the Apify client, or let an AI agent use it through the Apify MCP server.

### Changelog

- **0.1** — first release: JSON-LD and microdata recipes, linked-data resolution, times in minutes, nutrition, ratings, video, sitemap/feed/category discovery, robots.txt, proxy retry, optional residential proxy.

# Actor input Schema

## `recipeUrls` (type: `array`):

Recipe pages to extract, one per line. Each page with a recipe gives one row.

## `discoverFrom` (type: `array`):

Sitemaps (sitemap.xml, post-sitemap.xml), RSS feeds or category pages of recipe sites. The actor finds recipe links there and extracts them.

## `maxRecipesPerSite` (type: `integer`):

How many recipes to take from each discovery source / website.

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

Hard cap on recipes extracted (and charged) in this run.

## `keepSections` (type: `boolean`):

Return instructions as objects with their section name (e.g. 'For the sauce') instead of a plain list of step texts.

## `includeRawSchema` (type: `boolean`):

Add the page's full schema.org Recipe object as 'rawSchema' (for fields not mapped to columns).

## `skipFailed` (type: `boolean`):

Leave pages without recipe markup out of the dataset (they are never charged either way).

## `respectRobotsTxt` (type: `boolean`):

Skip pages the site's robots.txt disallows (recommended).

## `concurrency` (type: `integer`):

Pages fetched at the same time (1-10).

## `useResidentialProxy` (type: `boolean`):

Some large recipe publishers block datacenter IPs (HTTP 403). Turn this on to retry those pages through Apify residential proxy (billed by Apify per GB of proxy traffic on your account; most food blogs do not need it).

## Actor input object example

```json
{
  "recipeUrls": [
    "https://pinchofyum.com/chicken-with-cajun-cream-sauce",
    "https://minimalistbaker.com/easy-vegan-fried-rice/"
  ],
  "discoverFrom": [
    "https://pinchofyum.com/feed"
  ],
  "maxRecipesPerSite": 50,
  "maxRecipes": 1000,
  "keepSections": false,
  "includeRawSchema": false,
  "skipFailed": false,
  "respectRobotsTxt": true,
  "concurrency": 5,
  "useResidentialProxy": false
}
```

# Actor output Schema

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

All results as JSON items in the run's default dataset (also downloadable as CSV/Excel from the dataset).

# 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 = {
    "recipeUrls": [
        "https://pinchofyum.com/chicken-with-cajun-cream-sauce",
        "https://minimalistbaker.com/easy-vegan-fried-rice/"
    ],
    "discoverFrom": [
        "https://pinchofyum.com/feed"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("larkmoor/recipe-extractor").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 = {
    "recipeUrls": [
        "https://pinchofyum.com/chicken-with-cajun-cream-sauce",
        "https://minimalistbaker.com/easy-vegan-fried-rice/",
    ],
    "discoverFrom": ["https://pinchofyum.com/feed"],
}

# Run the Actor and wait for it to finish
run = client.actor("larkmoor/recipe-extractor").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 '{
  "recipeUrls": [
    "https://pinchofyum.com/chicken-with-cajun-cream-sauce",
    "https://minimalistbaker.com/easy-vegan-fried-rice/"
  ],
  "discoverFrom": [
    "https://pinchofyum.com/feed"
  ]
}' |
apify call larkmoor/recipe-extractor --silent --output-dataset

```

## MCP server setup

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

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/LkJ6kCuw6fw55wpYf/builds/VoL6jUU5OxUBQtmRu/openapi.json
