Canadian Grocery Price Comparison API avatar

Canadian Grocery Price Comparison API

Pricing

from $10.00 / 1,000 searches

Go to Apify Store
Canadian Grocery Price Comparison API

Canadian Grocery Price Comparison API

Compare grocery prices across 16 Canadian chains, Loblaws, Superstore, No Frills, Zehrs, Fortinos, Valu-mart, etc from one input. Get normalized product matches, prices, unit prices, sale flags, store details, product URLs, and CSV/JSON/Excel-ready output for apps, AI agents, and research.

Pricing

from $10.00 / 1,000 searches

Rating

0.0

(0)

Developer

JChaw

JChaw

Maintained by Community

Actor stats

1

Bookmarked

25

Total users

4

Monthly active users

a day ago

Last modified

Share

Same product, compared across Loblaws, No Frills, Save-On-Foods & PriceSmart in one call.

Loblaw Companies and Pattison Food Group run separate websites, separate catalogues and different house brands, so the same tub of butter shows up under different names. This Actor searches both companies (plus T&T), matches each item across them, and gives every match a confidence score, so you compare like with like instead of lining up four datasets yourself.

Sample output for "queries": ["salted butter"] (prices illustrative):

storecompanymatched productpriceunit pricematch confidence
No FrillsLoblaw CompaniesNo Name Salted Butter 454 g6.00$1.32/100ghigh
LoblawsLoblaw CompaniesNo Name Salted Butter 454 g6.49$1.43/100ghigh
Save-On-FoodsPattison Food GroupWestern Family Salted Butter 454 g7.49$1.65/100ghigh
PriceSmart FoodsPattison Food GroupLactantia Salted Butter 454 g6.99$1.54/100gmedium

Cost: billed per search, where one search is one item on one retailer. 5 items × 4 retailers = 20 searches. 100 searches ≈ $1–$3.67 USD on paid Apify plans ($5 on the free plan), plus $0.0015 per result row, about $0.45 at the default 3 results per search. The free Apify plan runs up to 5 items (or 5 categories) and 100 product results per run.

  • Loblaw Companies: Loblaws, Real Canadian Superstore, No Frills, Zehrs, Fortinos, Valu-mart, Your Independent Grocer, Provigo, Maxi, Wholesale Club, Atlantic Superstore
  • Pattison Food Group: Save-On-Foods, PriceSmart Foods, Urban Fare, Quality Foods
  • T&T Supermarket
  • Every row: matched product, retailer, store, price, sale price, normalized unit price, availability, product URL, match confidence
  • Setup: none. No API key, no account, no proxy.

Run it

Paste this into the Input tab (switch to JSON view) and hit Start:

{
"queries": ["eggs", "chicken breast", "celery"],
"location": "Vancouver, BC",
"retailers": ["loblaws", "saveonfoods", "tnt"]
}

Comparison rows stream into Output as each retailer finishes. Download from Storage → Dataset as JSON, CSV or Excel.

Three things to change from there:

  • Compare a real basket by extending queries to your weekly list
  • Move region by editing location, then naming the banners that serve it: Montréal is ["maxi", "provigo", "valumart"], Halifax is ["atlanticsuperstore", "nofrills", "independent"]
  • Add basket totals with "includeSummaries": true

From the API

Grab a token at console.apify.com/settings/integrations:

curl -X POST \
"https://api.apify.com/v2/acts/sunny_eternity~canada-grocery-price-comparison/run-sync-get-dataset-items?token=YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"queries": ["eggs", "chicken breast", "celery"], "location": "Vancouver, BC", "retailers": ["loblaws", "saveonfoods", "tnt"]}'
  • run-sync-get-dataset-items suits small runs and can time out on large ones
  • For scheduled runs or large baskets, POST to /runs and read the returned defaultDatasetId
  • Official JavaScript and Python clients work too

What you get back

Each comparison row in full:

