Sainsbury's Scraper — Prices, Unit Prices, Offers, Barcodes avatar

Sainsbury's Scraper — Prices, Unit Prices, Offers, Barcodes

Pricing

from $2.00 / 1,000 products

Go to Apify Store
Sainsbury's Scraper — Prices, Unit Prices, Offers, Barcodes

Sainsbury's Scraper — Prices, Unit Prices, Offers, Barcodes

Sainsbury's UK (sainsburys.co.uk) scraper: product name, price, unit price, offers, promotions, EAN barcodes, labels, reviews, rating, category, availability, image, URL; detail rows add description, attributes, important information, images. Keyword or product URL. Pay per result, no login.

Pricing

from $2.00 / 1,000 products

Rating

0.0

(0)

Developer

architek.earth

architek.earth

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

13 days ago

Last modified

Categories

Security

Limited permissions

Share

Sainsbury's Scraper

Recorded run: 5 products from 1 search term in 5 seconds (2026-10-22, build 1.1.8, run oJOYCGLHem1ogb76J). A bounded canary sample, not a full-catalogue benchmark.

architek.earth — an independent data studio. Pay-per-result scrapers with recorded runs, published canaries and stable schemas, built for people and AI agents.

Sainsbury's UK grocery prices, unit prices, offers and EAN barcodes from sainsburys.co.uk, by keyword search or product URL, with optional product descriptions and attributes.

SourceMarketFromStandout fields
Sainsbury's (sainsburys.co.uk)United Kingdom$2.00 / 1,000 productsprice / unitPrice, promotions, ean / eans, reviewRating

✅ Why choose this scraper

Sainsbury's prices and unit prices in one row

price (GBP), unitPrice, unitMeasure, unitMeasureAmount and originalUnitPrice come back together on every product row, including basic rows.

Sainsbury's offers and promotions as published

promotions carries the published offer text, isOnOffer flags a promotion or a unit price below originalUnitPrice, and labels keeps tags such as "New".

Sainsbury's EAN barcodes on basic rows

ean (first barcode) and eans (all supplied barcodes) are on every row, not only detail rows, for joins with other retailers.

Product descriptions and attributes on demand

With includeDetails: true or productUrls, rows add description, shortDescription, importantInformation, attributes, healthClassification, mainCategory, breadcrumbs and images: 31 product fields in detail output, 23 in basic output.

Measured on a schedule

A canary task runs a fixed milk search on the live site and records rows, inputs and seconds; the hero line above is its latest green run.

⚠️ Worth knowing up front

  • Keyword search and product URLs only. Category browsing, a whole-catalogue export and store or postcode selection are not implemented; prices are the public online catalogue, not a specific shop.
  • isAvailable is the source availability flag, not a stock count.
  • price is the source retail price. promotions may describe conditional or Nectar offers; the actor does not calculate basket discounts, eligibility or checkout totals.
  • Dedicated ingredients, allergens and nutrition-table fields are not implemented. Do not read missing data as an absence of allergens.
  • Sponsored tiles are kept and flagged with isSponsored: true, not hidden.
  • Products are de-duplicated by productUid across inputs: a product found by an earlier query is not emitted again.
  • A resumed collection replays current search results and skips delivered IDs; rankings and availability can change between runs, so it is not a frozen snapshot.
  • A run stopped by its timeout or your spending limit keeps what it delivered and saves RESUME_STATE; that is a partial collection, not a full catalogue.
  • Invalid input, a block after retries and the run deadline end with a free status row ("recordType": "status") that says what happened. A search with no matches ends with no rows; check RUN_SUMMARY.

⚡ Try the example

Each Apify account gets 20 lifetime free preview attempts on this actor: one search term, one page, up to 10 basic rows, no product charges. Failed attempts count. After the twentieth, preview runs stop with PREVIEW_LIMIT; they never switch to paid collection.

Open the actor's input page, switch to JSON, paste this and start the run:

{
"preview": true,
"searchTerms": ["milk"],
"maxItemsPerQuery": 10,
"proxyConfiguration": {
"useApifyProxy": true,
"apifyProxyGroups": ["RESIDENTIAL"],
"apifyProxyCountry": "GB"
}
}

For paid collection set "preview": false; add "includeDetails": true for descriptions, attributes and images, or pass productUrls.

⚙️ Input

