Save-On-Foods, PriceSmart, Urban Fare & Quality Foods Scraper
Pricing
from $0.80 / 1,000 product rows
Save-On-Foods, PriceSmart, Urban Fare & Quality Foods Scraper
Store-level grocery prices from Save-On-Foods, PriceSmart Foods, Urban Fare and Quality Foods across Western Canada. Search, aisles or whole stores, nearest stores by postal code. Sale dates, UPC, unit price, fees, stock, nutrition.
Pricing
from $0.80 / 1,000 product rows
Rating
0.0
(0)
Developer
Yugenox Corp
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Get store-level grocery prices from all four Pattison Food Group chains in Western Canada: Save-On-Foods, PriceSmart Foods, Urban Fare and Quality Foods, about 219 stores in British Columbia, Alberta, Saskatchewan, Manitoba and Yukon.
Search by keyword, scrape whole aisles or departments, or crawl an entire store (15,000 to 23,000 products). Prices come from the store nearest your postal code, or from several stores at once so you can compare them.
Every row carries the current price and the regular price, the sale's start and end dates, an already-scheduled next sale, the UPC / GTIN barcode, the unit price normalised to $/100 g or $/100 ml, the package size, deposit and eco fees, stock status, Made in Canada / Product of Canada flags, the full category path, the image, and a product link pinned to that store. Nutrition facts and ingredients are an optional add-on.
No account, no API key and no browser needed.
What you can do with it
- Track grocery prices at your local store week after week. Schedule the Actor and diff
priceover time. - Compare stores and chains. Prices differ between stores of the same chain: a 4 L jug of Dairyland 2% was $5.85, $6.25, $6.35 or $6.45 depending on the store.
- Build a deals feed from
is_on_sale,was_price,savings_percent,sale_ends_at, andnext_sale_pricefor sales that have not started yet. - Monitor CPG brands by UPC across all four chains.
- Power food apps and AI shopping agents with real Western Canada shelf prices, nutrition and ingredients.
- Research food inflation by region (Vancouver vs Kelowna vs Calgary vs Winnipeg).
How to use it
- Pick a chain (Save-On-Foods by default).
- Add search terms (e.g.
milk,chicken breast), pick categories from the list, or turn on Entire store. - Enter your postal code. The nearest store is used. Set Nearest stores to 3, 5 or more to compare stores, or give exact Store IDs.
- Click Start. Rows stream into the dataset as they arrive. Export them as JSON, CSV, Excel or through the API.
Input examples
One search at the store nearest a postal code:
{ "banner": "saveonfoods", "search_terms": ["milk"], "postal_code": "V6M 2P8" }
Everything in two aisles, at the 3 nearest Calgary stores, sale items only:
{"banner": "saveonfoods","categories": ["dairy-eggs/cheese", "meat-seafood"],"postal_code": "T2P 1J9","stores_per_banner": 3,"on_sale_only": true}
The same basket across all four chains:
{"banners": ["saveonfoods", "pricesmart", "urbanfare", "qualityfoods"],"search_terms": ["eggs", "butter", "bread"],"postal_code": "V6X 1A1"}
A whole store, with nutrition and ingredients:
{ "locationId": "2246", "all_products": true, "include_details": true }
Input fields
| Field | What it does |
|---|---|
banner | saveonfoods (default), pricesmart, urbanfare or qualityfoods |
search_terms | Keywords. Each returns up to ~280 best matches per store (the store's own search limit) |
categories | Departments or aisles from the dropdown, e.g. dairy-eggs or dairy-eggs/cheese. Every product in them is scraped |
categoryUrls | Any other category by numeric ID (30910) or by its URL on the chain's site |
all_products | Every product the store carries |
postal_code | Canadian postal code; picks the nearest store(s). Default V6M 2P8 |
locationId | Exact store ID(s), comma-separated; overrides the postal code |
stores_per_banner | How many nearest stores to price (1-50) |
all_stores | Price every store of the chain |
on_sale_only | Keep only products on sale right now |
include_details | Add nutrition facts, ingredients, serving size and extra images (one extra request per product) |
max_items_per_search | Limit per search term per store (default 1000) |
max_items | Limit for the whole run (0 = no limit) |
banners | Several chains in one run (overrides banner) |
sort | relevance, price, price desc, brand, brand desc; matters when a limit cuts the list |
Search terms combined with categories search inside those categories.
Output
One row per product per store. A real row (Save-On-Foods Kerrisdale, Vancouver):
{"store": "Save-On-Foods","name": "Dairyland - 2% Protein Milk","brand": "Dairyland","product_id": "00068700104428","upc": "068700104428","price": 5.99,"was_price": 6.99,"is_on_sale": true,"savings": 1,"savings_percent": 14.3,"sale_starts_at": "2026-09-17T07:00:00Z","sale_ends_at": "2026-09-24T04:59:00Z","next_sale_price": null,"unit_price": "$0.32/100ml","comparable_unit_price": 0.32,"comparable_unit": "100ml","package_size": "1.89 l","normalized_package_size": { "size": 1890, "unit": "ml" },"selling_type": "by_unit","deposit_fee": 0.1,"eco_fee": 0.02,"stock_status": "IN_STOCK","made_in_canada": true,"category": "dairy-eggs/milk-creams/2-milk","category_path": "Dairy & Eggs > Milk & Creams > 2% Milk","image_url": "https://images.cdn.saveonfoods.com/detail/00068700104428.jpg","product_url": "https://www.saveonfoods.com/sm/planning/rsid/2246/product/dairyland-2-protein-milk-id-00068700104428","location": "2246","location_name": "Kerrisdale","location_city": "Vancouver","location_postal_code": "V6M 3W4","location_coordinates": { "lat": 49.23271, "lng": -123.15565 },"distance_km": 0.8,"source": "search:milk"}
Rows also include description, gtin, plu (produce/bulk codes), price_text, pricing_unit_price and
pricing_unit (e.g. $6.99 / lb for meat sold by the piece), parsed_unit_price, parsed_package_size,
weight_increment (for items sold by weight), fees, promotions, has_loyalty_discount, badges,
notes (e.g. "Requires preparation time of 24 hours", "Pickup only"), categories, category_id, the store
address and province, and scraped_at.
With Nutrition, ingredients & extra images on, rows add ingredients, serving_size,
servings_per_package, nutrition (
{ "Calories": { "amount": 130, "unit": "cal" }, "Sodium": { "amount": 120, "unit": "mg", "daily_value_percent": 5 }, ... }additional_images.
The dataset has three table views: Products, Deals (sale windows and savings) and Nutrition & ingredients.
Field names
The core fields (store, name, price, was_price, is_on_sale, unit_price, comparable_unit_price,
package_size, parsed_package_size, normalized_package_size, selling_type, multi_buy_deal,
image_url, product_url, product_id, category, location, location_name, location_postal_code,
location_coordinates) use the same names as other Canadian grocery scrapers, so existing sheets and
pipelines work without remapping. price is a number.
FAQ
Which provinces and stores are covered? British Columbia, Alberta, Saskatchewan, Manitoba and Yukon: about 195 Save-On-Foods stores, 5 PriceSmart Foods, 5 Urban Fare and 14 Quality Foods (Vancouver Island). The store list is read live on every run, so new stores appear automatically. A postal code outside a chain's provinces is refused with the provinces it serves.
Why do I get about 260 results for a search term when the store has more? Keyword search returns the ~250-280 most relevant matches per term. For every product in an aisle or department, use Categories or Entire store; those have no such limit.
How long does an entire store take? About 2-3 minutes for a 15,000-product store. Large multi-store crawls run longer; the Actor stops cleanly before your run's timeout and keeps everything collected so far.
Are prices really per store?
Yes. Every row is priced at the store in location / location_name, and product_url opens the product at
that store. Sale prices and stock can differ between stores of the same chain.
What does next_sale_price mean?
Some sales are scheduled in advance. When a product has an upcoming sale that has not started yet, its price
and dates are in the next_sale_* fields, so you can see next week's deals early.
How do I find a store ID?
Usually the postal code is enough. Every row reports its location (store ID); you can also read it from the
store's URL on the chain's site (/rsid/2246/).
Can I schedule it? Yes. Save your input as a task and add a schedule (daily or weekly) in Apify Console, then connect the dataset to Google Sheets, a webhook or your database.
Can I use it from code? Yes, through the Apify API or the JavaScript and Python clients. Example:
curl -X POST "https://api.apify.com/v2/acts/yugenox~save-on-foods-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"banner":"saveonfoods","search_terms":["eggs","milk"],"postal_code":"V6M 2P8"}'
Use run-sync-get-dataset-items for small runs; for whole-store or multi-store runs start a run and read the
dataset when it finishes.
Is it legal to scrape Save-On-Foods, PriceSmart Foods, Urban Fare and Quality Foods? This Actor only collects publicly available data: product listings, prices, sale dates, stock, nutrition facts and store locations that anyone can see on these chains' websites without an account. Collecting publicly available data is generally legal, but you're responsible for how you use it. You must follow privacy laws such as GDPR, PIPEDA and CCPA, as well as each chain's terms. If you're unsure, check with a lawyer. More on this: Is web scraping legal?
Does it access any private data? No. Everything comes from pages Save-On-Foods, PriceSmart Foods, Urban Fare and Quality Foods show to any visitor without logging in. It never uses a login, never touches private or restricted accounts, and never reaches password-protected areas.