Mercadona Scraper - Prices, Unit Price & Postal Code avatar

Mercadona Scraper - Prices, Unit Price & Postal Code

Pricing

from $1.00 / 1,000 product results

Go to Apify Store
Mercadona Scraper - Prices, Unit Price & Postal Code

Mercadona Scraper - Prices, Unit Price & Postal Code

Scrape Mercadona products by delivery-area postal code. Search by keyword or category, or paste product and category URLs. Get local availability, current price, site-calculated price per kg, litre or unit, plus original price and discount when an item is on sale.

Pricing

from $1.00 / 1,000 product results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

0

Bookmarked

6

Total users

0

Monthly active users

6 days ago

Last modified

Share

Mercadona Scraper: Prices, Unit Price and Was-Price by Postal Code

Mercadona Scraper pulls product data from tienda.mercadona.es, Spain's largest supermarket chain. Every run starts from a Spanish postal code, because Mercadona's catalogue, availability and prices are zoned by delivery warehouse. Search by keyword, browse a real category, or paste product and category links directly. Every record carries the current price, the real per-kg/L/unit reference price the site itself computes, and a genuine was-price with discount whenever one actually exists, plus brand, EAN, origin and the full image gallery on request. Export to JSON, CSV or Excel, pull it through the API, or pipe results into your apps.

Why This Scraper?

  • Zoned by real delivery area. Give it a Spanish postal code and it resolves the same delivery warehouse the live site would use for that address, so catalogue, availability and prices match what a shopper there actually sees. A postal code with no delivery zone stops the run with a clear error, instead of a quietly empty dataset.
  • Real per-unit price, not computed after the fact. Mercadona's own catalogue returns a per-kg/L/unit reference price alongside the package price, captured as is, never derived from a guessed pack size.
  • Was-price captured only when it's real. Mercadona is a low-price retailer with very few promotions, so most products simply carry no was-price at all. This scraper checks the site's own previous-price field per item and only ever sets a was-price and discount when that field is genuinely populated and higher than the current price.
  • Own-brand aware. Hacendado, Deliplus, Bosque Verde and every other brand come through as the site's own structured brand field, once product detail is fetched, not guessed from the product name.
  • A keyword or a category browse, not both at once. A keyword goes straight to the site's own search index across your whole delivery zone. Leave it empty to walk the real category tree instead, and use Category to scope that walk to one aisle or group.
  • Three ways in. Keyword search or category browsing, both with brand, price and discount filters and a sort order, or paste any product or category link directly.
  • Optional export to your apps. Send results into Notion, Linear, Airtable, or any Apify MCP connector, alongside the dataset.

Use Cases

  • Grocery price tracking: monitor price, unit price and discount changes for chosen aisles or brands over time, by delivery zone.
  • Own-brand and private-label research: track Hacendado, Deliplus and Bosque Verde pricing and availability across categories.
  • Retail and category management: benchmark unit pricing (per kg or L) and pack sizes across a whole aisle.
  • Shopping assistants and price-comparison tools: look up a pasted product link on demand for the current price and availability in a shopper's own postal code.

Data You Get

Sample shape: values are illustrative placeholders, not from a live record.