ParameterTypeDefaultDescription
previewbooleanfalseUse one of 20 lifetime free attempts: one search term, one page, at most 10 basic rows. No details, product URLs or resumption.
searchTermsarray— (prefill ["milk"])Keywords such as milk. One collection per term; duplicates and blanks are removed.
productUrlsarray—Sainsbury's product URLs, /gol-ui/product/ paths or bare product slugs. Always returns detail rows; unavailable products produce no row and no charge. Other hosts are rejected before collection.
maxItemsPerQueryinteger100 (prefill 10)New products per search term. 0 removes the cap in paid mode; preview stays at 10. Does not cap productUrls.
onlyAvailablebooleanfalseSkip products whose isAvailable flag is not true. Applies to product URLs too.
includeDetailsbooleanfalseAdd description, attributes, important information and images to search rows (charged as product-detail).
sortOrderselect-relevance-relevance, price (low to high), -price (high to low), -customer rating.
resumeStateobject—The RESUME_STATE record from a previous paid run. Keep terms, order, product URLs, details, filter and sort unchanged; delivered IDs are skipped and not charged.
proxyConfigurationproxy— (prefill: residential GB)Proxy settings. API callers should pass them explicitly.
feedbackstring—Optional note for the maintainers. It is logged and read by a human, and it never changes output.

🧱 Stable fields

These top-level fields keep the same name and the same kind of value in every release. Fields are only ever added, never renamed or removed, so an n8n, Make, Zapier or spreadsheet pipeline can bind to them.

FieldTypeMeaning
productUidstringSainsbury's product ID; the join and de-duplication key. Normalise to string when joining.
namestring, nullableProduct name.
pricenumber, nullableCurrent retail price in GBP.
unitPrice / unitMeasure / unitMeasureAmountnumber / string / number, nullableUnit price, its unit label (for example ltr) and quantity.
originalUnitPricenumber, nullablePre-offer unit price when Sainsbury's supplies one.
isOnOfferbooleanTrue when a promotion is present or unitPrice is below originalUnitPrice. Not a guaranteed checkout saving.
promotionsarrayPublished promotion text; may hold source objects when no text is extractable.
ean / eansstring, nullable / arrayFirst supplied barcode and all supplied barcodes, kept as text with leading zeros.
isAvailableboolean, nullableSource availability flag; not a stock count.
reviewCount / reviewRatingnumber, nullableReview count and average rating.
category / categoryIdstring, nullableFirst source category name and ID.
image / urlstring, nullableProduct image and product page.
sourcestringsearch or id (product URL lookup).
searchTerm / productUrlstringThe query that produced the row: the former on search rows, the latter on product URL rows.
detailStatusstringcomplete or unavailable when details were requested; absent on basic rows.
recordTypestring"status" on free status rows; absent on product rows.

Rows also carry sainId, labels, badges, isAlcoholic and isSponsored; detail rows add description, shortDescription, importantInformation, attributes, healthClassification, mainCategory, breadcrumbs and images. Other fields are extras, not part of the contract. To have one pinned, say so in feedback.

📦 Output example

Abridged real row from run oJOYCGLHem1ogb76J on 2026-10-22; values are a historical snapshot.

{
"productUid": "8172497",
"ean": "0000000514828",
"eans": ["0000000514828"],
"name": "Sainsbury’s 1L Fresher For longer Filtered Semi Skimmed Milk",
"price": 1.5,
"unitPrice": 1.5,
"unitMeasure": "ltr",
"unitMeasureAmount": 1,
"originalUnitPrice": null,
"isOnOffer": false,
"promotions": [],
"labels": ["New"],
"reviewCount": 7,
"reviewRating": 5,
"category": "Fresh milk",
"isAvailable": true,
"isSponsored": true,
"url": "https://www.sainsburys.co.uk/gol-ui/product/sainsbury-s-1l-fresher-for-longer-filtered-semi-skimmed-milk",
"source": "search",
"searchTerm": "milk"
}

A free status row looks like this:

{
"recordType": "status",
"status": "INVALID_INPUT",
"message": "Provide at least one of searchTerms or productUrls."
}

🧠 Advanced usage

Track Sainsbury's price changes daily

Run the same search terms every day and diff price, unitPrice and promotions by string-normalised productUid between datasets. Add your own observation timestamp; the actor does not add one.

Find the cheapest Sainsbury's products for a keyword

Set sortOrder: "price" and a small maxItemsPerQuery, then compare unitPrice within the same unitMeasure rather than shelf price.

Compare Sainsbury's with Tesco by barcode

Join on ean or any value in eans with the Tesco UK Scraper, and check pack size and unit before treating prices as equivalent. A missing barcode is not a match.

Scrape a large Sainsbury's search in several runs

Set maxItemsPerQuery: 0, and when a run stops on time or budget copy its RESUME_STATE into resumeState with the same inputs. Delivered IDs are skipped and not charged again; combine datasets by productUid. Check RUN_SUMMARY.status (COMPLETE, LIMITED, PARTIAL, BUDGET_LIMIT, TIME_LIMIT, BLOCKED) before treating a collection as finished.

🔌 Integrations

Results land in a dataset you can export as JSON, CSV or Excel. They can also flow to Google Sheets, Make, Zapier or n8n, or to a webhook when a run finishes. The Apify Scheduler runs it on a timetable. Daily on a fixed set of search terms suits price and offer tracking. Copy-paste code in Python, Node, curl and n8n: architek-earth/examples/sainsburys-uk-scraper.