{
"_type": "comparison",
"schema_version": "2026-05-compare-v1",
"query": "ground beef",
"retailer": "loblaws",
"banner": "Loblaws",
"store": "Robson Street",
"store_id": "1050",
"matched_product": "PC Lean Ground Beef",
"price": 7.99,
"unit_price": "$1.76/100g",
"comparable_unit_price": 1.76,
"comparable_unit_basis": "100g",
"sale_price": null,
"was_price": null,
"is_on_sale": false,
"availability": "in_stock",
"match_confidence": "high",
"match_score": 0.86,
"match_reasons": ["brand_match", "size_match"],
"source_url": "https://www.loblaws.ca/...",
"image_url": "https://...",
"product_id": "20123456",
"package_size": "454 g",
"selling_type": "by_weight",
"multi_buy_deal": null,
"pc_optimum_offer": null,
"category": "search:ground beef",
"country": "CA",
"currency": "CAD",
"region": "BC",
"scraped_at": "2026-05-15T14:32:11.123Z",
"run_id": "abc123"
}

Every dataset record carries a _type. Branch on it: comparison and category_browse_product are product rows, the rest are roll-ups and run metadata.

Why this Actor

  • 705 runs across the suite in the last 30 days, none ended in a failed state. Run stats are public on the Apify API; figures from August 2026.
  • Every match shows its work. match_score runs 0 to 1, match_confidence buckets it high, medium or low, and match_reasons and mismatch_reasons name the signals behind the score, such as brand agreement or a differing package size.
  • Unit prices compare across chains. comparable_unit_price and comparable_unit_basis (100g, 100ml, each, lb) put a 1.89 L Superstore carton and a 2 L Save-On-Foods one on the same footing, and is_comparable_unit_price marks the rows where that holds.
  • Every retailer gets a verdict. run_meta.retailer_status reports success, no_results, failed with a reason, or skipped, and run_meta.warnings collects location and search failures, so a partial run tells you which retailer came up short.
  • Defaults stay small. Naming no retailers runs the six national chains; the other ten are opt-in, so an unspecified run stays predictable.
  • Runs without a browser, over plain HTTP against each retailer's own JSON API, with the Apify SDK as its only runtime dependency and no API keys.

What people build with it

  • Fixed-basket inflation tracking, rerunning the same list weekly and charting basket_summary totals
  • Grocery price comparison apps, using comparison rows straight as backend data
  • AI shopping agents, which get one normalized table instead of four retailer schemas
  • CPG competitor monitoring across banners and parent companies at once
  • Household budgeting dashboards in Google Sheets or Excel, fed by a scheduled run
  • Academic and journalistic food-price research needing store-level Canadian data

Input

FieldTypeRequiredDescription
queriesstring[]yesGrocery search terms. Also accepted as items. Free Apify plan: first 5 per run, the rest are skipped
retailersstring[]noAny subset of the 16 keys below. Default: tnt, loblaws, superstore, nofrills, saveonfoods, pricesmart
locationstringnoCity and province (Vancouver, BC) or postal code. Alias for region and postal_code
regionstringnoOne of 8 metros: Vancouver, Calgary, Edmonton, Toronto, Ottawa, Montreal, Quebec City, Halifax. Default metro_vancouver
postal_codestringnoOverrides region
locationIdsobjectnoPer-retailer store overrides, e.g. { "tnt": "MGFS", "superstore": "1517" }
categoriesstring[]no17 unified category slugs, used by category_browse and intel modes. Free Apify plan: first 5 per run, the rest are skipped
maxResultsPerQueryPerRetailerintegernoDefault 3. Free Apify plan: 100 product results per run in total
retailerConcurrencyintegernoDefault 3
minMatchConfidencestringnolow (default), medium or high
strictItemBestbooleannoDefault true. Restricts item_best_options to rows with a comparable unit price and medium or high confidence
includeSummariesbooleannoDefault false. Adds basket_summary, item_best_options and run_meta rows
outputModestringnoSee below. Default comparison

Output modes

ModeBest for
comparisonFlat rows, one matched product per query per retailer. CSV, Excel and ETL
comparison_groupedOne record per query with all retailer results nested. LLM and agent input
summaryCheapest retailer, price range, median price and sale count per query
category_browseFull category listings per retailer, with no query matching
intelComparison rows plus summaries, category stats, top deals and a run summary

