Skip to content

Spoonacular alternatives: what to use instead, and what it costs

Why people leave Spoonacular, what to use instead, and how to move your recipe calls over.

Spoonacular is often the first recipe API people find. It's big, it's well documented and the free key takes a minute to get. Then, a few weeks in, the questions start. Why did that request cost three points? Why am I out of quota at lunchtime? Wait, I have to delete my cache after an hour?

If that sounds familiar, this post is for you. We'll be fair about what Spoonacular does well, go through the alternatives, and then show how to move your recipe calls over. Full disclosure: we run one of those alternatives, Tiny Plates. We'll say so when something else is the better fit.

Everything about Spoonacular below comes from its pricing page and terms, checked in October 2026.

Why people look elsewhere

Points are hard to predict. Spoonacular doesn't count requests. It counts points. A recipe search costs 1 point plus 0.01 for each result, and some options add more. That's fair in a way, since bigger answers cost more. But it makes budgeting tricky. One screen in your app might cost one point or five, depending on what it asks for.

The free plan is small. It's 50 points a day, at 1 request per second, with a backlink to Spoonacular required. When the points run out, you get a 402 error until the next day. That's enough to try things. It's tight for a demo that more than a few people use.

The cost grows fast. Paid plans are $29 a month for 1,500 points a day, $79 for 4,500 and $149 for 10,000. Enterprise starts at $300. Extra points cost between $0.002 and $0.005 each, depending on the plan. For a small app that's fine. For a side project with no income, it can sting.

The caching rules. This is the one that surprises people most. The terms allow caching for at most one hour, and only with written permission. You can keep the recipe id, title and image URL forever, and nothing else. If you stop using the API, you're meant to delete everything you ever got from it. So you can't build a favourites screen that works offline, or slowly grow your own recipe library. Every view is a fresh call.

Attribution. You need to credit the original recipe source with a link. That's normal for recipe data, and most APIs ask for something similar. Just plan for it in your design.

To be fair, Spoonacular covers a lot of ground. One key gets you recipes, 600K+ grocery products, 115K+ restaurant menu items, meal planning, wine pairings, price estimates and health scores. Nothing else does all of that in one place.

The paid plans come with an uptime promise: 99% on the $29 and $79 plans and 99.9% on the $149 plan. It also has an MCP server for agents. If you need grocery products or menus, or you need a signed uptime promise today, stay with Spoonacular. Switching would mean stitching three APIs together.

The alternatives

We wrote a longer rundown in the best recipe APIs in 2026. Here's the short version, from the angle of someone leaving Spoonacular.

Edamam is the pick if you need size. Over 2 million web recipes and very good nutrition data. There's no free plan for Recipe Search, and it starts at $9 a month for 10,000 calls. The catch: on the $9 and $99 plans, the cooking steps aren't in the response. You link out to the source. Caching is just as tight, limited to the recipe id and name, plus a few nutrition numbers on the higher plans.

TheMealDB is the pick for learning and demos. No sign-up, a free test key and simple JSON. It's small, with 793 meals when we checked, and ingredients are plain text. Going public needs a one-off $10 supporter upgrade.

API Ninjas has a recipe endpoint with over 125,000 recipes and structured ingredients. The free plan is 3,000 calls a month, but it's for evaluation only. Commercial use needs a paid plan.

FatSecret Platform is the pick if nutrition is the main event. Its free Basic tier allows 5,000 calls a day with US data and attribution. Recipes are part of a bigger food and nutrition database.

Tiny Plates is ours. It's free, with 50 requests a day and 300 a week per account. No credit card, no backlink for the API itself, and we raise the limit on request. One call is one request, whatever it returns. You may cache the recipes your users open, with no one-hour rule. You just can't copy the whole index.

It goes deep on the recipe. Every ingredient has quantity, unit, name and preparation in separate fields, with an ingredient id shared across English, Spanish and Swedish recipes. Every recipe says which of 16 allergens it contains. You also get scaling, metric and imperial conversion, substitutions, cooking from the fridge and one shopping list for a whole week.

What it doesn't have: grocery products, restaurant menus, wine pairings, price estimates or an uptime promise. And thousands of recipes, not millions. If you need those things, it's not your answer yet. We put the full side-by-side on Tiny Plates vs Spoonacular.

Moving your recipe calls over

The good news is that the main calls map one to one.

