# Recipe Scraper (`mina_safwat/recipe-scraper`) Actor

Extracts structured recipes — ingredients, steps, times, nutrition, and ratings — from 725+ recipe sites.

- **URL**: https://apify.com/mina_safwat/recipe-scraper.md
- **Developed by:** [Mina](https://apify.com/mina_safwat) (community)
- **Categories:** News, E-commerce, Automation
- **Stats:** 2 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

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

Turn any **recipe page into structured data** — ingredients, numbered steps, prep and cook times, nutrition, ratings, and yield — from 725 recipe sites and thousands more that publish standard recipe markup.

### What does Recipe Scraper do?

Give it recipe URLs and it returns clean, machine-readable recipes: the ingredient list, the instructions as separate steps, total, prep and cook times in minutes, servings, nutrition facts, the star rating and how many people rated it, plus the cuisine, course, and author.

725 sites are supported directly, and most others work too, because the Actor also reads the standard recipe information that food sites publish. You are not limited to a fixed list.

### Why use Recipe Scraper?

- **Recipe apps and meal planners** — build a database without hand-entering anything.
- **Nutrition analysis** — pull calories and macros across hundreds of recipes at once.
- **Shopping list tools** — the ingredient list arrives already separated, line by line.
- **Content research** — compare how sites treat the same dish, or track ratings over time.
- **AI training data** — structured ingredients and steps are far more useful than raw HTML.

Running it on Apify adds scheduling, an API, integrations (Sheets, Slack, Zapier, S3), residential proxy rotation, and run monitoring.

### How to use Recipe Scraper

1. Paste recipe links into **Recipe URLs**, one per line.
2. Click **Start**.

That is the whole setup. Results appear in the Output tab as they are scraped, and download as JSON, CSV, Excel, or XML.

### Input

| Field | Description |
| --- | --- |
| `recipe_urls` | Links to recipe pages, one per line. |
| `max_recipes` | Stops after this many URLs. |
| `allow_unsupported_sites` | Try any site, not only the 725 supported ones. On by default. |
| `max_concurrency` | How many pages to fetch at once. Lower it if a site rate-limits you. |
| `proxy_country` | Comma-separated country codes for the residential proxy rotation. |

### Output

```json
{
  "url": "https://www.allrecipes.com/recipe/20144/banana-banana-bread/",
  "title": "Banana Banana Bread",
  "author": "Shelley Albeluhn",
  "site_name": "Allrecipes",
  "description": "An incredibly moist loaf with very ripe bananas.",
  "image": "https://www.allrecipes.com/thmb/lead.jpg",
  "yields": "1 loaf",
  "total_time_minutes": 75,
  "prep_time_minutes": 15,
  "cook_time_minutes": 60,
  "ingredients": [
    "2 cups all-purpose flour",
    "1 teaspoon baking soda",
    "3 ripe bananas, mashed"
  ],
  "instruction_steps": [
    "Heat the oven to 175 degrees C.",
    "Combine the dry ingredients.",
    "Fold in the bananas and bake for an hour."
  ],
  "nutrients": { "calories": "231 kcal", "proteinContent": "4 g" },
  "rating": 4.7,
  "rating_count": 17388,
  "category": "Breakfast",
  "cuisine": "American",
  "has_dedicated_scraper": true
}
```

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

#### Data fields

| Field | Description |
| --- | --- |
| `title`, `description`, `author`, `image` | The recipe and who wrote it. |
| `ingredients` | One line per ingredient, as written. |
| `ingredient_groups` | Ingredients split by section — "For the sauce", "For the topping" — where the site groups them. |
| `instructions`, `instruction_steps` | The method as one block, and as separate numbered steps. |
| `total_time_minutes`, `prep_time_minutes`, `cook_time_minutes` | Times as plain numbers, not text. |
| `yields` | Servings or quantity. |
| `nutrients` | Calories and macros, as the site publishes them. |
| `rating`, `rating_count` | Star rating and how many people rated it. |
| `category`, `cuisine`, `cooking_method`, `dietary_restrictions`, `keywords` | Classification. |
| `has_dedicated_scraper` | Whether this site is one of the 725 supported directly. |

### How much does it cost to scrape recipes?

Cost tracks the number of recipes scraped — links that fail are not charged — so **Max recipes** is the main lever on what a run costs.

### Tips

- **Check `has_dedicated_scraper`.** Directly supported sites tend to fill in more fields, especially nutrition and grouped ingredients.
- **Lower the concurrency** to 1 or 2 if a single site starts refusing requests.
- **Failed links are listed, not billed.** A URL that fails is left out of the dataset and listed, with the reason, in the `FAILED_INPUTS` record of the run's key-value store — so a large run never loses track of which inputs worked.

### FAQ and support

**Which sites are supported?** 725 directly, plus most others — the Actor also reads the standard recipe information that food sites publish.

**Why did a site return "no recipe data"?** A few sites do not publish their recipe in a readable form, and some links simply are not recipe pages. Those are listed in the `FAILED_INPUTS` record of the run's key-value store rather than failing the whole run.

**Why are some fields empty?** Not every site publishes prep time, nutrition, or a rating. When a site does not declare it, the field comes back empty rather than guessed.

**Why did a recipe come back with ingredients but no method?** A few sites — Simply Recipes among them — publish their ingredient list but not their instructions. Those recipes still come through, with the steps empty, and the run log names each one so you can spot them.

**Is scraping recipes legal?** Ingredient lists are generally facts rather than creative work, but the surrounding text, photos, and the recipe as written are usually copyrighted. Extracting for personal use, analysis, or research is common; republishing is a different matter. You are responsible for how you use the output, including each site's terms. Consult a lawyer if you are unsure.

Found a bug or want a field that is missing? Open an issue on the Actor's Issues tab.

### SEO Keywords

recipe scraper, extract recipe ingredients, structured recipe data, recipe nutrition scraper, food blog scraper, recipe api, cooking instructions extractor, meal planning data, recipe schema parser, recipe aggregator

# Actor input Schema

## `recipe_urls` (type: `array`):

Links to recipe pages, one per line. 725 sites have a dedicated extractor; others are read from the standard recipe markup most sites publish.

## `max_recipes` (type: `integer`):

Stops after this many URLs.

## `allow_unsupported_sites` (type: `boolean`):

Try any site, not only the 725 with a dedicated extractor, by reading the schema.org recipe markup on the page. Turn this off to skip unknown sites instead.

## `max_concurrency` (type: `integer`):

Higher is faster but more likely to be rate-limited. Drop to 1–2 if you see failures.

## `proxy_country` (type: `string`):

Comma-separated 2-letter codes, rotated across retries. Residential proxies are recommended — many recipe sites block datacentre IPs.

## Actor input object example

```json
{
  "recipe_urls": [
    "https://www.allrecipes.com/recipe/20144/banana-banana-bread/"
  ],
  "max_recipes": 100,
  "allow_unsupported_sites": true,
  "max_concurrency": 5,
  "proxy_country": "US,GB,DE,NL,FR"
}
```

# Actor output Schema

## `dataset` (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 = {
    "recipe_urls": [
        "https://www.allrecipes.com/recipe/20144/banana-banana-bread/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("mina_safwat/recipe-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 = { "recipe_urls": ["https://www.allrecipes.com/recipe/20144/banana-banana-bread/"] }

# Run the Actor and wait for it to finish
run = client.actor("mina_safwat/recipe-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 '{
  "recipe_urls": [
    "https://www.allrecipes.com/recipe/20144/banana-banana-bread/"
  ]
}' |
apify call mina_safwat/recipe-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mina_safwat/recipe-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/Sp3kBbJ2sZinL2bfW/builds/AsWRJGdLFnxLtt2I5/openapi.json
