🇮🇹 Esselunga Example solution JavaScript /parse + /products

Italian Sunday Lunch at Esselunga — Parsing Osso Buco from a Food Blog

This parses a traditional Italian recipe from a food blog using Pepesto's /parse endpoint, then matches each ingredient to the best available Esselunga product via /products. The output is a complete Italian shopping list with product names and prices.

Run this yourself

$ PEPESTO_API_KEY=your_key node esselunga-italian-sunday-lunch.js

Full script: esselunga-italian-sunday-lunch.js. You'll need an API key to run it — get one here.

Getting started

bash
export PEPESTO_API_KEY=your_key_here
node esselunga-italian-sunday-lunch.js

The first call — parsing the recipe

js
const res = await fetch('https://s.pepesto.com/api/parse', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${process.env.PEPESTO_API_KEY}`,
  },
  body: JSON.stringify({
    recipe_url: 'https://www.giallozafferano.it/ricette/osso-buco-alla-milanese.html',
    locale: 'it-IT',
  }),
});
const { recipe } = await res.json();

The response gives a clean, structured ingredient list with quantities and categories — nothing like the wall of text on the original page:

json — /parse response
{
  "recipe": {
    "title": "Osso buco alla milanese",
    "ingredients": [
      "4 osso buco (veal shank slices, ~1.2kg)",
      "50g plain flour",
      "80g butter",
      "1 onion (~150g)",
      "1 carrot (~100g)",
      "1 celery stalk",
      "200ml dry white wine",
      "300ml beef stock",
      "400g canned chopped tomatoes",
      "2 garlic cloves",
      "1 lemon, zest only",
      "30g fresh parsley",
      "salt",
      "black pepper",
      "olive oil"
    ],
    "nutrition": {
      "calories": 2840,
      "carbohydrates_grams": 62,
      "protein_grams": 198,
      "fat_grams": 142
    },
    "kg_token": "EjMKMU9zc28gYnVjbyBhbGxhIG1pbGFuZXNlSjY..."
  }
}

The second call — matching to Esselunga products

Pass the kg_token to /products with supermarket_domain: "spesaonline.esselunga.it". The API knows Esselunga's catalog and returns real product names in both Italian and English where available.

js
const productsRes = await fetch('https://s.pepesto.com/api/products', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${process.env.PEPESTO_API_KEY}`,
  },
  body: JSON.stringify({
    recipe_kg_tokens: [recipe.kg_token],
    supermarket_domain: 'spesaonline.esselunga.it',
  }),
});
const { items } = await productsRes.json();
json — /products response (excerpt)
{
  "items": [
    {
      "item_name": "Flour",
      "products": [
        {
          "product": {
            "product_name": "Esselunga Organic soft wheat flour, Type 00",
            "product_name_it": "Esselunga Bio Farina di grano tenero tipo 00",
            "quantity": { "grams": 1000 },
            "price": { "price": 129, "promotion": {} },
            "classification": { "is_bio": true }
          },
          "session_token": "eyJwcm9kdWN0...",
          "num_units_to_buy": 1
        },
        {
          "product": {
            "product_name": "Molino Spadoni Gran Mugnaio soft wheat flour, Type 00",
            "product_name_it": "Molino Spadoni Gran Mugnaio Farina di grano tenero tipo 00",
            "quantity": { "grams": 1000 },
            "price": { "price": 163, "promotion": {} }
          },
          "session_token": "eyJwcm9kdWN0...",
          "num_units_to_buy": 1
        }
      ]
    },
    {
      "item_name": "Butter",
      "products": [
        {
          "product": {
            "product_name": "Esselunga Burro dolce di panna 250g",
            "quantity": { "grams": 250 },
            "price": { "price": 219, "promotion": {} }
          },
          "session_token": "eyJwcm9kdWN0...",
          "num_units_to_buy": 1
        }
      ]
    },
    {
      "item_name": "Semolina",
      "products": [
        {
          "product": {
            "product_name": "Esselunga Organic durum wheat semolina",
            "product_name_it": "Esselunga Bio Semola di grano duro",
            "quantity": { "grams": 1000 },
            "price": { "price": 189, "promotion": {} },
            "classification": { "is_bio": true }
          },
          "session_token": "eyJwcm9kdWN0...",
          "num_units_to_buy": 1
        }
      ]
    }
  ]
}

What the data showed

The parser extracted 15 clean ingredients from a page that had them scattered across three separate sections. All 15 matched to Esselunga products. For flour, the API returned two options: the Esselunga Bio Farina di grano tenero tipo 00 (€1.29/kg) and the Molino Spadoni Gran Mugnaio version (€1.63/kg) — both valid, different price points.

Italian product names in the response are exact as they appear on the Esselunga site: "Esselunga Bio Semola di grano duro" rather than a generic "semolina" label. This is useful when the shopping list needs to be recognisable to the person doing the actual buying.

The veal shank — the centrepiece of the dish — was available as a special-order item, with num_units_to_buy: 4 correctly calculated from the 1.2kg quantity in the recipe.

The result

What started as a messy recipe page became a structured shopping list in one API call, then a set of real Esselunga products in a second call. The session tokens go into /api/session to create the checkout. Total elapsed time from script start to having a basket URL: about four seconds.

What else you could do?

Add a "serves N" multiplier to scale quantities before calling /products — osso buco for 12 is a different basket than osso buco for 4. Add logic to prefer DOP or IGP certified products when the recipe is explicitly Italian regional — the tags field and product names surface this. Add a Conad fallback: if an ingredient isn't available at Esselunga, retry the same kg_token against spesaonline.conad.it.

Links

Ready to build?

Start building Italian recipe carts at Esselunga

Parse any Italian recipe and match ingredients to live Esselunga products — two calls, one key.

27supermarkets 13countries 1schema Instant access