What you're doing Spoonacular Tiny Plates
Search recipes GET /recipes/complexSearch?query=pasta GET /search?query=pasta
Leave out an allergen &intolerances=dairy &without=milk
Cook from what you have GET /recipes/findByIngredients?ingredients=chicken,rice GET /pantry?ingredients=chicken,rice
Get one recipe GET /recipes/{id}/information GET /recipes/{id}
Shopping list Meal planner shopping list GET /shopping-list?recipes=id1,id2

Want a recipe for six instead of four? Add ?servings=6 to the recipe call and every amount is rewritten. With Tiny Plates you send the key as a header: Authorization: Bearer rd_your_api_key. The allergen names are different, so dairy becomes milk, egg becomes eggs and peanut becomes peanuts. The full list is at /vocabularies. If you send a name we don't know, you get a clear error instead of a silent miss.

One difference to know about. On a free account, search doesn't take cuisine, diet or time filters. Each result does carry cuisines, dietary flags and times, so you can filter on those yourself after the search.

The recipe fields map like this:

Spoonacular Tiny Plates
id (a number) id (a string)
title title
image media, the item with role: "hero"
servings servings.quantity
readyInMinutes times.total.seconds, divided by 60
sourceUrl url
extendedIngredients[].name ingredients[].name
extendedIngredients[].amount and .unit ingredients[].quantity.value and .unit
extendedIngredients[].original ingredients[].original (or display)
analyzedInstructions[0].steps[].step instructions[].text
cuisines cuisines
dishTypes courses
vegetarian, vegan, glutenFree, dairyFree dietary.vegetarian, .vegan, .glutenFree, .dairyFree

Times are in seconds, not minutes. A dietary flag can be missing, which means we don't know. false means a known no. And display is the line we'd show a cook. It's tidied up, and it follows scaling and unit conversion. original is exactly what the source wrote.

If your UI already reads Spoonacular's shape, the quickest move is a small adapter. Fetch from Tiny Plates, then hand your components the fields they expect:

const API = 'https://api.tinyplates.dev'
const headers = { Authorization: `Bearer ${process.env.TINY_PLATES_KEY}` }

export async function getRecipe(id, servings) {
  const query = servings ? `?servings=${servings}` : ''
  const response = await fetch(`${API}/recipes/${id}${query}`, { headers })

  if (!response.ok) {
    throw new Error(`Tiny Plates answered ${response.status}`)
  }

  const { recipe } = await response.json()

  return toSpoonacularShape(recipe)
}

function toSpoonacularShape(recipe) {
  const hero = recipe.media.find((item) => item.role === 'hero')
  const totalSeconds = recipe.times.total?.seconds

  return {
    id: recipe.id,
    title: recipe.title,
    image: hero?.url,
    servings: recipe.servings?.quantity,
    readyInMinutes: totalSeconds ? Math.round(totalSeconds / 60) : undefined,
    sourceUrl: recipe.url,
    cuisines: recipe.cuisines,
    dishTypes: recipe.courses,
    vegetarian: recipe.dietary?.vegetarian ?? false,
    vegan: recipe.dietary?.vegan ?? false,
    glutenFree: recipe.dietary?.glutenFree ?? false,
    dairyFree: recipe.dietary?.dairyFree ?? false,
    extendedIngredients: recipe.ingredients.map((line) => ({
      name: line.name,
      amount: line.quantity?.value,
      unit: line.quantity?.unit ?? '',
      original: line.display
    })),
    analyzedInstructions: [
      {
        name: '',
        steps: recipe.instructions.map((step) => ({
          number: step.step,
          step: step.text
        }))
      }
    ]
  }
}

Note the ?? false on the diet flags. That keeps Spoonacular's yes-or-no shape, but it turns "we don't know" into "no". It's a safe default for a badge. If you'd rather show "unknown", leave the value as it is.

Once that works, you can drop the adapter bit by bit. The richer fields are worth it. preparation gives you "finely chopped" on its own. ingredientId lets you match the same ingredient across recipes. And allergens gives you a plain true or false for each of 16 allergens. Here's what that adds up to in a weekly meal planner:

Live, on the real API

What's for dinner this week?

Easy lunches, weeknight dinners that don't fuss, and something to linger over at the weekend.

Anything we should keep in mind?

Your week goes here, Monday to Sunday, lunch and dinner. Don't fancy something? Swap it for another.

What about the data you already stored? Under Spoonacular's terms you can keep the recipe ids, titles and image URLs. Those ids won't match ours, so search by title to find a similar recipe. The rest of the cache has to go anyway when you stop using the API.

You don't have to move everything at once, either. Lots of apps keep Spoonacular for grocery products and use another API for recipes. That's a perfectly good setup.

If you want to try it, grab a free key and point one screen at it. You'll know within an afternoon if it fits.