# Indigo Books Scraper — Chapters & Coles Prices, ISBN, Stock (`yugenox/indigo-scraper`) Actor

Scrape indigo.ca (Indigo, Chapters, Coles): books, eBooks and gifts by keyword, ISBN, bestseller list or link. Price vs list price, ISBN-10/13 for every format, authors, publisher, online stock, live per-store stock across ~160 Canadian stores, ratings and reviews. No login.

- **URL**: https://apify.com/yugenox/indigo-scraper.md
- **Developed by:** [Yugenox Corp](https://apify.com/yugenox) (community)
- **Categories:** E-commerce, Automation, Integrations
- **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 results

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

## Indigo Books Scraper: Chapters & Coles Prices, ISBNs and Stock

This actor scrapes **indigo.ca**, the online store of Canada's largest bookstore chain (Indigo, Chapters and Coles). You can look up books, eBooks, audiobooks and gifts by **keyword, ISBN, bestseller list or link**. Each result is a clean row with:

- the current price, the list price and the discount
- ISBN-10 and ISBN-13 for every format
- authors, publisher and series
- online stock and, optionally, **live stock at each of about 160 stores**, with quantities and pickup times
- the star rating, the review breakdown and the latest reviews

You don't need an Indigo account, API key or browser.

### What you can scrape

| Input | What you get |
|---|---|
| **Search terms** (`atomic habits`, `stephen king`, `dune`) | Every matching product, in the website's order or sorted by price, newest, release date or rating |
| **ISBNs / barcodes** (ISBN-13, ISBN-10 or UPC) | That exact edition, with price and stock. Useful for checking a list of books against Indigo |
| **Collections & bestseller lists** (`new-york-times-bestsellers`, `globe-and-mail-bestsellers`, `heathers-picks`, `canadian-authors`, `most-anticipated-books`, `new-this-week-books`, `kids-books`, `kobo-sale`…) | The whole list, in rank order |
| **indigo.ca links** (product, collection or search pages) | The same data as the page shows. Old-style links from the previous site (`…/en-ca/books/…/9780735211292-item.html`) work too: the ISBN in the link is looked up |

#### Filters

- Department (books, kids' books, eBooks, gifts, toys, lifestyle)
- Format (hardcover, paperback, Kobo eBook, audiobook, board book…)
- Language
- Price range and minimum star rating
- Labels such as *Heather's Pick*, *Staff Pick*, *Canadian*, *New York Times Bestseller* or *Signed Edition*
- Only products on sale, or only products available online

### Use cases

- **Book arbitrage and FBA scouting.** Price a list of ISBNs at Indigo and compare them with Amazon.ca. Find discounted titles and see which store has copies on the shelf.
- **Publishers, authors and agents.** Track the price, discount, promotions and bestseller-list placement of your titles in Canada.
- **Price comparison and deal sites.** Get daily prices and list prices for the whole range of a search or category.
- **Retail and market research.** Track new releases, pre-orders, format mix, series and Canadian-author titles.
- **Store availability.** Find which Indigo, Chapters or Coles stores in a city or postal area have a title in stock, and how many copies.

### Input examples

A keyword search with ratings and reviews:

```json
{
  "searchTerms": ["atomic habits", "project hail mary"],
  "maxItemsPerQuery": 50,
  "includeReviews": true,
  "maxReviews": 5
}
```

A price check on a list of ISBNs, with Toronto store stock and one row per ISBN even when Indigo doesn't carry the book:

```json
{
  "isbns": ["9780735211292", "0-593-13520-5", "9780593135204"],
  "includeStoreStock": true,
  "storeFilter": ["Toronto"],
  "includeNotFound": true
}
```

Bestseller lists, hardcovers only:

```json
{
  "collections": ["new-york-times-bestsellers", "globe-and-mail-bestsellers"],
  "formats": ["Hardcover"],
  "maxItemsPerQuery": 500
}
```

Sale items in a department, cheapest first:

```json
{
  "category": "kids-books",
  "onSaleOnly": true,
  "sortBy": "price_asc",
  "maxItems": 1000
}
```

### Output

By default each product gives **one row**. The row shows the format the website lists first, and the other formats are listed in `otherFormats`. Turn on **One row per format** to give each hardcover, paperback, eBook or audiobook its own row, with its own ISBN, price and stock.

```json
{
  "title": "Atomic Habits: An Easy & Proven Way to Build Good Habits & Break Bad Ones",
  "authors": ["James Clear"],
  "format": "Hardcover",
  "isbn13": "9780735211292",
  "isbn10": "0735211299",
  "price": 27,
  "compareAtPrice": 36,
  "discountPct": 25,
  "onSale": true,
  "currency": "CAD",
  "promotions": ["Promo - Up to 25% off Bestsellers"],
  "availability": "in_stock",
  "onlineQtyAvailable": 3355,
  "storesInStockCount": 154,
  "stores": [
    { "store": "Toronto Eaton Centre", "city": "Toronto", "provinceCode": "ON", "postalCode": "M5B 2H1",
      "address": "220 Yonge Street", "phone": "(416) 591-3622", "available": true, "quantity": 48,
      "pickUpTime": "Usually ready in 24 hours" }
  ],
  "rating": 4.81,
  "reviewCount": 569,
  "starDistribution": { "1": 3, "2": 1, "3": 10, "4": 75, "5": 480 },
  "readerRatings": { "Reading Pace": 3, "Resonance": 2 },
  "reviews": [
    { "rating": 5, "title": "Evidenced-based book", "text": "Better than most self help books…",
      "date": "2025-11-30", "verifiedBuyer": true, "country": "CA" }
  ],
  "publisher": "Penguin Publishing Group",
  "imprint": "Avery",
  "language": "English",
  "pageCount": 320,
  "releaseDate": "2018-10-16",
  "featured": ["Heather's Pick", "Staff Pick"],
  "genre": "Self-Help General",
  "collections": ["Trending on BookTok", "Indigo Non-Fiction Bestsellers", "Workplace Culture"],
  "imageUrl": "https://cdn.shopify.com/s/files/1/0655/8980/5233/files/1_d8dc….jpg",
  "url": "https://www.indigo.ca/products/atomic-habits",
  "otherFormats": [
    { "format": "Audiobook", "isbn13": "9780593207093", "price": 19.99, "availability": "out_of_stock" },
    { "format": "Kobo eBook", "isbn13": "9780735211308", "price": 16.99, "availability": "digital" }
  ],
  "source": { "type": "isbn", "input": "9780735211292" },
  "rank": 1,
  "scrapedAt": "2026-09-24T02:57:23.266Z"
}
```

Each row also includes:

- `upc`, `sku`, `inventoryPolicy`, `storesWithStockCount`
- `seriesName`, `seriesId`, `seriesPosition`
- `illustrators`, `translators`, `editors`, `contributorIds`
- `productType`, `brand`, `colour`, `subject`, `collectionIds`, `browseCategoryIds`
- `adultOnly`, `largePrint`, `returnable`
- `handle`, `productId`, `variantId`, `listedAt`, `description`, `formatsCount`

The **Overview** and **Stock** tabs of the dataset show the most useful columns. The CSV export leaves out the nested lists.

#### The `availability` field

| Value | Meaning |
|---|---|
| `in_stock` | Ships now; `onlineQtyAvailable` units are available online |
| `preorder` | Not released yet; orders are being taken |
| `backorder` | Released but out of stock; orders are still being taken |
| `out_of_stock` | Can't be ordered online right now (it may still be in stores; turn on per-store stock) |
| `digital` | A Kobo eBook or audiobook, delivered digitally |

### Tips

- **Past 10,000 results.** Indigo shows at most 10,000 results for any one search or collection. If you set **Max results per search** above 10,000, the actor splits the search into price bands, then by format and language. Each band stays under the limit, and duplicates are removed. Crawling the entire catalogue (about 8 million products) is out of scope. Split a large department with the filters instead.
- **Broad words like "romance" or "cookbooks"** open a curated collection on indigo.ca instead of search results. The actor does the same, and the row's `source.redirectedTo` shows which collection it used. Turn off *Follow category redirects* to get plain keyword matches instead.
- **Collection names** are the last part of a collection link: `indigo.ca/collections/heathers-picks` → `heathers-picks`. Every row's `collectionIds` also lists the collections a product belongs to, so you can use those as inputs.
- **On sale only / Available online only** are checked product by product, so on a broad search the actor reads through the whole result list (up to 10,000 per search) to find the matches. That is slower. Narrow the search, pick a collection like `kobo-sale`, or add a price or format filter.
- **Spending limit.** If you set a maximum cost for the run, the actor stops just before it, and every row it returns is covered.
- **Speed.** One request returns up to 200 products. Searches and lists run at thousands of products per minute. Per-store stock and reviews add one small request per product.

### FAQ

**Do I need an Indigo account or cookies?**
No. The actor reads the same public data the website shows to any visitor.

**Which proxy should I use?**
Apify's datacenter proxy, which is the default. If the store ever starts refusing datacenter traffic, the actor switches to Canadian residential proxies on its own.

**Are the prices and stock live?**
Yes. Prices, online stock and the in-store count come from the live catalogue at the time of the run. With *Per-store stock* on, the online quantity and each store's quantity are also read live from the store.

**Does it include Chapters and Coles?**
Yes. They share one catalogue and one store network with Indigo. Per-store stock covers every store location listed on indigo.ca (about 160). Distribution centres are left out.

**French books? eBooks? Gifts?**
Yes to all three. French and other languages can be filtered. Kobo eBooks are listed with `availability: "digital"`. Gifts, toys and stationery come with their brand, colour or scent and a UPC.

**What happens when an ISBN isn't sold at Indigo?**
By default it is skipped and listed in the run's status message. Turn on *Rows for codes Indigo doesn't carry* to get one `found: false` row for each missing code.

**Are reviewer names included?**
No. Reviews include the rating, title, text, date, verified-buyer flag and country, but not the reviewer's identity.

**Is it legal to scrape indigo.ca?**
This Actor only collects publicly available data: product listings, prices, stock levels, store locations, ratings and reviews that anyone can see on indigo.ca without an account. Collecting publicly available data is generally legal, but you're responsible for how you use it. Results include the names of authors and other contributors as credited on each product, and that counts as personal data. You must follow privacy laws such as GDPR, PIPEDA and CCPA, as well as Indigo's terms. 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 indigo.ca shows 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

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

Titles, authors, series or keywords — what you would type into the indigo.ca search box. Each term is scraped separately.

## `isbns` (type: `array`):

ISBN-13, ISBN-10 (hyphens are fine) or UPC barcodes. Each code returns that exact edition — ideal for checking a list of books against Indigo's price and stock.

## `collections` (type: `array`):

Collection names or indigo.ca/collections/… links, e.g. new-york-times-bestsellers, globe-and-mail-bestsellers, heathers-picks, canadian-authors, most-anticipated-books, new-this-week-books, bestselling-books, kids-books, booker-prize, kobo-sale.

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

Product pages, collection pages or search result pages from indigo.ca. A product link with ?variant=… returns that exact format.

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

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

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

Upper limit for each search term or collection. Indigo shows at most 10,000 results for one search; ask for more and the actor splits the search by price, format and language to go past that.

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

Order of search and collection results, as on the website.

## `category` (type: `string`):

Limit searches to one department. Picking a department without any search terms scrapes the department itself.

## `formats` (type: `array`):

Only these formats. Leave empty for all.

## `languages` (type: `array`):

Only books in these languages, e.g. English, French, Spanish; Castilian, German. Leave empty for all.

## `featured` (type: `array`):

Only products carrying one of these labels.

## `minPrice` (type: `integer`):

Only products at or above this price.

## `maxPrice` (type: `integer`):

Only products at or below this price.

## `minRating` (type: `integer`):

Only products rated at least this many stars (1–5).

## `onSaleOnly` (type: `boolean`):

Keep only products priced below their list price.

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

Keep only products that can ship now (in stock online, or eBooks).

## `emitEachFormat` (type: `boolean`):

Give every format of a book (hardcover, paperback, eBook, audiobook…) its own row with its own ISBN, price and stock. Off: one row per book, other formats listed inside it.

## `includeStoreStock` (type: `boolean`):

Live stock at each Indigo, Chapters and Coles store: store name, city, postal code, phone, quantity on hand and pickup time. Also refreshes the online quantity.

## `storeFilter` (type: `array`):

Only list stores matching one of these: a city (Toronto), a province code (ON, BC), a postal code or its start (M5V, V6), or part of a store name (Yorkdale). Leave empty for every store.

## `storesInStockOnly` (type: `boolean`):

List only stores with the item in stock. The in-stock store count is always included.

## `includeReviews` (type: `boolean`):

Adds the review count, star breakdown, reader ratings (reading pace, resonance…) and the latest reviews.

## `maxReviews` (type: `integer`):

How many of the latest reviews to include per product. 0 = the rating breakdown only.

## `includeDescription` (type: `boolean`):

The publisher's description of each product.

## `includeNotFound` (type: `boolean`):

Add a row with found: false for every ISBN, barcode or link that Indigo does not sell, so your list lines up one-to-one.

## `followRedirects` (type: `boolean`):

Broad words like "romance" or "cookbooks" take you to a curated collection on indigo.ca. On: scrape that collection, like the website. Off: plain keyword matches.

## `maxConcurrency` (type: `integer`):

Higher is faster for long ISBN lists and big crawls.

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

Apify's datacenter proxy works and is the cheapest. The actor switches to residential proxies by itself if the store ever blocks datacenter traffic.

## Actor input object example

```json
{
  "searchTerms": [
    "atomic habits"
  ],
  "maxItems": 20,
  "maxItemsPerQuery": 100,
  "sortBy": "relevance",
  "category": "any",
  "onSaleOnly": false,
  "inStockOnly": false,
  "emitEachFormat": false,
  "includeStoreStock": false,
  "storesInStockOnly": true,
  "includeReviews": false,
  "maxReviews": 10,
  "includeDescription": true,
  "includeNotFound": false,
  "followRedirects": true,
  "maxConcurrency": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `products` (type: `string`):

Every scraped product row as JSON.

## `productsCsv` (type: `string`):

The same rows as CSV, for a spreadsheet or a price-tracking sheet.

## `productsTable` (type: `string`):

The same rows narrowed to title, author, format, ISBN, price, list price, stock and rating.

# 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 = {
    "searchTerms": [
        "atomic habits"
    ],
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("yugenox/indigo-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 = {
    "searchTerms": ["atomic habits"],
    "maxItems": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("yugenox/indigo-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 '{
  "searchTerms": [
    "atomic habits"
  ],
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call yugenox/indigo-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yugenox/indigo-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/mchIaEdHDhIWNllxI/builds/lFdMCxCMUx7y3OFz9/openapi.json