FieldExample
productId / slug"7823456" / "sample-product-hacendado"
name"Sample Product Hacendado"
brand"Hacendado" (needs fetchDetails)
category / categoryPath"Sample Subcategory" / ["Sample Group", "Sample Aisle", "Sample Subcategory"]
packaging"Botella"
url / imageproduct page link / card image URL
price / currency1.85 / "EUR"
unitPrice / unitPriceFormat11.08 / "kg"
packageSize / packageSizeFormat0.167 / "kg"
previousPrice / discountAmount / discountPercent2.2 / 0.35 / 15.9
isOnSpecialtrue
isPack / hasUnitSelector / isNewArrivalfalse / true / false
onlineAvailable / publishedtrue / true
isWater / requiresAgeCheckfalse / false
maxQuantityPerOrder12
sellingMethod / taxPercentage / iva0 / 4.0 / null (iva is the site's separate VAT rate field, e.g. 10, set only on some products; taxPercentage is a different field and is not the same value)
isApproxSize / hasBunchSelector / priceDecreasedfalse / false / false
minBunchAmount / incrementBunchAmount / drainedWeight / packSize / totalUnits / unitNamesite's own pricing-unit values, null when not applicable
status / unavailableFrom / unavailableWeekdaysthe site's availability markers, null when available
topCategoryId / topCategoryLevel / topCategoryOrderid, level and display order of the top-level aisle group
ean / origin"8412345678904" / "España" (needs fetchDetails)
suppliers["Sample Supplier S.L."] (needs fetchDetails)
description / ingredients / allergenslegal description text, ingredients text, allergens text (needs fetchDetails)
imagesfull-resolution photo gallery (needs fetchDetails)
reviews[] (Mercadona has no product review system, on every record)

A pasted product link, a Brand filter, or the Fetch full product detail toggle also add legalName, usageInstructions, storageInstructions, mandatoryMentions, dangerMentions, isBulk and isVariableWeight, all pulled from the same product-detail page.

How to Use

  1. Pick a mode: search (keyword and/or category browse for a delivery zone) or url (paste product or category links).
  2. Set Postal code to a real Spanish postal code. It decides your delivery zone, catalogue, availability and prices, in every mode.
  3. In search mode, either give a keyword, which searches the whole delivery zone directly, or leave it empty and set Category to walk one real aisle or group (leave both empty to browse the whole catalogue). Add brand, price and specials filters and a sort order as needed.
  4. Set Max products total (and Max categories per search, for a category browse) to control run size and cost, then click Start.

Keyword search across the whole delivery zone:

{
"mode": "search",
"postalCode": "28001",
"searchTerm": "aceite de oliva",
"maxItems": 20
}

Browse one real aisle, Hacendado only, currently on special, sorted by price:

{
"mode": "search",
"postalCode": "28001",
"category": "Aceite, vinagre y sal",
"brands": ["Hacendado"],
"specialsOnly": true,
"sortBy": "PRICE_ASC",
"maxItems": 50
}

Paste a product link (full detail, brand, EAN, ingredients, image gallery, is always fetched for it):

{
"mode": "url",
"postalCode": "28001",
"urls": ["https://tienda.mercadona.es/product/4241/aceite-oliva-04o-hacendado-garrafa"]
}

Paste a category link and walk the whole aisle:

{
"mode": "url",
"postalCode": "28001",
"urls": ["https://tienda.mercadona.es/categories/112"],
"maxItems": 100
}

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/mercadona-es-scraper").call(run_input={
"mode": "search",
"postalCode": "28001",
"searchTerm": "aceite de oliva",
"maxItems": 20,
})
for product in client.dataset(run["defaultDatasetId"]).iterate_items():
print(product["name"], product["price"], product["currency"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/mercadona-es-scraper').call({
mode: 'search',
postalCode: '28001',
searchTerm: 'aceite de oliva',
maxItems: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.

Keyword search versus category browse

A keyword (searchTerm) queries the site's own per-warehouse search index directly, across your whole delivery zone, and Category is not applied to that search. Results are then narrowed to products whose name actually contains your keyword, so the site's own tolerance for typos, plurals or word order is not carried through. Category only takes effect when no keyword is given (a plain category browse), or automatically, as a fallback, on the rare run where the search index itself is temporarily unreachable, in which case the run walks Category (or the whole catalogue, if Category is also empty) and matches the keyword against product names there instead. Setting both a keyword and a category does not scope the keyword search to that category.

Filters, price band and sort order

searchTerm, specialsOnly, minPrice, maxPrice, brands and sortBy apply in search mode, and in url mode when the pasted link is a category link. A pasted product link always ignores all of them and is returned as is. sortBy sorts within whichever category or search page is being collected; for one fully sorted aisle, set a single Category and leave the keyword empty (Category is not applied when a keyword is set). Mercadona also has no product review system, so reviews is always an empty array on every record, a real absence on the site itself, not a scraping gap.

Send results into your apps (MCP connectors)

Optionally pipe results into the apps you already use through Model Context Protocol (MCP) connectors. Authorize a connector once under Apify, Settings, Integrations, then select it in the mcpConnectors field. Each connector receives a condensed, human-readable summary per product (name plus key fields), while the complete record always stays in the Apify dataset. For Notion, also set notionParentPageUrl to the page the item pages should be created under, and use maxNotifyListings to cap how many items are exported per connector per run. Supported connectors: Notion, Linear, Airtable and Apify. Leave the field empty to skip, it never changes the dataset output.

Input Parameters

ParameterTypeDefaultDescription
modestringsearchsearch browses by keyword and/or category for your delivery zone; url scrapes pasted product or category links.
postalCodestring28001Spanish postal code that resolves your Mercadona delivery zone; scopes catalogue, availability and prices in every mode. Required; a code with no delivery zone stops the run.
languagestringesLanguage of names, categories and descriptions: es, en, ca, eu or vai (Valencian). Category names are matched in the chosen language; a numeric category id works in any language.
querystringnoneAlias of searchTerm, used only when searchTerm is empty.
categorystringnone (prefilled with Aceite, vinagre y sal)A real Mercadona category or group name/id, search mode only. Ignored in url mode, and not applied whenever a keyword is set, unless the search index itself is unreachable; empty browses every aisle.
urlsarraythree example links (one product, one category, one search-results)Product (/product/<id>), category (/categories/<id>) or search-results (/search-results?query=<keyword>) links to scrape, url mode only. Leaving the field untouched in url mode scrapes the three example links; clear it and add your own. A sub-aisle id (e.g. /categories/420) is located by looking through every aisle one at a time (each aisle is fetched once per run), then only that sub-aisle's products are scraped; an id that is not an aisle, group or sub-aisle logs a warning and scrapes nothing for that link. If the lookup cannot finish (for example the connection keeps failing), a separate Could not finish looking for category warning says how many aisles were checked and nothing is scraped for that link. If the site's category tree itself fails to load, a separate Could not load the category tree warning is logged and nothing is scraped for that link (the next link retries the load).
searchTermstringnone (prefilled with aceite de oliva)Keyword. In search mode it queries the site's own search index across the whole delivery zone, then keeps only hits whose name actually contains it; Category is not applied to it. In url mode it keeps only products in a pasted category link whose name contains the keyword; a pasted product link always ignores it.
specialsOnlybooleanfalseKeep only products carrying a genuine was-price higher than the current price. Applies in search mode and to a pasted category link; a pasted product link ignores it.
brandsarraynone (prefilled empty)Exact brand names to keep. Automatically turns on full product-detail fetching so brand can be checked (stops checking further candidates once enough matches are found), applies the same as specialsOnly.
minPricenumbernoneOnly return products priced at or above this amount, in euros. Applies the same as specialsOnly.
maxPricenumbernoneOnly return products priced at or below this amount, in euros. Applies the same as specialsOnly.
sortBystringRELEVANCERELEVANCE (catalogue order in a category browse, the search index's own relevance order for a keyword search), PRICE_ASC or PRICE_DESC. Sorts within whichever category or search page is being collected.
fetchDetailsbooleanfalseAdds brand, EAN, origin, suppliers, full description, ingredients/allergens, storage/usage instructions and the full image gallery, billed once per product enriched. Always on for a pasted product link and whenever Brands is set, regardless of this toggle.
maxPagesintegernone (unlimited)In a category browse, stop after walking this many aisles; in a keyword search, stop after this many result pages (40 products each). Leave empty for no limit. Ignored for a single pasted product link.
maxItemsinteger20Hard cap on total products returned across the run. 0 means unlimited.
proxyobject{"useApifyProxy": true}Connection settings for the run. The run always connects through the Apify proxy when it runs on Apify, even if useApifyProxy is false and no custom proxy URLs are given (as in every earlier version). Supplying your own proxy URLs uses only those, with no automatic backup connection.
resumeFromRunIdstringnoneRun ID or dataset ID of an earlier run of yours; products already collected there are skipped and not charged again. For recurring monitoring use Incremental mode instead.
incrementalModebooleanfalseRemembers each product between runs. The first run returns everything as NEW; later runs return only NEW, UPDATED and REAPPEARED products. Adds changeType, changedFields, firstSeenAt and lastSeenAt to each row.
stateKeystringautoNames a monitoring campaign. Empty derives the key from mode, delivery zone, language, keyword, category, links, filters, sort and Fetch details (never Max products).
emitUnchangedbooleanfalseAlso return UNCHANGED products (billed like any returned product).
emitExpiredbooleanfalseAlso return products that disappeared since the last run, as EXPIRED. Only after a fully completed scan: never when Max products, Max pages, a skipped link or Resume cut the run short.
ignoreFieldsForChangesarraynoneOutput fields that should not count as a change. Ignored fields are still returned.
mcpConnectorsarraynoneOptional MCP connectors to export results into (Notion, Linear, Airtable, Apify).
notionParentPageUrlstringnoneNotion connector only: page under which item pages are created.
maxNotifyListingsinteger50Cap on items exported to each connector per run. Does not affect the dataset.

Output Example

Sample shape: values are illustrative placeholders, not from a live record.

{
"productId": "7823456",
"slug": "sample-product-hacendado",
"name": "Sample Product Hacendado",
"brand": "Hacendado",
"category": "Sample Subcategory",
"categoryPath": ["Sample Group", "Sample Aisle", "Sample Subcategory"],
"packaging": "Botella",
"url": "https://tienda.mercadona.es/product/7823456/sample-product-hacendado",
"image": "https://prod-mercadona.imgix.net/images/sample-card.jpg",
"price": 1.85,
"currency": "EUR",
"previousPrice": 2.2,
"discountAmount": 0.35,
"discountPercent": 15.9,
"isOnSpecial": true,
"unitPrice": 11.08,
"unitPriceFormat": "kg",
"packageSize": 0.167,
"packageSizeFormat": "kg",
"isPack": false,
"hasUnitSelector": true,
"onlineAvailable": true,
"published": true,
"isWater": false,
"requiresAgeCheck": false,
"maxQuantityPerOrder": 12,
"isNewArrival": false,
"ean": "8412345678904",
"origin": "España",
"suppliers": ["Sample Supplier S.L."],
"description": "Sample legal product description as shown on the site.",
"ingredients": "Sample ingredients text.",
"allergens": "Sample allergens text.",
"images": ["https://prod-mercadona.imgix.net/images/sample-zoom.jpg"],
"isBulk": false,
"isVariableWeight": false,
"reviews": []
}

Plan Requirement

The run reads the site through the Apify proxy, so your Apify plan must include proxy access: a paid plan is recommended. The run tries the default proxy connection first, then automatically tries other connections if one is refused. Residential access is not part of Apify free plans. If every connection is refused the run fails with a clear message rather than returning an empty dataset (see the FAQ below). You can also supply your own proxy URLs in the Proxy settings; with your own URLs the run uses only those and no automatic backup connection. Setting useApifyProxy to false without any proxy URLs does not disable the proxy: the run still uses the Apify proxy, unchanged from earlier versions.

FAQ

How much does it cost?

You pay per product returned, plus one detail-enrichment charge for every product whose full detail page is fetched and actually returned. That enrichment charge always applies to a pasted product link, and to every product returned under a Brand filter (products checked against the filter and rejected are not charged), on top of turning on Fetch full product detail yourself. A small one-time charge also applies when the run starts. The Pricing tab shows the current rates. Use Max products total to cap the cost of any run.

This actor collects only publicly available catalogue and price data. You are responsible for how you use it: follow Mercadona's terms and the laws that apply to you, and get legal advice before any commercial redistribution.

Why did my run fail instead of returning an empty dataset?

A run that never loaded a single usable page ends as Failed, never as a successful empty run. You will see one of these messages:

  • The proxy connection was refused for this account, so no page could be read, because your Apify plan does not include proxy access and a paid plan is required. Upgrade your plan, or check that your own proxy URLs have valid credentials if you entered any.
  • No results, because residential proxies are unavailable on this run (Apify free plans do not include them) and the backup connection could not load the requested Mercadona pages. Upgrade, or supply your own proxy URLs, then try again.
  • Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search; try again later.
  • "Postal code ... does not map to a Mercadona delivery zone" means the postal code is invalid; use 5 digits such as 28001.

On a free plan without residential access, the log also shows a warning that the selected connection is unavailable and the run continues on a backup connection; some pages may still be unavailable. If the site starts refusing requests after some products were collected, the run finishes with what it already has, which can be smaller than expected.

Six shapes: a product link with slug (/product/4241/aceite-...), a bare product link (/product/4241), a product link with ?lang=en, a category link (/categories/112), a category link with slug, and a search-results link (/search-results?query=aceite). A sub-aisle id (for example /categories/420) is located by checking every aisle one at a time and stops at the first one that contains it; only that sub-aisle's products are scraped. An id that is not an aisle, group or sub-aisle logs a warning and scrapes nothing for that link. If the lookup stops early (the connection keeps failing), a separate Could not finish looking for category warning reports how many aisles were checked, and nothing is scraped for that link. If the category tree itself fails to load, a separate Could not load the category tree for this delivery zone warning is logged instead (never the "not an aisle" one), nothing is scraped for that link, and the next category link retries the load. Note: the urls field has three example links as its default (a product, a category and a search-results link; the other shapes above resolve to the same products or aisle, so the form's prefill lists all six but only these three are the default), so an API call in url mode that omits urls scrapes those examples instead of nothing; pass your own list to avoid it.

Does setting both a keyword and a category narrow the search to that category?

No. A keyword goes straight to the site's own search index across your whole delivery zone, and Category is not applied to it. Leave the keyword empty and set Category to walk one real aisle or group instead. Category is only used together with a keyword automatically, as a fallback, if the search index itself is temporarily unreachable.

Can I track prices on a schedule?

Yes. Schedule the actor from the Schedules tab and turn on Incremental changes for scheduled runs. The first run returns every matching product as NEW; later runs return only what changed (NEW, UPDATED with the names in changedFields, REAPPEARED), which is how a price cut is spotted. Unchanged products are neither returned nor billed unless you turn on Emit unchanged. The extra detail-enrichment charge applies only to products actually returned, never to a suppressed unchanged one. Without incremental mode each run is a full snapshot.

Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.

🔗 Want more grocery data?

Pair this actor with these related scrapers from the same team:

🥦 Lidl.es Products, Weekly Offers, Prices & Reviews Scraper
Scrape Lidl.es grocery and non-food products across weekly offers, tools, home, garden...
🥦 Carrefour Spain Scraper
Scrape Carrefour Spain (carrefour.es) products. Search by keyword, browse a category, or...
🥦 El Corte Inglés Scraper
Scrape El Corte Inglés elcorteingles.es products across fashion, electronics, home...
🥦 Auchan France Scraper
Scrape Auchan.fr products: grocery, drinks, household and general merchandise. Real price...
🥦 E.Leclerc Scraper
Scrape E.Leclerc France (e.leclerc) grocery and retail products. Search by keyword or...
🥦 ResQ Club Scraper
Scrape ResQ Club surplus food offers in Finland, Sweden and Estonia: name, price, current...

👉 Browse all abotapi scrapers

💬 Support

  • 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
  • 🛠️ Need another site, extra fields or a private build? Email contact@abotapi.com.
  • ⭐ Enjoying it? A quick review on the actor page helps other users find it.