DEV Community

FlexTeam26
FlexTeam26

Posted on

Building CocktailsABC: 652 normalized recipes and a 'what can I actually make' engine

I kept hitting the same wall with cocktail sites: a 1,400-word story about the Negroni before I find out whether I can actually make one. So I built cocktailsabc.com around one question — what can I make from the bottles on my shelf right now?

The core feature: My Bar

You pick the bottles you own. The site returns every recipe you can make, ranked by how few ingredients you're missing. Two missing items is a shopping list; zero missing is tonight's drink.

Sounds trivial until you look at the data underneath it.

The actual problem was ingredient normalization

Recipe sources are a mess:

  • "sweet vermouth" vs "red vermouth" vs "Italian vermouth" — same thing
  • "dry sherry" vs "fino" — same thing, different granularity
  • garnishes counted as ingredients in some sources, not others
  • "bar spoon", "barspoon", "1 dash" — units that mean nothing to a matching engine

So the pipeline is:

  1. Collect recipes from public sources, keep the original text.
  2. Normalize ingredient strings into canonical IDs with an alias table (the alias table is 80% of the work).
  3. Classify each line: ingredient, substitution, or garnish. Garnishes don't block a match.
  4. Index the result as a set of canonical ingredient IDs per recipe.
  5. Match against the user's inventory as a set-submission test, then rank by |recipe_set - inventory|.

The ranking is boring on purpose — a missing-count sort beats any clever scoring once the ingredient IDs are clean. Garbage IDs make every algorithm downstream look bad.

Public dataset

652 normalized recipes (tagged, with canonical ingredient IDs) are published as a dataset on Zenodo: DOI 10.5281/zenodo.24041819. CSV and JSONL. If you want to build on top of it, it's there.

Indexing and AI discoverability

Small site, so no ad budget — the play is being findable:

  • full sitemap + llms.txt so AI assistants can cite the recipe pages
  • IndexNow submissions on every publish (Bing/Yandex pick up within minutes)
  • one clean URL per recipe, canonical tags, hreflang for the localized hubs

What I'd genuinely like feedback on

  • Is "missing ingredient count" the right ranking, or should it weight how likely you are to already own it (bitters, simple syrup)?
  • Substitution handling: should "replace Campari with Aperol" show as a match or a separate tier?
  • What would make a recipe dataset trustworthy enough for you to build on?

Stack: TypeScript front end, Python crawl/normalize pipeline, served on Kubernetes in my homelab.

Try it: cocktailsabc.com — dataset DOI 10.5281/zenodo.24041819.

Top comments (0)