OvenLovin

Recipe Importers

OvenLovin supports multiple recipe import methods to make it easy to add recipes from any source. All importers extract recipe data, parse ingredients and instructions, and calculate confidence scores for quality validation.

URL Import

Import recipes directly from recipe websites that use Schema.org Recipe markup.

How It Works

The URL importer:

  1. Fetches the HTML from the provided URL
  2. Extracts Schema.org Recipe JSON-LD structured data
  3. Parses ingredients, instructions, nutrition, servings, and schema.org prep/cook durations
  4. Pulls the main image from schema.org Recipe image, falling back to og:image
  5. Copies that image into Vercel Blob when a blob token is configured
  6. Calculates confidence scores based on completeness
  7. If JSON-LD and HTML miss, extracts from page text with RK_MODEL_EXTRACT (else RK_MODEL_DEFAULT, else deepseek/deepseek-v4.1-flash). DeepSeek failures retry openai/gpt-6-luna
  8. Returns a validated recipe draft

Supported Sites

Any website that includes Schema.org Recipe JSON-LD markup, including:

  • AllRecipes
  • Food Network
  • NYT Cooking
  • Serious Eats
  • Bon Appétit
  • Most food blogs (WordPress, Wix, etc.)

Usage

Via MCP Tool

{
  "tool": "import_recipe",
  "input": {
    "source": "url",
    "content": "https://example.com/recipe/chocolate-chip-cookies"
  }
}

Via REST API

curl -X POST https://your-app.vercel.app/api/v1/recipes/import \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source": "url",
    "content": "https://example.com/recipe/chocolate-chip-cookies",
    "save": true
  }'

Programmatic (TypeScript)

import { createUrlImporter } from "@ovenlovin/importers";
 
const importer = createUrlImporter();
 
// Check if URL can be imported
if (importer.canHandle({ url: "https://example.com/recipe" })) {
  // Extract raw data
  const extraction = await importer.extract({
    url: "https://example.com/recipe",
  });
 
  // Convert to recipe draft
  const draft = await importer.toDraft(extraction);
 
  console.log(draft.title);
  console.log(draft.confidence.overall); // 0.0 - 1.0
}

What Gets Extracted

  • Title and description
  • Ingredients with quantities and units
  • Instructions with step-by-step text
  • Servings and yield
  • Times (prep, cook, total)
  • Nutrition (if available in JSON-LD)
  • Main image (largest or first schema.org Recipe image, else og:image). Extra gallery photos are not saved on import; people can add more later.
  • Cuisine and course/category
  • Author and attribution
  • Method tags (detected from ingredients/steps)

Confidence Scoring

Each imported recipe receives confidence scores:

{
  confidence: {
    overall: 0.85,          // Combined score
    structure: 0.9,         // Has title, ingredients, steps
    ingredients: 0.8,       // Ingredient quality
    instructions: 0.9,      // Instruction quality
    metadata: 0.7           // Times, servings, images
  }
}

Score ranges:

  • 0.9 - 1.0: Excellent (complete, well-structured)
  • 0.7 - 0.89: Good (minor gaps acceptable)
  • 0.5 - 0.69: Fair (review recommended)
  • < 0.5: Poor (manual editing required)

Photo Import (OCR)

Extract recipes from photos of recipe cards, cookbook pages, or handwritten notes using optical character recognition.

How It Works

The photo importer:

  1. Accepts one or more images (JPEG, PNG, WebP, GIF, AVIF) as a file upload, Blob URL, or base64
  2. Stores the first photo in Vercel Blob as the recipe's single main image
  3. Sends all pages to a vision-capable AI Gateway model (default: RK_MODEL_VISION or deepseek/deepseek-v4.1-flash). DeepSeek failures retry openai/gpt-6-luna
  4. Extracts title, servings, times, ingredients (name, quantity, unit), steps, notes, and a visible source
  5. Classifies ingredients with the existing allergen catalog and lists uncertainFields when the photo is hard to read
  6. Returns a draft for review (save omitted) or persists when save=true

Usage

Via REST API

Preview (default - review before save):

curl -X POST https://your-app.vercel.app/api/v1/recipes/import/photo \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "image=@recipe-card.jpg"

Or send a Blob URL / base64:

curl -X POST https://your-app.vercel.app/api/v1/recipes/import/photo \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "imageUrl": "https://blob.vercel-storage.com/recipe-card.jpg",
    "save": false
  }'

Set save: true to persist immediately. The first photo is stored in Vercel Blob and is the recipe's only main image. The response lists uncertainFields when the photo is hard to read.

Programmatic (TypeScript)

import { runPhotoImport } from "@ovenlovin/importers";
 
const { draft, uncertainFields, allergenClassifications } = await runPhotoImport({
  images: [{ blob: "https://blob.vercel-storage.com/recipe.jpg" }],
});
 
console.log(draft.title, uncertainFields, allergenClassifications);

Supported Image Types

  • JPEG / JPG
  • PNG
  • WebP

Best Results

For optimal OCR quality:

  • Lighting: Even, bright lighting without glare
  • Focus: Clear, sharp image (not blurry)
  • Angle: Flat, head-on perspective (avoid skew)
  • Resolution: At least 1024x768 pixels
  • Text size: Recipe text should be readable when zoomed in
  • Handwriting: Print is better than cursive

