Loblaws, Superstore, No Frills, Maxi & 8 More — Grocery Prices
Pricing
from $0.69 / 1,000 results
Loblaws, Superstore, No Frills, Maxi & 8 More — Grocery Prices
Canadian grocery prices from all 12 Loblaw banners and 1,107 stores, priced at the individual store by postal code. 67 fields per product: UPC barcodes, stock status, PC Optimum member prices, promo expiry dates, nutrition and ingredients. Many chains and stores in one run. No API key, no browser.
Pricing
from $0.69 / 1,000 results
Rating
0.0
(0)
Developer
Arpit Gandhi
Maintained by CommunityActor stats
0
Bookmarked
3
Total users
2
Monthly active users
3 days ago
Last modified
Categories
Share
Canadian grocery prices from all 12 Loblaw banners and 1,107 stores, priced at the individual store by postal code — with UPC barcodes, live stock status, PC Optimum member prices, promo expiry dates, ratings, nutrition and ingredients on the row.
67 fields per product. Not a name-and-price feed: everything the shelf tag, the barcode and the label carry, from one input.
- Chains — Loblaws, Real Canadian Superstore, No Frills, Zehrs, Fortinos, Valu-mart, Your Independent Grocer, Independent City Market, Provigo, Maxi, Wholesale Club, Atlantic Superstore
- Coverage — 1,107 stores across every province plus Yukon and the Northwest Territories, in English and French
- Setup — none. No API key, no account, no proxy, no browser, no geocoder
What you get that a price feed doesn't
Scan-ready identifiers. upc and gtin on the row, so prices join straight onto an existing product database or a barcode scan. No fuzzy name matching.
Stock, not just price. stock_status and is_shoppable tell you whether the item is actually on the shelf at that store today. A price for something out of stock is a bad datapoint.
Member vs shelf price. member_price and member_price_ends capture PC Optimum member-only pricing separately from price and was_price — three different numbers the same product can show.
Promotions with expiry dates. sale_ends, deal_ends, pc_optimum_offer_ends and numeric pc_optimum_points, alongside multi_buy_deal and purchase_limit. You know when a price dies, not only that it exists.
Many chains and many stores in one run. banners takes a list and stores_per_banner prices the nearest N of each — so "Superstore vs No Frills vs Maxi, three stores each" is a single run, not nine.
The full label. Turn on include_details for nutrition, ingredients, category_path, average_weight_kg and gtin.
Paid placements removed by default. The storefront injects sponsored products into every search page, often unrelated — a search for milk returns kombucha and baby cereal. Those are dropped unless you ask for them, and flagged with is_sponsored when you do.
Real unit-price maths. comparable_unit_price normalizes to $/100 g or $/100 ml and stays null when a package size won't parse, so a wrong number never enters your comparison. comparison_prices keeps every unit the store quoted ($/kg and $/lb).
Run it
Paste into the Input tab (JSON view) and hit Start:
{"banners": ["superstore"],"search_terms": ["eggs", "milk", "chicken breast"],"postal_code": "V5X 0C4"}
Rows stream into Output as they arrive. Download from Storage → Dataset as JSON, CSV or Excel.
Three things to change from there:
- Compare chains —
"banners": ["superstore", "nofrills", "maxi"], one run, every row naming its store - Compare stores —
"stores_per_banner": 3prices the three nearest locations of each banner - Take the whole store —
"all_products": trueinstead of search terms
What a row looks like
{"store": "Real Canadian Superstore","banner": "superstore","name": "Bananas, Bunch","product_id": "20175355001_KG","upc": "4011","price": 1.98,"price_unit": "ea","was_price": null,"is_on_sale": false,"member_price": null,"unit_price": "$1.72/kg, $0.78/lb","comparable_unit_price": 0.17,"comparable_unit": "100g","selling_type": "by_weight","stock_status": "in_stock","is_shoppable": true,"rating": 3.67,"review_count": 3,"image_url": "https://digital.loblaws.ca/PCX/20175355001_KG/en/1/...png","product_url": "https://www.realcanadiansuperstore.ca/en/bananas-bunch/p/20175355001_KG","location_id": "1517","location_name": "Real Canadian Superstore Marine Drive","location_address": "350 SE Marine Dr, Vancouver, BC, V5X 2S5","location_province": "British Columbia","location_coordinates": { "lat": 49.20906, "lng": -123.10 },"distance_km": 1.4}
Fields
Product — name, brand, description, product_id, article_number, upc, upcs, package_size, parsed_package_size, normalized_package_size, variant_label, image_url, product_url, seller_name
Price — price, price_unit, was_price, is_on_sale, sale_ends, member_price, member_price_ends, unit_price, comparable_unit_price, comparable_unit, parsed_unit_price, comparison_prices, selling_type, deposit, eco_fee, tax_info
Promotions — deal_type, deal_text, deal_ends, multi_buy_deal, purchase_limit, pc_optimum_offer, pc_optimum_points, pc_optimum_offer_ends, badges
Availability & reviews — stock_status, is_shoppable, rating, rating_count, review_count, is_sponsored
Store — store, banner, location, location_id, location_name, location_address, location_city, location_province, location_postal_code, location_coordinates, location_phone, distance_km
Run — search_term
With include_details — gtin, category, category_path, ingredients, nutrition, average_weight_kg, variant_group_id, variant_count, variants
Input
| Field | Type | Default | Description |
|---|---|---|---|
banners | string[] | — | One or more of the 12 banners below. Several in one run compares chains. |
search_terms | string[] | — | Keyword queries, e.g. ["eggs", "no name"]. Use French for Maxi and Provigo. |
postal_code | string | — | Any Canadian postal code; picks the nearest store of each banner. |
all_products | boolean | false | Walk the store's entire catalogue instead of searching. |
include_details | boolean | false | Add nutrition, ingredients, category path, GTIN, average weight. One extra request per product. |
on_sale_only | boolean | false | Keep only products on sale or carrying a deal. |
group_variants | boolean | false | Collapse sizes of one product into a single row with a variants array. |
stores_per_banner | integer | 1 | Price the nearest N stores (1–10) of each banner. |
locationId | string | — | One exact store, overriding postal_code. |
language | string | auto | en / fr. Auto = French for Maxi and Provigo. |
max_items_per_search | integer | 500 | Cap per search term, per store. |
max_items | integer | 0 | Stop the whole run after N products. 0 = no limit. |
include_sponsored | boolean | false | Keep the storefront's paid placements. |
One of search_terms or all_products is required.
Examples
Compare one basket across three chains:
{ "banners": ["superstore", "nofrills", "maxi"], "search_terms": ["milk", "eggs", "bread"], "postal_code": "H2X 1Y6" }
Everything on sale at the nearest No Frills:
{ "banners": ["nofrills"], "all_products": true, "on_sale_only": true, "postal_code": "M6H 1V4" }
Barcodes and nutrition for a category of products:
{ "banners": ["loblaw"], "search_terms": ["greek yogurt"], "include_details": true, "postal_code": "M5V 2T6" }
Price the same products at the five nearest stores:
{ "banners": ["superstore"], "search_terms": ["chicken breast"], "stores_per_banner": 5, "postal_code": "T2P 1J9" }
One exact store:
{ "banners": ["superstore"], "locationId": "1517", "search_terms": ["bananas"] }
Supported stores
| Banner | Store | Stores | Provinces |
|---|---|---|---|
nofrills | No Frills | 350 | AB, BC, MB, NB, NL, NS, ON, PE, SK |
maxi | Maxi | 198 | NB, QC |
independent | Your Independent Grocer | 181 | AB, BC, NB, NL, NS, NT, ON, PE, QC, SK, YT |
superstore | Real Canadian Superstore | 119 | AB, BC, MB, ON, SK, YT |
wholesaleclub | Wholesale Club | 56 | AB, BC, MB, NB, NL, NS, ON, QC, SK |
rass | Atlantic Superstore | 52 | NB, NS, PE |
loblaw | Loblaws | 48 | AB, BC, ON |
zehrs | Zehrs | 42 | ON |
fortinos | Fortinos | 24 | ON |
provigo | Provigo | 20 | QC |
valumart | Valu-mart | 14 | ON |
independentcitymarket | Independent City Market | 3 | ON |
Counts read live from Loblaw's own store directory. Each banner prices independently — the same SKU can differ by a dollar or more between them. rass is Atlantic Superstore's internal code. Aliases accepted: loblaws, rcss, no frills, valu-mart, yig, atlantic, icm.
From the API
Grab a token at console.apify.com/settings/integrations:
curl -X POST \"https://api.apify.com/v2/acts/arpitgandhi1934~loblaws-grocery-scraper/run-sync-get-dataset-items?token=YOUR_API_TOKEN" \-H "Content-Type: application/json" \-d '{"banners": ["superstore"], "search_terms": ["eggs", "milk"], "postal_code": "V5X 0C4"}'
run-sync-get-dataset-items suits small runs and can time out on large ones. For scheduled or whole-store scrapes, POST to /runs and read the returned defaultDatasetId. The official JavaScript and Python clients work too, as do Zapier, Make, Google Sheets and Airbyte.
What people build with it
- Price comparison apps keyed to a real store, not a national average
- Food inflation research — rerun a fixed basket weekly and diff
pricebyproduct_idand store - CPG competitor monitoring across all 12 banners, including member-only pricing rivals can't see in a flyer
- Deal and flyer sites from
is_on_sale,multi_buy_deal,pc_optimum_offerand their expiry dates - Barcode and inventory apps joining on
upc/gtinwithstock_status - AI shopping agents that need grounded prices with a store, a timestamp and a stock flag
FAQ
How do I scrape Real Canadian Superstore prices? Set "banners": ["superstore"] with search_terms and a postal_code. The Run it example above works as-is.
Can I get prices for a specific postal code? Yes. Any Canadian postal code resolves to the nearest store of each banner, and every row reports that store's name, address, postal code, coordinates and distance.
Does this work in Quebec? Yes — maxi and provigo, which default to French. independent and wholesaleclub also have Quebec locations.
Can I compare the same product across chains? Yes, in one run: pass several banners. product_id is shared across the Loblaw catalogue, so rows join directly.
Is there an official Loblaws API? No. Loblaw publishes no public pricing API, which is why this reads the same JSON endpoints its own storefronts and app use.
How do I get barcodes? upc is on every row. gtin comes with include_details.
How do I track prices over time? Schedule it daily or weekly and keep each run's dataset, then compare price per product_id per store. The Actor returns current prices and stores no history itself.
How many products can one run return? A search term returns up to max_items_per_search (default 500). all_products walks the whole catalogue — a small Valu-mart is ~2,000 products in under a minute; a large No Frills is ~21,000 and takes several minutes. Around 25,000 products are reachable per store. Rows stream as they go, so partial results are available while the run continues.
Do I need a proxy? No. It runs from Apify's datacenter IPs without one. proxyConfiguration is there for very large or very frequent scrapes.
Is scraping Loblaws legal? Scraping publicly available product and price information is generally legal. Complying with the retailer's terms and the law in your jurisdiction is your responsibility, so keep request volume reasonable.
Notes
- Grocery size variants are separate products in Loblaw's catalogue;
group_variantsgroups them by brand and name with no extra requests. Truevariantsarrays are clothing (Joe Fresh size/colour). - Result ordering from the upstream search is not stable between identical calls, so whole-store runs walk the catalogue in repeated passes until a pass adds almost nothing. That is why a full store takes minutes rather than seconds.
- A postal code outside a banner's footprint returns a clear error naming the provinces that banner serves, so a Quebec query never quietly returns an Ontario store.