# Canadian Tire Scraper — Store Stock, Prices, Sport Chek, Mark's (`yugenox/canadian-tire-scraper`) Actor

Canadian Tire, Sport Chek, Mark's & Party City products by keyword, category, URL or code: store-level CAD price, units on the shelf, warehouse stock, sale & clearance prices, per-size/colour stock, ratings, part numbers. Nearest stores to any postal code. No login.

- **URL**: https://apify.com/yugenox/canadian-tire-scraper.md
- **Developed by:** [Yugenox Corp](https://apify.com/yugenox) (community)
- **Categories:** E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 product rows

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Canadian Tire, Sport Chek & Mark's Scraper — Store Stock & Prices

Scrape **Canadian Tire**, **Sport Chek**, **Mark's** and **Party City Canada** with one actor. For every product you get the **price at a specific store**, **units on that store's shelf**, **units in the distribution centre**, sale and clearance prices, and optionally **every size and colour with its own price and stock**.

Search by keyword, paste category / product / brand URLs, give exact product codes, or pull a store's **whole catalogue**. Pick stores by ID or let the actor find the **nearest stores to any postal code or city**. No account or login needed.

### What you can do with it

- **Store-level price & stock monitoring** — how many units of a product are on the shelf at each store, and what it costs there (prices really differ between stores).
- **Clearance and deal hunting** — every product on sale or on store clearance at your local stores, with the regular price, % off and sale end date.
- **Retail arbitrage & reselling** — manufacturer part numbers (MPN) and SKU numbers to match products against Amazon and other marketplaces, plus local stock to know where to buy.
- **Competitor & assortment research** — full catalogues by category, brand coverage, new arrivals, top sellers.
- **Size/colour availability** — for boots, clothing, tires and hockey sticks, which sizes are in stock at which store.

### Supported sites

| Banner | Site | Language |
|---|---|---|
| Canadian Tire | canadiantire.ca | English, French |
| Sport Chek | sportchek.ca | English |
| Mark's | marks.com | English |
| Party City (Canada) | partycity.ca | English, French |

### Input

| Field | What it does |
|---|---|
| **Stores (banners)** | Which retailers to search. Search terms run on each banner you pick. |
| **Search terms** | Keywords, brands, part numbers or product codes (`dewalt 20v`, `winter tires`, `0546716P`). |
| **Start URLs** | Product, category, brand or search-results URLs from any of the four sites. Filters in the URL are kept. |
| **Product codes** | Exact products (e.g. `0546716P`, `80940585F`) — returned with all sizes/colours and their store stock. |
| **Whole catalogue** | Every product the store carries. Result sets over 10,000 are split by category automatically. |
| **Near location** | Postal code (`M5V 2T6`), city (`Calgary`, `Laval, QC`) or `latitude,longitude`. |
| **Stores per location** | The N nearest stores (1–48) per location and banner — compare stock across a city. |
| **Store IDs** | Exact stores, e.g. `600`, or `SC:401` when using several banners. |
| **In stock only** | Only products with units on the shelf at the store. |
| **Deals** | On sale, clearance, or either. |
| **Sort by** | Relevance, price, newest, rating, best sellers. |
| **Sizes & colours** | Adds a `variants` list (per-size/colour price and stock) to multi-size products. |
| **Details** | Adds description, specifications, category path, and ratings for Sport Chek / Mark's. |
| **Max products per query / in total** | Limits. `0` = no limit. |

#### Example: DeWalt kits at a Toronto store

```json
{
  "banners": ["CTR"],
  "searchTerms": ["dewalt 20v"],
  "storeIds": ["600"],
  "maxItemsPerQuery": 50
}
```

#### Example: hockey sticks in stock at the 3 nearest Sport Chek stores, with sizes

```json
{
  "banners": ["SC"],
  "searchTerms": ["hockey stick"],
  "locations": ["Vancouver"],
  "nearestStores": 3,
  "inStockOnly": true,
  "includeVariants": true
}
```

#### Example: all clearance items at a store

```json
{
  "banners": ["CTR"],
  "fullCatalog": true,
  "deals": "clearance",
  "storeIds": ["150"],
  "maxItemsPerQuery": 0
}
```

### Output

One row per product per store. Example (trimmed):

```json
{
  "banner": "CTR",
  "bannerName": "Canadian Tire",
  "storeId": "600",
  "storeName": "Toronto Eaton Centre, ON",
  "code": "0546716P",
  "skuNumber": "054-6716-4",
  "partNumber": "DCK477D2",
  "title": "DEWALT DCK477D2 20V MAX Cordless Drill/Driver, Impact Driver, Circular Saw & Work Light Combo Kit",
  "brand": "DEWALT",
  "url": "https://www.canadiantire.ca/en/pdp/dewalt-dck477d2-20v-max-cordless-drill-driver-impact-driver-circular-saw-work-light-combo-kit-0546716p.html",
  "imageUrl": "https://media-www.canadiantire.ca/product/...jpg",
  "price": 399.99,
  "wasPrice": 649.99,
  "isOnSale": true,
  "discountPercent": 38,
  "savings": 250,
  "saleEndDate": null,
  "currency": "CAD",
  "badges": ["BESTSELLER", "TOPRATED", "PROMO"],
  "ecoFee": null,
  "rating": 4.68,
  "reviewCount": 63,
  "storeQty": 4,
  "inStockAtStore": true,
  "dcQty": 450,
  "dcEtaMinDays": 6,
  "dcEtaMaxDays": 12,
  "isMultiSku": false,
  "variants": null,
  "priceSource": "search",
  "stockSource": "search",
  "searchQuery": "dewalt 20v",
  "position": 2,
  "scrapedAt": "2026-09-24T04:44:37.580Z"
}
```

With **Sizes & colours** on, multi-size products carry a `variants` list:

```json
"variants": [
  { "sku": "1872509", "options": { "Shoe Size (US)": "9" }, "price": 99.99, "wasPrice": 189.99, "storeQty": 2, "dcQty": 107, "partNumber": "LY-WH190001A" },
  { "sku": "1872508", "options": { "Shoe Size (US)": "8" }, "price": 99.99, "wasPrice": 189.99, "storeQty": 1, "dcQty": 29, "partNumber": "LY-WH190001A" }
]
```

#### Field notes

- `storeQty` — units on the shelf at `storeId`. `null` means the store doesn't stock it (online-only), not zero.
- `dcQty` — units at the distribution centre (ships to home / to store); `dcEtaMinDays`–`dcEtaMaxDays` is the delivery estimate (days, when the search provides it). When store stock comes from the per-SKU lookup, `pickupEtaFrom`/`pickupEtaTo` (warehouse → store pick-up) and `deliveryEtaFrom`/`deliveryEtaTo` (ship to home) give the dates (YYYY-MM-DD) the site shows.
- For multi-size products, `price` is the lowest size price, `maxPrice` the highest, and `storeQty` / `dcQty` are summed over sizes.
- `priceSource` / `stockSource` tell you where a value came from; `null` stock means it couldn't be read for that row.
- `category` is filled when the row came from a category (a category URL, a keyword that opens a category, or a whole-catalogue slice).

### FAQ

**Do I need an account, cookies or a login?** No. No login is needed: the actor reads the same public product pages and store prices any visitor sees, and needs nothing from you except a search, category, URL or product code.

**How many products can I get?** A single search reaches up to 10,000 results per store. Whole-catalogue runs and very large categories are split into category slices automatically, so a full Canadian Tire store (~67,000 products) is covered.

**Why are prices different between stores?** Canadian Tire prices and stock are set per store. Run several stores to compare.

**Why do some Sport Chek / Mark's rows have no rating?** Their search listings don't include ratings. Turn on **Details** to add them.

**How fast is it?** Roughly 200 products per request on Canadian Tire and Party City (120 on Sport Chek and Mark's). Sport Chek and Mark's need one extra lookup per ~200 sizes to get store stock. Typical runs finish in seconds to a few minutes.

**Which store is used if I don't pick one?** A central Toronto store (Calgary for Mark's). Every row says which store it describes.

**Is French supported?** Yes for Canadian Tire and Party City. Sport Chek and Mark's only publish English data.

**Which proxy should I use?** Keep the default (Apify Proxy, datacenter). It comes with every Apify plan, including the free one. If datacenter IPs keep getting refused, the run switches to Canadian residential proxies when your account has them, and carries on without them when it doesn't. If the proxy you picked isn't available on your account, the run uses datacenter instead and says so in its status message.

**What happens if a run hits its time limit?** It stops shortly before the timeout (20% of the run time, at most a minute), saves everything collected so far, and finishes successfully. If the timeout is so short that nothing came back, the status message says so: give the run at least 120 seconds.

**Is it legal to scrape Canadian Tire, Sport Chek, Mark's and Party City?** This Actor only collects publicly available data: product listings, store prices, stock levels, ratings and store addresses that anyone can see on these sites without an account. Collecting publicly available data is generally legal, but you're responsible for how you use it. The results contain no personal data: ratings are totals and averages only, with no reviewer names or review text. You must follow the sites' terms and laws such as PIPEDA, GDPR and CCPA. If you're unsure, check with a lawyer. More on this: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

**Does it access any private data?** No. Everything comes from what these sites show to any visitor without logging in. It never uses a login, never touches private or restricted accounts, and never reaches password-protected areas.

# Actor input Schema

## `banners` (type: `array`):

Which retailers to search. Search terms run on every banner you pick; start URLs always run on their own site. Canadian Tire is used when this is empty.

## `searchTerms` (type: `array`):

Keywords, brands, part numbers or product codes, e.g. "dewalt 20v", "winter tires", "hockey stick", "0546716P". A product code returns that exact product.

## `startUrls` (type: `array`):

Product, category, brand or search-results pages from canadiantire.ca, sportchek.ca, marks.com or partycity.ca. Filters in a category URL (e.g. ?x1=brand\&q1=DEWALT) are kept.

## `productCodes` (type: `array`):

Exact products by their code (the last part of the product URL), e.g. 0546716P (Canadian Tire), 80940585F (Sport Chek), 75983118F (Mark's). Returns every size/colour with its store price and stock.

## `fullCatalog` (type: `boolean`):

Scrape every product the store carries (Canadian Tire: ~67,000 per store). Large result sets are split by category automatically. Set "Max products per query" to 0 to get everything.

## `locations` (type: `array`):

Price and stock come from the stores nearest to a postal code ("M5V 2T6"), city ("Calgary", "Laval, QC") or "latitude,longitude". Several locations = several stores.

## `nearestStores` (type: `integer`):

How many of the nearest stores to scrape for each location and banner (1–48). Each store is a separate set of rows — useful for comparing stock across a city.

## `storeIds` (type: `array`):

Exact stores. Every row reports its store ID, e.g. 600 = Canadian Tire Toronto Eaton Centre. Prefix with the banner when you use several banners: "CTR:600", "SC:401", "MKS:50", "PTY:820".

## `inStockOnly` (type: `boolean`):

Keep only products with units on the shelf at the selected store.

## `deals` (type: `string`):

Only products on sale, on store clearance, or either.

## `sort` (type: `string`):

Result order (matters when you cap the number of products).

## `includeVariants` (type: `boolean`):

Add a variants list to multi-size products (tires, boots, clothing, hockey sticks): every size/colour with its own price, units in store and warehouse stock. One extra request per multi-size product.

## `includeDetails` (type: `boolean`):

Add the full description, specifications and category path to every product, and star ratings for Sport Chek and Mark's. One extra request per product.

## `maxItemsPerQuery` (type: `integer`):

Limit for each search term / URL / catalogue, per store. 0 = no limit.

## `maxItems` (type: `integer`):

Stop the whole run after this many rows. 0 = no limit.

## `language` (type: `string`):

Product names and descriptions. French is available on Canadian Tire and Party City; Sport Chek and Mark's stay in English.

## `exactKeywordSearch` (type: `boolean`):

Some words open a category or brand page on the site ("drill" opens the Drills category). Off: scrape what the site shows. On: return every product whose text matches the words.

## `concurrency` (type: `integer`):

Parallel requests. The default is fast and gentle; raise it for very large runs.

## `proxyConfiguration` (type: `object`):

Apify Proxy is required. The default datacenter pool works; the actor switches to residential (Canada) on its own if it gets blocked.

## Actor input object example

```json
{
  "banners": [
    "CTR"
  ],
  "searchTerms": [
    "dewalt 20v"
  ],
  "fullCatalog": false,
  "nearestStores": 1,
  "storeIds": [
    "600"
  ],
  "inStockOnly": false,
  "deals": "none",
  "sort": "relevance",
  "includeVariants": false,
  "includeDetails": false,
  "maxItemsPerQuery": 50,
  "maxItems": 0,
  "language": "en",
  "exactKeywordSearch": false,
  "concurrency": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All scraped products with store price and stock.

## `run` (type: `string`):

Status and statistics for this run.

## `report` (type: `string`):

RUN_REPORT: how the run ended, counts and proxy use.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "banners": [
        "CTR"
    ],
    "searchTerms": [
        "dewalt 20v"
    ],
    "storeIds": [
        "600"
    ],
    "maxItemsPerQuery": 50,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("yugenox/canadian-tire-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "banners": ["CTR"],
    "searchTerms": ["dewalt 20v"],
    "storeIds": ["600"],
    "maxItemsPerQuery": 50,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("yugenox/canadian-tire-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "banners": [
    "CTR"
  ],
  "searchTerms": [
    "dewalt 20v"
  ],
  "storeIds": [
    "600"
  ],
  "maxItemsPerQuery": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call yugenox/canadian-tire-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yugenox/canadian-tire-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/Ofu3S8Gvbhiby2Amb/builds/M1FP8gTtkFt823qNz/openapi.json