OCR Limitations

  • Accuracy: 85-95% for printed text, lower for handwriting
  • Layout: Complex multi-column layouts may need manual review
  • Languages: English recommended; other languages may have lower accuracy
  • Quality: Confidence scores will reflect OCR uncertainty

Paste Import

Parse recipes from pasted plain text, including recipes copied from emails, PDFs, or screenshots.

How It Works

The paste importer:

  1. Accepts plain text input
  2. Sends to LLM (RK_MODEL_DEFAULT or deepseek/deepseek-v4.1-flash) for parsing. DeepSeek failures retry openai/gpt-6-luna
  3. Identifies title, ingredients, instructions, and metadata
  4. Structures data into recipe format
  5. Returns draft with confidence scores

Usage

Via MCP Tool

{
  "tool": "import_recipe",
  "input": {
    "source": "paste",
    "content": "Chocolate Chip Cookies\n\nIngredients:\n2 1/4 cups flour\n..."
  }
}

Via REST API

curl -X POST https://your-app.vercel.app/api/v1/recipes/import \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source": "paste",
    "content": "Chocolate Chip Cookies\n\nIngredients:\n2 1/4 cups flour\n1 cup butter\n...",
    "save": true
  }'

Programmatic (TypeScript)

import { createPasteImporter } from "@ovenlovin/importers";
 
const importer = createPasteImporter({
  aiGatewayKey: process.env.AI_GATEWAY_API_KEY,
  defaultModel: process.env.RK_MODEL_DEFAULT || "deepseek/deepseek-v4.1-flash",
});
 
const text = `
Chocolate Chip Cookies
 
Ingredients:
- 2 1/4 cups all-purpose flour
- 1 cup butter, softened
- 2 cups chocolate chips
 
Instructions:
1. Preheat oven to 375°F
2. Mix butter and sugar
3. Add flour gradually
4. Fold in chocolate chips
5. Bake for 10-12 minutes
`;
 
if (importer.canHandle({ text })) {
  const extraction = await importer.extract({ text });
  const draft = await importer.toDraft(extraction);
  console.log(draft.ingredients.length); // 3
}

Supported Text Formats

The paste importer handles various formats:

  • Structured (clearly labeled sections)
  • Semi-structured (some headings)
  • Unstructured (narrative format)
  • Bullet points or numbered lists
  • Mixed (ingredients as list, instructions as paragraphs)

Example Formats

Structured

Chocolate Chip Cookies

Ingredients:
- 2 1/4 cups flour
- 1 cup butter

Instructions:
1. Preheat oven
2. Mix ingredients

Semi-Structured

CHOCOLATE CHIP COOKIES

2 1/4 cups flour
1 cup butter
2 cups chocolate chips

Preheat oven to 375. Mix butter and sugar.
Add flour. Fold in chips. Bake 10-12 minutes.

Narrative

To make chocolate chip cookies, you'll need 2 1/4 cups
of flour, 1 cup of butter, and 2 cups of chocolate chips.

First, preheat your oven to 375 degrees. Mix the butter
and sugar together, then gradually add the flour...

Confidence Scores

All importers calculate confidence scores to help you identify recipes that may need review.

Score Components

{
  confidence: {
    overall: 0.85,          // Combined score (weighted average)
    structure: 0.9,         // Has required fields (title, ingredients, steps)
    ingredients: 0.8,       // Ingredient parsing quality
    instructions: 0.9,      // Instruction parsing quality
    metadata: 0.7           // Optional fields (times, servings, images)
  },
  issues: [                 // Specific problems detected
    {
      field: "servings",
      severity: "warning",
      message: "Servings not found; defaulting to 4"
    }
  ]
}

Quality Guidelines

Overall ScoreRecommendationAction
0.9 - 1.0ExcellentReady to use
0.7 - 0.89GoodMinor review recommended
0.5 - 0.69FairReview and edit before use
< 0.5PoorRequires manual editing

Common Issues

Low Structure Score:

  • Missing title
  • No ingredients or instructions
  • Malformed data

Low Ingredient Score:

  • Few ingredients detected (< 3)
  • No quantities or units
  • Ambiguous ingredient names

Low Instruction Score:

  • Few steps (< 2)
  • Steps are too short or vague
  • No cooking instructions detected

Low Metadata Score:

  • Missing prep/cook times
  • No servings specified
  • No images available

Import failures

classifyImportFailure maps fetch/parse errors to 400. AI Gateway down is import_ai_unavailable (503), not from classify.

codeHTTPWhen
not_a_public_url400Private or loopback http(s) address
import_blocked400Site blocked the importer
import_page_private400Page is private or needs a sign-in
import_page_gone400Page is gone
import_not_a_recipe400No recipe found, including leftover AI_* errors that are not unavailable
import_unsupported_site400Site is not supported
import_ai_unavailable503Gateway / model down, overloaded, or rate-limited. Retry-After: 60

MCP: classified codes are JSON-RPC -32602. import_ai_unavailable is -32603.

Import Strategy

For best results, use importers in this order:

  1. URL Import (highest quality)

    • Use when recipe is on a website
    • Most reliable and complete
  2. Photo Import (good for physical media)

    • Use for recipe cards, cookbooks
    • Requires good lighting and focus
  3. Paste Import (flexible fallback)

    • Use for email recipes, PDFs, or OCR text
    • Most forgiving of format variations

Next Steps