---
title: "mercadona prices by postcode: what changes from zone to zone"
description: "mercadona prices by postcode, read daily in 174 zones. on the mainland they match, except sugary drinks in catalonia because of a tax. plus how i collect them."
date: 2026-10-08
author: "joel taylor pedrós"
lang: en
url: https://joeltaylor.business/blog/mercadona-prices-by-postcode
translations:
  ca: https://joeltaylor.business/blog/preus-mercadona-per-zones
  es: https://joeltaylor.business/blog/precios-mercadona-por-zona
image: https://joeltaylor.business/_next/static/media/cover.en.0exq50iiqezcx.webp
---

# mercadona prices by postcode: what changes from zone to zone

![a grid of 174 squares, one per zone of mercadona's online shop, with catalonia's 21 zones in blue.](https://joeltaylor.business/_next/static/media/cover.en.0exq50iiqezcx.webp)

in catalonia, a 2-litre bottle of hacendado cola costs €1.10. in madrid or seville, €0.80.

since 14 september i've had a program reading mercadona prices by zone every day, for every product in the online shop. on 6 october it read 743,112 of them, spread over 174 zones, about 4,270 per zone. it's a personal project with no connection to mercadona.

## what a mercadona zone is

every order from the online shop is put together by a warehouse, and the warehouse decides the catalogue and the prices. when you type your postcode on the website, the server answers with a header, `X-Customer-Wh`, that says which warehouse you get: `bcn1`, `mad3`, `svq1` or a number.

to find them all, the program asks about postcodes. the candidates come from geonames, and it tries 300 a day. it starts with the first postcode in each province, then the second, so the map covers the whole country early instead of working alphabetically from álava to zaragoza. if the shop answers 404, it doesn't deliver there, and the program doesn't ask again for 90 days.

on the site and here i call it a zone. for the analysis, each zone gets the province that comes up most among its postcodes. catalonia is the 21 zones in provinces 08, 17, 25 and 43. the canary islands have 17, and the mainland 144.

## the mercadona catalogue in 6 queries

the shop's search runs on algolia, and each warehouse has one index per language, like `products_prod_bcn1_ca`. the program reads the catalan one. an empty query returns 1,000 results at most, and a warehouse has about 4,300. so mercapy, the python library that does the work, splits the catalogue up.

first it asks for a single result, which comes with the product count for each top-level category. then it shares the categories out, largest first, into groups of no more than 1,000, and runs one query per group with an `OR` filter. if a group returns more than 1,000, because the counts moved between one query and the next, it splits it in two. since version 2.3.0, from 4 october, a warehouse takes 6 requests. it used to take 27.

three warehouses had failed since day one because their catalan index has no categories to filter on. for those, the library splits by ranges of a numeric field in the index, `score`, and halves any range that goes over 1,000.

at the end, the program counts the unique products and compares them with the total algolia reports. if they don't match, the collection is marked as degraded and changes nothing. a half-finished collection can't make any product disappear, and for a product to stop being listed in a zone it has to be missing two days in a row.

timing matters too. mercadona changes its prices between 2 and 4 in the morning. of the 296 nationwide changes i could date, 272 fell in that window, which is why the collection day starts at 5. before, each warehouse waited 24 hours from its last success. since the cron runs every two hours, each day's run came two hours later than the last, until a day got skipped. up to 4 october that lost 147 of 2,141 warehouse-days, 7%.

## only what changes gets stored

if i copied the whole catalogue every day, at about 1.6 kb per product, that would be over 1 gb of json a day, almost all of it repeated.

the program uses three tables. `product_state` has one row per product and zone with the current price. `product_version` only adds a row when the product changes in that zone. each state also remembers which version was in effect at the end of the previous day, and today's changes are worked out against that one.

on 5 october there were 820,298 versions, and most of them said the same thing, because a product reads the same in almost every warehouse. there were only 19,128 distinct summaries. now each summary is stored once, in a table keyed by the hash of its json, and the versions point to it. the versions table went from 1.6 gb to 172 mb, plus 32 mb of summaries. the whole database, from 2,096 mb to 735 mb.

before that i tried timescaledb, pg-xpatch, forward and backward diffs, and lz4. timescaledb took up less space, but lost the unique index on the open version and the foreign key from `product_state`. pg-xpatch silently dropped rows in a batch copy.

![diagram of three tables. product_state, one row per product and zone, 743,112 prices available on 6 october, points to product_version, a new row only when the product changes, 820,298 versions on 5 october, which points to summary_payload, each distinct summary stored once, 19,128 summaries.](https://joeltaylor.business/_next/static/media/taules.en.2b93nhd6-na58.webp)

_820,298 versions, but only 19,128 distinct summaries._

## which price gets compared

a product has several prices: the shelf price, the previous one if it's reduced, and the price per kilo or per litre. changes compare just one of them, `tracked_price`.

for fixed-size products it's the shelf price. for variable-weight ones, like fish or meat cut to order, it's the price per kilo. in the data i looked at to decide this, there were 370 variable-weight products sold in two or more warehouses. 156 had the same price per kilo with different basket prices, and only 3 had a genuinely different price per kilo. a hake that costs €12.77 in seville and €17.14 in barcelona is €11.50/kg in both. only the weight of the piece changes.

for fish counter products bought by weight, mercadona publishes as the price the price per kilo times the size, or times 99 when there's no size. a frozen prawn was the most expensive product in the database, at €3,663. it didn't affect any comparison, because those products are tracked by price per kilo, but the shop shows the price of one step, from 0.15 to 0.4 kg, and now the program does too.

reductions are handled separately. mercadona's api has a field that should say whether a price has dropped, and across 397,000 stored states it has never been `true`. the program recognises a reduction by the previous price struck through next to it, and stores it as a marked reduction. an observed drop is a tracked price lower than the one at the end of yesterday, in the same zone. if there are two collections in a day, the changes are recalculated against the same baseline, so two collections on the same afternoon can't invent a drop and a rise.

## one price on the mainland, except in catalonia

of the 4,861 products sold in at least 20 mainland zones on 6 october, only 32 had prices that varied by zone. that's under 1%.

29 of those 32 are sugary drinks: 8 sizes of coca-cola, 3 of hacendado cola, 4 monster, 2 red bull, 6 hacendado milkshakes and milk drinks, the hacendado energy drink, 2 dairy drinks with cereal, the horchata and 2 hacendado tonics. all of them cost more in the 21 catalan zones and in no others. the zero versions cost the same everywhere.

![dot chart of prices on 6 october 2026. 2-litre hacendado cola, €1.10 in catalonia and €0.80 in the rest of the mainland; the zero, €0.80 in both. 2-litre coca-cola, €2.52 and €2.15; the zero, €2.15. half-litre monster energy, €1.55 and €1.45; the ultra zero, €1.45. 1.2-litre hacendado chocolate milkshake, €1.66 and €1.55; the 0% added sugar one, €1.85.](https://joeltaylor.business/_next/static/media/cola-catalunya.en.2-e0f5n-id445.webp)

_within each group, every zone had the same price._

it's catalonia's tax on packaged sugary drinks, which is €0.10 per litre if the drink has between 5 and 8 grams of sugar per 100 ml, and €0.15 if it has more. on the 2-litre hacendado cola the difference is €0.30, exactly €0.15 per litre. on the 2-litre coca-cola it's €0.37, and on the half-litre monster, €0.10. those don't come out as neatly.

of the 32, the other 3 are two lemon products and the whole frozen chicken breasts.

## the canary islands, the most expensive fruit

82 fruit and veg products are sold both in the canary islands and in at least 20 mainland zones. comparing the median in each place, 64 cost more on the islands and 5 cost less. broccoli is €5.80/kg in the 17 canary zones, unchanged since 14 september, and €2.70/kg in the other 157.

## three weeks, and nearly everything goes up

i took the 71 zones with a complete collection on both 14 september and 6 october. i kept 3,526 products sold by the unit, the ones sold in at least 30 of those zones with no struck-through price on either day. a product counts as a rise if it went up in most of its zones.

90 went up. 2 went down, hacendado semi-skimmed and skimmed milk, by 1 cent each and in all 71 zones. none of the 92 changed size.

the number depends on the start date. if i start counting on 15 or 16 september, the rises are 78 and 59. the drops are still the same 2.

![bar chart of the ten products that rose most between 14 september and 6 october 2026, out of 90. top is the hacendado almond chocolate ice cream bars, from €2.70 to €3.30, up 22.2%. the only two that fell are hacendado semi-skimmed milk, from €0.84 to €0.83, and skimmed, from €0.82 to €0.81.](https://joeltaylor.business/_next/static/media/pujades-i-baixades.en.0gg_t7jrknax7.webp)

_the ten biggest rises out of 90, and the only two drops._

seasonal fruit moves faster. on 14 september, piel de sapo melon cost €0.70/kg on the mainland. on the 21st it went to €0.90, on the 29th to €1.35 and on 6 october to €2.20, in all 144 mainland zones.

## what's still missing

the site that will show all this, in catalan, isn't public yet. you'll enter your postcode and see the price of every product in your zone and how it has changed since 14 september.

all of this comes from three weeks of data. the plan is to leave the program collecting every day for years, and the collection was the first thing i built because a price that isn't read today can't be recovered later.