Start with comparison unless you know you need another one.

Fixed-basket tracking

Run the same basket on a schedule to build a price history:

{
"queries": ["eggs", "milk", "bread", "bananas", "chicken breast", "ground beef", "rice", "celery"],
"location": "Vancouver, BC",
"retailers": ["loblaws", "saveonfoods", "tnt"],
"includeSummaries": true
}

With includeSummaries on, each run also emits:

  • basket_summary, the basket total per retailer
  • item_best_options, the cheapest source per item
  • run_meta, per-retailer status and warnings

That covers basket totals, per-item winners and sale frequency over time with no post-processing.

Supported retailers

KeyChainWhere
loblawsLoblawsBC, AB, ON
superstoreReal Canadian SuperstoreBC, AB, SK, MB, ON, YT
nofrillsNo FrillsNationwide
zehrsZehrsON
fortinosFortinosON
valumartValu-martON, QC
independentYour Independent GrocerNationwide
provigoProvigoQC
maxiMaxiQC, NB
wholesaleclubWholesale ClubNationwide
atlanticsuperstoreAtlantic SuperstoreNB, NS, PE
saveonfoodsSave-On-FoodsBC, AB, SK, MB
pricesmartPriceSmart FoodsMetro Vancouver
urbanfareUrban FareVancouver, Kelowna
qualityfoodsQuality FoodsVancouver Island, Sunshine Coast
tntT&T SupermarketBC, AB, ON, QC

T&T serves one catalogue chain-wide, so its resolved store labels the rows while prices stay constant. Loblaw and Pattison banners price per store.

FAQ

How do I compare grocery prices across Canadian stores? Give queries (your grocery list), a location, and the retailers you want. Each run returns one matched row per item per retailer, with price, unit price and a confidence score.

Which is cheapest for my basket? Set "includeSummaries": true and read the basket_summary rows, which total the basket per retailer, and item_best_options, which names the cheapest source per item.

Are the matches exact? Not always. The Actor compares retailer search results, and grocery products vary by brand, size and naming. Every row carries match_score, match_confidence and the reasons behind them; filter with minMatchConfidence.

Which retailers run by default? The six national chains: tnt, loblaws, superstore, nofrills, saveonfoods and pricesmart. The other ten are opt-in.

Does it cover Sobeys, Metro, Walmart or Costco? Sobeys, Metro and Walmart Canada are outside the 16. Costco has a separate Actor.

Does it track price history? No. Each run returns current prices. Schedule the same basket and keep each dataset to build history.

Is scraping these retailers legal? Scraping publicly available product and price information is generally legal. Complying with each retailer's terms of service and the law in your jurisdiction remains your responsibility, so keep request volume reasonable.

Limitations

  • This Actor compares retailer search results, and makes no guarantee of exact product equivalence across stores, because grocery products vary by brand, size, store and naming. Review matches with match_confidence, package_size, comparable_unit_price and source_url, and filter them with minMatchConfidence.
  • Prices and availability vary by store, postal code, time of scrape, loyalty program and retailer search behaviour.

Canadian grocery Actors

ActorChainsCoverage
Canadian Grocery Price Comparison API (this Actor)16, matched and ranked in one runNationwide
Loblaws, No Frills, Superstore & Maxi Scraper API - Canada12 Loblaw bannersEvery province, YT, NT
Save-On-Foods, PriceSmart & Urban Fare Scraper API - Canada4 Pattison Food Group bannersBC, AB, SK, MB
T&T Asian Supermarket Grocery Price Scraper API - CanadaT&TBC, AB, ON, QC
Costco Scraper API - Warehouse Prices & DealsCostco warehousesCanada and US

Use this Actor to compare across chains. Use a retailer Actor when you want one chain in depth, with full category trees, whole-store scrapes and every field that chain exposes. All four retailer Actors share 21 core output fields, so their datasets concatenate without a mapping layer.

Feedback

Found a bug or have technical feedback? Open an issue on the Actor's Issues tab.