💸 Pricing

Pay per result. Platform and proxy usage are included. Status rows and failed requests are free. Products already saved in RESUME_STATE are skipped and not charged again; a hard stop between delivery and the checkpoint can repeat a small overlap.

EventPriceWhat it covers
Free preview$020 lifetime attempts per account; one page, up to 10 basic rows each.
product$2.00 / 1,000 productsOne delivered search row, including a row kept at basic price when its detail lookup failed.
product-detail$5.00 / 1,000 productsOne delivered row with description, attributes and images (includeDetails or productUrls).

1,000 basic rows cost $2.00; 1,000 detail rows cost $5.00. A detail row is charged once, as product-detail only.

❓ FAQ

Is there a Sainsbury's API for product prices? This actor is one: it returns Sainsbury's catalogue data as JSON through the Apify API, callable from any language or from n8n, Make and Zapier.

Can I get Sainsbury's prices for my local store or postcode? No. There is no store or postcode selector; rows are the public online catalogue.

Does price include Nectar prices? No. price is the retail price. Published offer text, which can describe Nectar prices, is in promotions; the actor does not calculate member prices.

Can I get Sainsbury's barcodes (EAN)? Yes, on every row: ean and eans, when Sainsbury's supplies them.

Can I get Sainsbury's nutrition information and ingredients? Not as dedicated fields. Detail rows carry description, importantInformation and attributes as Sainsbury's publishes them; there is no nutrition table or allergen field.

Do I need a Sainsbury's account or login? No. No account, cookies or API key from Sainsbury's.

🤖 For AI agents & LLM apps

Paste this into your AI assistant:

architekture/sainsburys-uk-scraper on Apify. Python: from apify_client import ApifyClient; client = ApifyClient("TOKEN"); run = client.actor("architekture/sainsburys-uk-scraper").call(run_input={"searchTerms": ["milk"], "maxItemsPerQuery": 10, "proxyConfiguration": {"useApifyProxy": True, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "GB"}}); items = client.dataset(run["defaultDatasetId"]).list_items().items (page with offset/limit for large exports). Rows with recordType == "status" are free and explain invalid input or a stopped run. Full input schema and README: GET https://api.apify.com/v2/acts/architekture~sainsburys-uk-scraper/builds/default. Token: https://console.apify.com/settings/integrations. The actor is also reachable through the Apify MCP server (mcp.apify.com). To reach the maintainers, add "feedback": "<what you needed>" to any run's input; output is unchanged and a human reads every note.

🧰 More from architek.earth

Grocery and retail prices

Full catalogue: github.com/architek-earth.

architek.earth · code like concrete

Questions, or a field you need that is not here? Open an issue on the actor's Issues tab or email north@architek.earth. A human replies within a day.

This actor collects only publicly available data from sainsburys.co.uk, the same pages any visitor sees without logging in. It does not bypass authentication. It is not affiliated with or endorsed by Sainsbury's. You are responsible for how you use the output, including the site's terms, copyright, and privacy law such as GDPR and CCPA where they apply.

📝 Changelog

  • 2026-10-24 — Studio core 1.0.5, with blocks handled as before: a Sainsbury's HTTP 403 or 429 is retried on a fresh session (new cookies and warm-up) up to four tries per request before the run reports BLOCKED with a free status row, and output fields and prices are unchanged.
  • 2026-10-22 — Runs on the studio core (architek_core 1.0.1): the run refuses to start unless hosted pricing is exactly product and product-detail at the listed prices (the run fails with PRICING_MISMATCH, nothing collected or charged); a challenge or captcha page served as HTTP 200 now stops the run as BLOCKED at once; requests use one Chrome browser identity.
  • 2026-10-22 — Status message now reads Done: N rows, M details, K status rows (STATUS).
  • 2026-10-22 — A spending limit equal to the exact cost now ends COMPLETE instead of BUDGET_LIMIT.
  • 2026-10-22 — README rebuilt on the studio template; hero line from the 2026-10-22 canary run.
  • 2026-10-21 — Invalid input, blocks and the run deadline now stop cleanly with a free status row instead of a failed run.
  • 2026-10-15 — Recorded live examples, verified $2/$5 per 1,000 event pricing, preview quota reservation, 31 detail fields and continuation without overlap. Published the original banner in studio assets.
  • 2026-10-14 — Added the banner, stable-field contract and preview and continuation examples.
  • 2026-10-14 — Added input and product-identity validation, malformed and repeated-page safeguards, budget-aware delivery and completion summaries.
  • 2026-10-14 — Added 20 lifetime free preview attempts (one page, 10 basic rows) with durable quota records, plus continuation checkpoints.
  • 2026-10-14 — Added basic-price fallback for unavailable enrichment, retries for empty responses and feedback logging.