UK Grocery Prices: Tesco, Sainsbury's, Asda, Aldi
Pricing
from $1.39 / 1,000 products
UK Grocery Prices: Tesco, Sainsbury's, Asda, Aldi
Compare UK supermarket prices from Tesco, Sainsbury's, Asda, Aldi and Morrisons in one dataset.
Pricing
from $1.39 / 1,000 products
Rating
0.0
(0)
Developer
ParseBird
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
6 days ago
Last modified
Categories
Security
Limited permissionsShare
UK Grocery Prices: Tesco, Sainsbury's, Asda, Aldi
UK Grocery Prices compares supermarket prices from Tesco, Sainsbury's, Asda, Aldi and Morrisons in one dataset. Every product comes back in the same format: price, was-price, loyalty card price, unit price, offer text and end date, pack size, stock, category, rating, and a match key for lining up the same product across shops.
| Search five UK supermarkets at once, read whole categories or whole shops, or price a shopping list at every shop and get the cheapest basket. Clubcard, Nectar and More Card prices come back as their own field, separate from the shelf price. |
Copy to your AI assistant
Copy this block into ChatGPT, Claude, Cursor, or any LLM to start using this actor.
Apify Actor parsebird/uk-grocery-price-scraper compares UK supermarket prices from Tesco, Sainsbury's, Asda, Aldi and Morrisons in one row format. Call it with the apify-client package: client.actor("parsebird/uk-grocery-price-scraper").call(run_input={"mode": "search", "retailers": ["tesco", "sainsburys", "asda", "aldi", "morrisons"], "queries": ["semi skimmed milk"], "maxItems": 50}). Inputs: mode ("search" default, "category", "product", "catalogue", "basket"), retailers (array of "tesco","sainsburys","asda","aldi","morrisons"; default ["aldi","sainsburys"]; used in search, catalogue and basket mode), queries (array, max 50, default ["milk"]), categoryUrls (array, max 250, shop taken from each URL), productUrls (array, max 500), maxItems (int, default 100, 0 = no limit, split equally between shops), includeDetails (bool, adds ingredients and nutrition), priceHistory (bool, keeps weekly prices in a key-value store named uk-grocery-price-history and adds priceHistory once 2+ weeks exist), basket (array of lines like "2 x semi skimmed milk"), basketPricing ("live" or "snapshot"), basketPick ("cheapest" or "relevance"), useLoyaltyPrices (bool), asdaStoreId (string), outputDataset (named dataset to append rows to), datasetName (rename this run's dataset; placeholders {isoWeek}, {date}, {retailer}). Output: one dataset item per product with retailer, retailerProductId, ean[], matchKey, name, brand, packSize, price, wasPrice, unitPrice {value, measure}, loyaltyPrice, promotionText, promotionEndsAt, inStock, categoryPath[], url, imageUrl, rating {value, count}, scrapedAt, plus query/position or categoryUrl, and ingredients/nutrition/priceHistory when requested. Basket mode saves one row per basket line per shop (type "basketLine") and the totals plus cheapestRetailer in the key-value store record OUTPUT. Prices are in GBP. API docs: https://apify.com/parsebird/uk-grocery-price-scraper/api. Get a token: https://console.apify.com/settings/integrations
What is UK Grocery Prices?
UK Grocery Prices is a UK supermarket price comparison scraper for Tesco, Sainsbury's, Asda, Aldi and Morrisons. It reads the product data each supermarket shows on its own website and returns all five shops in one row format, so a Tesco row and an Asda row have the same fields and can sit in the same spreadsheet. It works as a UK grocery price API alternative: you send search terms, category links, product links or a shopping list, and you get clean JSON back.
The easiest way to try it: open the Input tab, keep the prefilled search semi skimmed milk with all five shops, and click Start. You get 20 products, 4 from each shop, in about 5 seconds.
What can UK Grocery Prices do?
- 🔍 Search five supermarkets at once: each search term runs in every shop you pick, and every row keeps its
queryandposition. - 🗂️ Read category pages: paste category links from any of the five shops; the Actor works out the shop from each link.
- 🏬 Read whole shops: Catalogue mode walks every grocery category of Tesco, Asda, Aldi or Morrisons.
- 🔗 Refresh known products: paste product links to re-price a fixed list, for example the products you track.
- 🛒 Price a shopping list: Basket mode matches each item in every shop, adds up the totals, and names the cheapest complete basket.
- 💷 Get every price: the shelf price, the was-price, the Clubcard, Nectar or More Card price, the unit price, and the offer text with its end date.
- 🥗 Add ingredients and nutrition: one switch adds the ingredients list and the nutrition table.
- 📈 Keep weekly price history: the Actor can store this week's prices in your account and add a
priceHistorylist once a product has two or more weeks.
On the Apify platform you also get scheduled runs, a full REST API, integrations with Make, Zapier, n8n, Google Sheets, Slack, and webhooks, and export to JSON, CSV, Excel, XML, or HTML.
What data can you extract from UK supermarkets?
| Field | Description |
|---|---|
retailer | tesco, sainsburys, asda, aldi or morrisons |
retailerProductId | The shop's own product ID |
name / brand | Product name and brand. Own-label products carry the shop's name as brand |
packSize | Pack size, for example 2.272L, 4x415g, 2 pints |
price | The price you pay without a loyalty card, in GBP |
wasPrice | The earlier price when the shop shows one (Rollback, "Was £", price drops) |
loyaltyPrice | Tesco Clubcard, Sainsbury's Nectar or Morrisons More Card price |
unitPrice | {value, measure}, for example {"value": 1.06, "measure": "l"} |
promotionText / promotionEndsAt | Offer text, such as "Rollback", "Buy 3 for £10" or "£1.40 Clubcard Price", and the offer's end date when the shop gives one |
inStock | Whether the product can be ordered now |
categoryPath | Where the product sits in the shop, for example ["Chilled Food", "Milk, Butter, Cream & Eggs", "Fresh Milk"] |
ean | EAN barcodes (Tesco and Sainsbury's) |
rating | {value, count} average rating and number of reviews |
matchKey | Lower-case name plus the pack size in g or ml, for lining up the same product across shops |
url / imageUrl | Product page and the largest product image |
ingredients / nutrition | With Include ingredients and nutrition on: ingredients text and rows of {nutrient, per100, perServing} |
priceHistory | With Keep weekly price history on: [{week, price, loyaltyPrice}] once two or more weeks exist |
How to compare UK supermarket prices
- Open UK Grocery Prices and click Try for free.
- Pick a Mode: Search, Category URLs, Product URLs, Catalogue or Basket.
- Pick the Shops, and add your search terms, links or shopping list.
- Set Max items. It is shared equally between the shops, so 100 items across five shops gives up to 20 from each.
- Turn on Include ingredients and nutrition or Keep weekly price history if you need them.
- Click Start, then download the results from the Output tab as JSON, CSV, Excel, XML, or HTML, or fetch them through the API.
To track prices every week, add the run to a schedule with Keep weekly price history on, and optionally set Name this run's dataset to snapshot-{retailer}-{isoWeek} so each week's dataset is kept under its own name.
Input examples
Search all five shops:
{"mode": "search","retailers": ["tesco", "sainsburys", "asda", "aldi", "morrisons"],"queries": ["semi skimmed milk", "baked beans"],"maxItems": 100}
Read category pages (the shop comes from each link):
{"mode": "category","categoryUrls": ["https://www.tesco.com/shop/en-GB/browse/groceries-and-essentials/fresh-food/milk-butter-and-eggs/milk/all","https://www.asda.com/groceries/food-cupboard/cereals-cereal-bars","https://www.aldi.co.uk/products/chilled-food/milk/k/1588161416978051001","https://groceries.morrisons.com/categories/fresh-foods/milk/177268","https://www.sainsburys.co.uk/gol-ui/groceries/food-cupboard/canned-and-tinned-food/pulses-and-beans/c:1019516"],"maxItems": 500}
Price a shopping list and find the cheapest shop:
{"mode": "basket","retailers": ["tesco", "sainsburys", "asda", "aldi", "morrisons"],"basket": ["2 x semi skimmed milk", "baked beans", "6 free range eggs", "sourdough bread", "bananas", "cheddar"],"useLoyaltyPrices": true}
All input parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
| mode | string | search | search, category, product, catalogue or basket |
| retailers | array | ["aldi", "sainsburys"] | Shops for search, catalogue and basket mode |
| queries | array | ["milk"] | Search terms, up to 50 |
| categoryUrls | array | — | Category links from any of the five shops, up to 250 |
| productUrls | array | — | Product links from any of the five shops, up to 500 |
| maxItems | integer | 100 | Most product rows to save, split equally between shops. 0 = no limit |
| includeDetails | boolean | false | Add ingredients and the nutrition table |
| priceHistory | boolean | false | Store weekly prices and add priceHistory once 2+ weeks exist |
| basket | array | — | Shopping list, one item per line, optional 2 x quantity |
| basketPricing | string | live | live searches now; snapshot uses the latest weekly prices your runs saved |
| basketPick | string | cheapest | cheapest (lowest unit price) or relevance (the shop's top match) |
| useLoyaltyPrices | boolean | false | Use Clubcard, Nectar and More Card prices in basket totals |
| asdaStoreId | string | — | Asda store number for the in-stock flag |
| outputDataset | string | — | Also append every row to this named dataset |
| datasetName | string | — | Name this run's dataset; placeholders {isoWeek}, {date}, {retailer} |
| proxyConfiguration | object | no proxy | Optional. The Actor switches to Apify Proxy by itself if a shop refuses direct requests |
Output example
[{"retailer": "tesco","retailerProductId": "254656543","ean": ["05000436589457"],"matchKey": "tesco british semi skimmed milk 2.272l 4 pints 2272ml","name": "Tesco British Semi Skimmed Milk 2.272L, 4 Pints","brand": "TESCO","packSize": "2.272L","price": 1.75,"wasPrice": null,"unitPrice": { "value": 0.77, "measure": "l" },"loyaltyPrice": null,"promotionText": null,"promotionEndsAt": null,"inStock": true,"categoryPath": ["Groceries & Essentials", "Fresh Food", "Milk, Butter & Eggs", "Milk"],"url": "https://www.tesco.com/groceries/en-GB/products/254656543","imageUrl": "https://digitalcontent.api.tesco.com/v2/media/ghs/07531d6d-8bf2-41b5-a5ad-e2ae0a71f2b3/17233543-2c5b-4a06-a0ab-cfdbddcd488e_2028878860.jpeg","rating": { "value": 4, "count": 710 },"query": "semi skimmed milk","position": 1,"scrapedAt": "2026-11-03T23:22:48Z"},{"retailer": "asda","retailerProductId": "2041527","ean": [],"matchKey": "cravendale arla filtered fresh semi skimmed milk 1l fresher for longer 1000ml","name": "Cravendale Arla Filtered Fresh Semi Skimmed Milk 1L Fresher for Longer","brand": "Cravendale","packSize": "1L","price": 1.4,"wasPrice": 1.64,"unitPrice": { "value": 1.4, "measure": "l" },"loyaltyPrice": null,"promotionText": "Rollback","promotionEndsAt": null,"inStock": true,"categoryPath": ["Chilled Food", "Milk, Butter, Cream & Eggs", "Fresh Milk", "Semi Skimmed Milk"],"url": "https://www.asda.com/groceries/product/semi-skimmed-milk/cravendale-arla-filtered-fresh-semi-skimmed-milk-1l-fresher-for-longer/2041527","imageUrl": "https://asdagroceries.scene7.com/is/image/asdagroceries/5000181024029","rating": { "value": 4.68, "count": 296 },"query": "semi skimmed milk","position": 2,"scrapedAt": "2026-11-03T23:22:48Z"}]
In Basket mode each shop's line is saved as a row with type: "basketLine", and the key-value store record OUTPUT holds every shop's total, the matched and missing lines, and cheapestRetailer.
Basket API (Standby)
The Actor also runs as an always-on HTTP endpoint through Apify Standby. Send a shopping list and get the totals back in the same request, without starting a run:
curl -X POST "https://parsebird--uk-grocery-price-scraper.apify.actor/basket" \-H "Authorization: Bearer <YOUR_APIFY_TOKEN>" \-H "Content-Type: application/json" \-d '{"items": ["2 x semi skimmed milk", "baked beans"], "retailers": ["tesco", "asda", "aldi"], "pricing": "live"}'
The body takes items (strings or {query, quantity}), retailers, pricing (live or snapshot), pick (cheapest or relevance) and useLoyaltyPrices. Each matched line at each shop is charged as a basket line.
How much does it cost to compare UK grocery prices?
UK Grocery Prices uses pay-per-event pricing. You pay for what is saved; compute and proxy traffic are included in the event prices and not billed separately.
| Event | When it is charged | Free | Bronze | Silver | Gold |
|---|---|---|---|---|---|
| Product | One product row saved | $1.99 / 1,000 | $1.79 / 1,000 | $1.59 / 1,000 | $1.39 / 1,000 |
| Product details | A product row that carries ingredients or a nutrition table, on top of Product | $4.99 / 1,000 | $4.49 / 1,000 | $3.99 / 1,000 | $3.49 / 1,000 |
| Price history | A priceHistory list added to a row (only when two or more weekly prices exist) | $3.99 / 1,000 | $3.79 / 1,000 | $3.59 / 1,000 | $3.39 / 1,000 |
| Basket line (live) | One matched basket line at one shop, priced live | $1.99 / 1,000 | $1.79 / 1,000 | $1.59 / 1,000 | $1.59 / 1,000 |
| Basket line (snapshot) | One matched basket line at one shop, priced from the weekly snapshot | $1.99 / 1,000 | $1.79 / 1,000 | $1.59 / 1,000 | $1.59 / 1,000 |
A small platform Actor start fee also applies per run. Examples on the Free plan:
- 100 products from a search: about $0.20.
- 100 products with ingredients and nutrition, all with details found: about $0.70.
- A 20-item shopping list priced at all five shops (100 matched lines): about $0.20.
Items a shop doesn't match are not charged. Apify's free plan includes monthly platform credit you can use for this Actor.
Python and JavaScript API examples
Python (apify-client):
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("parsebird/uk-grocery-price-scraper").call(run_input={"mode": "search","retailers": ["tesco", "sainsburys", "asda", "aldi", "morrisons"],"queries": ["semi skimmed milk"],"maxItems": 50,})for p in client.dataset(run["defaultDatasetId"]).iterate_items():print(p["retailer"], "|", p["name"], "|", p["price"], "|", p.get("loyaltyPrice"), "|", p.get("unitPrice"))
JavaScript (apify-client):
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('parsebird/uk-grocery-price-scraper').call({mode: 'basket',retailers: ['tesco', 'sainsburys', 'asda', 'aldi', 'morrisons'],basket: ['2 x semi skimmed milk', 'baked beans', '6 free range eggs'],});const output = await client.keyValueStore(run.defaultKeyValueStoreId).getRecord('OUTPUT');console.log(output.value.cheapestRetailer, output.value.totals);
Find all endpoints on the API tab.
FAQ
Which shop data is available for each supermarket?
All five shops return price, was-price where shown, unit price, offer text, pack size, category and image. Tesco and Sainsbury's also return EAN barcodes. Tesco, Sainsbury's and Morrisons return loyalty card prices (Clubcard, Nectar, More Card). Aldi's UK site marks its products as not sold online and shows no ratings or barcodes, so Aldi rows have inStock, rating and ean empty.
Why are Asda ingredients and nutrition empty? Asda serves ingredients and nutrition only on its product pages, and those pages refuse requests from Apify's servers. Asda prices, offers, stock, ratings and categories come from Asda's product search and work normally. Asda rows without details are not charged the Product details event.
What is the difference between price, wasPrice and loyaltyPrice?
price is what you pay without a loyalty card. wasPrice is the earlier price the shop shows next to an offer, such as an Asda Rollback or a Morrisons "Was £3.90". loyaltyPrice is the Clubcard, Nectar or More Card price. Morrisons gives the regular price and the offer as text ("Now £3, Was £3.90", "Half price"), and the Actor works out the price you pay from that text.
How does Basket mode pick a product for each item? A product counts as a match only if its name contains every word of the item (plural forms count, and "6" matches "6 pack" or "x6"). With Cheapest by unit price, the Actor stays on the shelf of the shop's own best match and takes the lowest unit price there, so "bananas" is not matched with banana yogurt. With Top search result, it takes the shop's first match. A shop missing any item is not counted as the cheapest complete basket.
How does price history work?
With Keep weekly price history on, each product's price for the current ISO week is stored in a key-value store named uk-grocery-price-history in your Apify account. A product gets a priceHistory list once it has prices from two or more weeks, so the history starts filling up from your second weekly run. Up to 104 weeks are kept per product.
How many products can I get? Search and category results go as deep as each shop's own results. In our tests, Catalogue mode returned the whole Asda grocery range, 34,373 products, in about 25 minutes, and 3,000 Morrisons products in about 2 minutes. Asda's catalogue leaves out its Home & Entertainment (George) range. Asda's search returns at most 1,000 results per query, so large Asda categories are read through their sub-categories. Products Asda hides from its online shop are left out, as on asda.com.
Are prices the same in every store? The Actor returns the online grocery prices each shop's website shows. Asda prices come from its online price list for England. Prices in physical stores can differ.
Can I schedule the scraper and connect it to other tools? Yes. Use Apify schedules to run it daily or weekly, and connect the results to Google Sheets, Slack, Make, Zapier, n8n, or your own system through integrations, webhooks, or the API.
Something does not work or a field is missing. Open an issue on the Issues tab with your input and run ID, and we will look into it.
Is it legal to scrape UK supermarket prices?
The Actor collects only public product and price information that the supermarkets show to every visitor of their websites. It does not collect personal data. Check that your use of the data complies with each shop's terms and the laws that apply to you. For more background, read Apify's article Is web scraping legal? and consult a lawyer if you are unsure about your use case.
Other grocery and retail scrapers from ParseBird
| Actor | What it scrapes |
|---|---|
| Tesco UK & Ireland Scraper | Tesco.com and Tesco.ie products, Clubcard prices, nutrition, and reviews |
| Sainsbury's UK Grocery Scraper | Sainsbury's products with Nectar prices, offers and descriptions |
| Lidl Scraper | Lidl online shop products across European countries |
| ALDI Australia Scraper | ALDI Australia products and prices |
| Carrefour MAF Scraper | Carrefour products in the Middle East |
| Walmart Product Scraper | Walmart product data |