# Canadian Tire Store Stock & Clearance Tracker (`automatic/canadian-tire-store-stock`) Actor

Canadian Tire in-store stock near a Canadian postal code: units per store for clearance, searched or chosen products, with regular and sale price, discount, aisle, store address and distance. Sort by discount, distance or stock; track restocks and price drops between runs.

- **URL**: https://apify.com/automatic/canadian-tire-store-stock.md
- **Developed by:** [Philip Kirkbride](https://apify.com/automatic) (community)
- **Categories:** E-commerce
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.95 / 1,000 product in a stores

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 Store Stock & Clearance Tracker

Find Canadian Tire clearance offers and nearby stock before you make the trip. Choose a postal code, a search phrase or specific products to compare store quantities, displayed prices and discounts in one table. Stock belongs to each individual store; displayed prices come from the nearest store and are clearly identified in each result.

Use changes mode to follow restocks, stock changes and price changes between runs.

### Who it is for

- Bargain hunters and resellers looking for deep clearance markdowns close to home
- Shoppers who want to know which nearby store still has an item before driving there
- Deal sites and price trackers that follow Canadian Tire clearance in a city
- Anyone watching a few products for a restock or a price drop
- Stock-alert and price-tracking apps that need a daily store-level feed

### Quick start

1. Open the Input tab. The form is prefilled with a downtown Toronto postal
   code (`M5V 3L9`), the 5 nearest stores within 25 km, 10 clearance products
   and a 100-row cap.
2. Click **Start**, then open the Output tab or export the rows as JSON, CSV
   or Excel.

An empty input (`{}`) also works: it checks the clearance listing near
downtown Toronto (`M5V 3L9`) at the 10 nearest stores within 25 km, for 20
products and at most 200 rows. Change the postal code to search your own area.

### What you get

One row per product per store:

- **Product:** name, brand, SKU, product code, link and image
- **Store:** store number, name, street address, city, province, postal code, map position, distance from your location, and the store's phone, fax, e-mail and dealer name as Canadian Tire lists them
- **Stock:** units in the store, a stock status (in stock, limited, out of stock or unknown), the aisle when the store lists one, and units for online orders when shown
- **Price:** regular price, current price, discount percent, clearance flag, and the price messages and badges exactly as Canadian Tire shows them
- **Changes mode:** what changed, the previous units and prices, how much the price fell, and when the item was first and last seen at that store

### Input

| Field | What it does |
|---|---|
| Postal code | Where to search, for example `M5V 3L9`. You can give a latitude and longitude instead. |
| Radius (km) | Only stores within this distance, 1 to 200. Default 25. |
| Maximum stores | The nearest stores to check, up to 50. Default 10. |
| Scan the clearance listing | Check Canadian Tire's clearance products. On when you give nothing else. |
| Products | Up to 200 SKUs (`0439003` or `043-9003-8`), product codes (`0439003P`) or product page links. |
| Search | Search words, for example `kitchenaid mixer`. |
| Maximum products | How many products to check, up to 500. Default 20. |
| Maximum rows | Stop after this many rows, up to 10,000. Default 200. |
| Sort by | Biggest discount, nearest store, or most in stock. |
| In stock only / Minimum discount | Optional filters for full mode. |
| Mode | `full` for every row, `changes` for only what changed since the last run. |
| State key | Changes mode: a name for your saved watch list, so runs with the same name compare against each other. |

Example: clearance near downtown Toronto, five closest stores, ten products:

```json
{
  "postalCode": "M5V 3L9",
  "radiusKm": 25,
  "maxStores": 5,
  "maxProducts": 10,
  "sortBy": "discount"
}
```

Example: watch two products near Ottawa and report only changes:

```json
{
  "postalCode": "K1P 1J1",
  "products": ["0439003", "https://www.canadiantire.ca/en/pdp/dyson-ball-allergy-bagless-upright-corded-vacuum-cleaner-0438297p.html"],
  "mode": "changes",
  "stateKey": "ottawa-mixers"
}
```

### Example row

**Selected fields only.**

```json
{
  "productId": "0438297P",
  "sku": "0438297",
  "skuNumber": "043-8297-4",
  "title": "Dyson Ball Allergy + Bagless Upright Corded Vacuum Cleaner",
  "brand": "Dyson",
  "url": "https://www.canadiantire.ca/en/pdp/dyson-ball-allergy-bagless-upright-corded-vacuum-cleaner-0438297p.html",
  "storeId": "621",
  "storeName": "Liberty Village, ON",
  "address": "5 Joe Shuster Way",
  "city": "Toronto",
  "province": "ON",
  "postalCode": "M6K 0C7",
  "latitude": 43.639935,
  "longitude": -79.423492,
  "distanceKm": 1.94,
  "storePhone": "4165883232",
  "storeFax": "4165883699",
  "storeEmail": "ct621@canadiantirecares.ca",
  "dealerName": "MATTHEW DEROUIN",
  "quantity": 4,
  "stockStatus": "in_stock",
  "shelfLocation": "Aisle 2",
  "regularPrice": 699.99,
  "salePrice": 479.93,
  "currency": "CAD",
  "discountPct": 31.4,
  "clearance": true,
  "priceLabels": [],
  "badges": [
    "TOPRATED_EN",
    "TOPRATED",
    "TOPRATED_FR"
  ],
  "priceStoreId": "621",
  "foundIn": "clearance",
  "observedAt": "2026-11-04T22:37:40.601034+00:00",
  "changeType": null
}
```

In changes mode `changeType` is one of `new`, `stockChanged`, `backInStock`, `outOfStock`, `priceChanged` or `gone`, with `previousQuantity`, `previousSalePrice` and `priceDropFromLastSeen` filled in.

### Good to know

- **Prices are the nearest store's.** Canadian Tire prices can differ from store to store. Every row shows the prices of the nearest store (`priceStoreId`); units are each store's own.
- **Discounts are Canadian Tire's own.** The discount compares the regular and current price the site shows. Many clearance items show one price only; their discount is empty rather than guessed. Changes mode then reports how much the price fell since your last run.
- **Products with sizes or colours** (tires, wheels, clothing) are checked one variant at a time: give the variant's SKU. The clearance and search listings skip them and say how many were skipped. A variant's price may be empty.
- **Missing stock is unknown.** A missing quantity does not mean the item is sold out. Incomplete observations do not become stock-change alerts.
- **The first changes run** reports every row as new; later runs report only changes. Keep the same state key, location and products between runs.
- **Postal-code searches are approximate.** Use latitude and longitude for a more precise starting location.
- Up to 500 products, 50 stores and 10,000 rows per run, subject to your run limits and the available listings.
- Stock figures are what the store's system shows and can be a little behind the shelf. Call the store before a long drive.

### FAQ

**How fresh is the stock?** Each run reads units and prices at run time;
nothing is cached between runs.

**Why is a discount empty on a clearance item?** Canadian Tire often shows a
clearance item with one price only. The Actor never guesses a discount; use
changes mode to see how far the price fell since your last run.

**How do I get daily restock or markdown alerts?** Use changes mode with a
fixed state key, the same location and products, and a daily schedule. Then
send the dataset to a webhook, e-mail or spreadsheet integration.

**Can I watch tires or clothing?** Yes, one variant at a time: give the
variant's SKU in Products.

**What export formats are there?** JSON, CSV, Excel, XML and RSS from the
dataset, like any Apify run.

### Pricing

The run-start event costs **$0.005 per GB of memory**, with a minimum of one
event. The default 512 MB run is one start event, charged even if no rows are
saved.

Full mode costs **$0.00095 per delivered product-store row**.

Changes mode also costs **$0.0016 per product-store observation**, even when
nothing changed. Returned changes carry the same $0.00095 per-row price.
Set a maximum total charge to control your result budget.

Worked costs: the prefilled run (up to 100 rows) costs at most about
**$0.10**; 1,000 full-mode rows cost about **$0.955**. A daily changes run over
10 products at 5 stores (50 observations) costs about $0.085 plus $0.00095 for
each change it returns.

See the Pricing tab for the current prices.

# Actor input Schema

## `postalCode` (type: `string`):

Canadian postal code to search around, for example M5V 3L9. Location is approximate at postal-code-area level. Ignored when latitude and longitude are given.

## `latitude` (type: `number`):

Optional exact latitude to search around (use with longitude instead of a postal code).

## `longitude` (type: `number`):

Optional exact longitude to search around (use with latitude instead of a postal code).

## `radiusKm` (type: `integer`):

Only stores within this distance are included.

## `maxStores` (type: `integer`):

The nearest stores to check, up to 50. Each product gets one row per store.

## `clearance` (type: `boolean`):

Check the products Canadian Tire lists as clearance. On by default when no products or search are given. With a search, only clearance products matching it are checked.

## `products` (type: `array`):

Products to track: SKUs (0439003 or 043-9003-8), product codes (0439003P) or product page links. For products sold in several sizes or colours, give the SKU of the variant.

## `searchQuery` (type: `string`):

Optional search words, for example kitchenaid mixer. A search that matches a whole department opens a category on the site and returns no products; use more specific words.

## `maxProducts` (type: `integer`):

How many products to check stock for, up to 500. Listed products come after the ones you name.

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

Stop after this many product-store rows (sorted first).

## `sortBy` (type: `string`):

discount: biggest markdown first; distance: nearest store first; stock: most units first.

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

Full mode only: keep only stores that have the product in stock.

## `minDiscountPct` (type: `number`):

Full mode only: keep only rows with at least this markdown from the regular price.

## `mode` (type: `string`):

full: every product-store row. changes: only what changed since the last run with the same state key (new, stock changes, back in stock, out of stock, price changes, gone).

## `stateKey` (type: `string`):

Changes mode: a name for the saved state (letters, digits, dashes). Runs with the same key compare against each other. Leave empty to derive one from the location and products.

## Actor input object example

```json
{
  "postalCode": "M5V 3L9",
  "radiusKm": 25,
  "maxStores": 5,
  "products": [],
  "maxProducts": 10,
  "maxItems": 100,
  "sortBy": "discount",
  "inStockOnly": false,
  "mode": "full"
}
```

# Actor output Schema

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

No description

# 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 = {
    "postalCode": "M5V 3L9",
    "radiusKm": 25,
    "maxStores": 5,
    "maxProducts": 10,
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("automatic/canadian-tire-store-stock").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 = {
    "postalCode": "M5V 3L9",
    "radiusKm": 25,
    "maxStores": 5,
    "maxProducts": 10,
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("automatic/canadian-tire-store-stock").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 '{
  "postalCode": "M5V 3L9",
  "radiusKm": 25,
  "maxStores": 5,
  "maxProducts": 10,
  "maxItems": 100
}' |
apify call automatic/canadian-tire-store-stock --silent --output-dataset

```

## MCP server setup

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

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/2dBHPfGdZj3OinHo5/builds/pRMIz1kauwha2Uz61/openapi.json
