# Costco Scraper API - Warehouse Prices, Deals & Product Data (`sunny_eternity/costco-scraper`) Actor

Extract Costco prices and product data from costco.ca and costco.com — sale prices, discounts, package sizes, normalized unit pricing, images and item numbers. Pick a warehouse by postal code for regional pricing. Browse any department, paste product URLs, or search. Export as JSON, CSV or Excel.

- **URL**: https://apify.com/sunny\_eternity/costco-scraper.md
- **Developed by:** [JChaw](https://apify.com/sunny_eternity) (community)
- **Categories:** Automation, Integrations, E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Costco Scraper — Warehouse Prices, Deals & Product Data

Extract product data from [Costco Canada](https://www.costco.ca) and [Costco US](https://www.costco.com) — product names, current prices, sale prices and discounts, package sizes, derived unit pricing, images, ratings, and warehouse item numbers.

The scraper is **location-aware**: give it a postal code and it resolves the nearest warehouse, then returns that region's catalog and pricing. Costco's assortment genuinely differs by province — a BC run and an Ontario run return different products for the same query.

### ⚡ Quick start

Scrape Costco Canada's grocery department for a Vancouver warehouse:

```json
{
  "site": "CABC",
  "categories": ["grocery-household"],
  "postal_code": "V6B 1V4",
  "max_items": 1000
}
```

Selecting a department also scrapes everything nested beneath it, so you don't need to list its subcategories as well.

### 🔗 Related Actors

Pair this with our other North American grocery scrapers for full coverage:

- **[Canadian Grocery Price Comparison](https://apify.com/sunny_eternity/canada-grocery-price-comparison)** — Query in, comparison out. One call across Canadian banners with match-confidence scoring and normalized unit prices.
- **[Loblaws Grocery Scraper](https://apify.com/sunny_eternity/loblaws-grocery-scraper)** — Real Canadian Superstore, No Frills, and Loblaws.
- **[Save-On-Foods & PriceSmart Grocery Scraper](https://apify.com/sunny_eternity/save-on-foods-pricesmart-scraper)** — Western Canada coverage.
- **[T\&T Supermarket Scraper](https://apify.com/sunny_eternity/tnt-grocery-scraper)** — Canada's largest Asian grocery chain.

### Who is this for?

- Developers building grocery and retail price comparison apps
- Retail analysts tracking Costco pricing and discounts across regions
- CPG brands monitoring how their products are priced at Costco
- Deal sites and price-alert tools that need Costco's current promotions
- Researchers studying bulk-retail pricing and food affordability
- Data teams building North American product databases

### Features

- **Whole catalog, or any slice of it** — 43 selectable departments, subcategories and curated lists (New Items, Treasure Hunt, Offers Ending Sunday), or `all` for everything.
- **Raw Costco links** — paste a product, category, or search URL and the actor works out what to do with it.
- **Location-aware pricing** — warehouse resolved from a postal code, with the province driving regional prices and assortment.
- **Discounts** — current price, original price, and Costco's promotional text with its validity window.
- **Derived unit pricing** — per 100 g / 100 ml / unit, computed from package sizes so you can compare across pack formats.
- **Canada and the US** — one actor, both storefronts.
- **No browser** — plain HTTP against Costco's own catalog API, so runs are fast and cheap.

### What data does the Costco scraper extract?

| Field | Description |
| --- | --- |
| `name`, `brand` | Product title and brand |
| `price`, `was_price`, `is_on_sale` | Current price, original price, discount flag |
| `multi_buy_deal`, `promotion_text`, `promotion_validity` | Costco's promotional text and its dates |
| `unit_price`, `comparable_unit_price` | Derived per-100g / per-100ml / per-unit pricing |
| `package_size`, `parsed_package_size`, `normalized_package_size` | Package size, parsed and normalized |
| `image_url`, `product_url` | Product image and page link |
| `product_id`, `item_number` | Catalog id and the warehouse item number from the shelf tag |
| `availability`, `member_only` | Stock status and membership restriction |
| `rating`, `rating_count` | Customer rating and review count |
| `location`, `location_name`, `location_postal_code`, `location_coordinates` | The warehouse the prices were resolved for |
| `store`, `currency`, `category` | Storefront, currency, and the category scraped |

### ⬇️ Input

| Field | Type | Description |
| --- | --- | --- |
| `site` | string | `CABC` (costco.ca, CAD) or `USBC` (costco.com, USD). Default `CABC`. |
| `categories` | array | Department, subcategory or curated-list slugs, or `all` for the entire catalog. |
| `startUrls` | array | Raw costco.ca / costco.com product, category or search URLs. |
| `search_terms` | array | Free-text queries. Combined with `categories`, they filter category results instead. |
| `postal_code` | string | Resolves the nearest warehouse and sets the pricing region. **Required** — see below. |
| `warehouseId` | string | Use a specific warehouse number. Requires `postal_code` too. |
| `shipToState` | string | Override the province/state code (`BC`, `ON`, `WA`, …). |
| `latitude`, `longitude` | string | Resolve the warehouse from coordinates. This is how you select a US warehouse. |
| `on_sale_only` | boolean | Keep only discounted products. |
| `max_items` | integer | Stop after N products. `0` means no limit. Default `1000`. |

#### A location is required

Costco's catalog API returns **zero results** when no postal code is supplied — it doesn't error, it just serves an empty catalog. The actor therefore fails fast rather than reporting an empty run. Supply one of:

- `postal_code` — Canadian postal codes are geocoded automatically (`site: "CABC"`).
- `latitude` + `longitude` — works for both countries, and is the supported way to pick a US warehouse.
- `warehouseId` **together with** `postal_code`.

#### Example inputs

Discounted grocery items only:

```json
{
  "site": "CABC",
  "categories": ["grocery-household"],
  "postal_code": "M5H 2N2",
  "on_sale_only": true
}
```

A single product from its URL:

```json
{
  "site": "CABC",
  "postal_code": "V6B 1V4",
  "startUrls": ["https://www.costco.ca/p/-/scotties-premium-facial-tissue-21-pack/4000376464"]
}
```

Costco US, warehouse resolved from coordinates:

```json
{
  "site": "USBC",
  "latitude": "47.6062",
  "longitude": "-122.3321",
  "search_terms": ["olive oil"]
}
```

The entire Costco Canada catalog (~11,000 products):

```json
{
  "site": "CABC",
  "categories": ["all"],
  "postal_code": "V6B 1V4",
  "max_items": 0
}
```

### ⬆️ Output

#### JSON output example

```json
{
  "store": "Costco",
  "currency": "CAD",
  "category": "grocery-household",
  "name": "Ruffles Potato Chips Variety Pack, 36 × 28 g",
  "brand": "Ruffles",
  "price": 17.49,
  "was_price": 20.99,
  "is_on_sale": true,
  "multi_buy_deal": "$3.50 OFF",
  "promotion_text": "$3.50 OFF",
  "promotion_validity": "Valid for orders placed 08/03/26 to 08/30/26.",
  "unit_price": "1008g, $1.74/100g",
  "comparable_unit_price": 1.74,
  "package_size": "1008g",
  "parsed_package_size": { "size": 1008, "unit": "g" },
  "normalized_package_size": { "size": 1008, "unit": "g" },
  "parsed_unit_price": { "value": 1.74, "quantity": 100, "unit": "g", "unit_type": "weight" },
  "selling_type": "by_weight",
  "image_url": "https://bfasset.costco-static.com/.../4160094-894__1?auto=webp&format=jpg",
  "product_url": "https://www.costco.ca/p/-/ruffles-potato-chips-variety-pack-36-x-28-g/4000363385",
  "product_id": "4000363385",
  "item_number": "4160094",
  "availability": "IN_STOCK",
  "member_only": false,
  "rating": 4.3,
  "rating_count": 128,
  "location": "552",
  "location_name": "Vancouver BC",
  "location_postal_code": "V6B 1V4",
  "location_coordinates": { "lat": 49.278, "lng": -123.11 }
}
```

### ❓ FAQ

#### Where does the unit price come from?

Costco publishes no unit price and no package-size field, so the actor derives both from the product title, which Costco consistently suffixes with the size (`", 1 kg"`, `"36 × 28 g"`, `"21-pack"`). Multipacks are collapsed to their total contents, so `36 × 28 g` becomes `1008g` and the unit price reflects the whole box.

When a title carries no parseable size — gift cards, furniture, apparel — `package_size` and `comparable_unit_price` come back `null` rather than a guess, because a wrong unit price silently corrupts comparisons.

#### Are sale prices included?

Yes. `price` is the live discounted price, `was_price` is the original, and `multi_buy_deal` / `promotion_text` carry Costco's own wording (`"$6 OFF"`). Use `on_sale_only: true` to keep only discounted items.

#### Does the scraper return warehouse-specific prices?

It returns prices for the region the warehouse sits in. Costco prices and assortment vary by province/state rather than by individual warehouse, so two warehouses in the same province generally return the same catalog.

#### Do I need a Costco membership?

No. The actor reads Costco's public catalog. No account, no membership, no login.

#### Is there an official Costco API?

Costco does not offer a public product or pricing API. This actor gives you structured, ready-to-use data without maintaining a scraper of your own.

#### Is it legal to scrape Costco?

Scraping publicly available product and price information is generally legal, but you are responsible for complying with Costco's terms of service and any applicable laws in your jurisdiction. Use the data responsibly and avoid excessive request volume.

#### How much does it cost to run?

The actor runs on Apify's pay-per-usage model. It makes plain HTTP calls with no browser, so runs are inexpensive; a few categories typically fit within Apify's free tier credits. A full-catalog run scales with the product count.

#### Can I integrate the scraper with other tools?

Yes — use Apify integrations to connect with Zapier, Make, Google Sheets, Airbyte, and more, or trigger runs via webhooks and the Apify API. Export as JSON, CSV, or Excel.

#### Can I schedule recurring scrapes?

Yes — use Apify's built-in scheduler to run the actor daily, weekly, or on any cron schedule, which is how you build a Costco price history.

### 🔧 Maintainer notes

#### Credentials

The actor calls Costco's catalog API with the request headers its own storefront sends. Those values are published in the page source of any costco.ca page. If Costco rotates them the actor will start returning `401`; re-read them by fetching a storefront page and searching the HTML for `catalog/search/api/v1/search`, then copy the adjacent `required_request_headers` block. Both values can be overridden without a code change:

| Variable | Default |
| --- | --- |
| `COSTCO_GRS_ENDPOINT` | `https://gdx-api.costco.com/catalog/search/api/v1/search` |
| `COSTCO_CLIENT_IDENTIFIER` | `168287ea-1201-45f6-9b45-5bbea49f8ee7` |

#### Using this module outside Apify

`src/costco-api.ts` is a plain `fetch` client with no Apify import, matching the other actors in this repository. Wiring Costco into the daily MongoDB scrape is therefore a matter of adding an adapter in `packages/scraper/src/api-handlers/actor-handlers.ts`, registering it in `registry.ts`, adding a `costco:` block to `packages/scraper/config.yml`, and registering a location handler with `supportsMultiLocation: true` so the orchestrator visits every configured warehouse.

### 📝 Your feedback

We're always working on improving the performance of our Actors. If you've got any technical feedback for the Costco Scraper or found a bug, please create an issue on the Actor's Issues tab.

# Actor input Schema

## `site` (type: `string`):

Which Costco storefront to scrape. Prices and assortment differ between them.

## `categories` (type: `array`):

Select departments (📁), specific subcategories (└), or curated lists (⭐). Selecting a department also scrapes everything nested beneath it, so there is no need to add its subcategories as well. Choose 'All Categories' for the entire catalog.

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

Paste raw costco.ca or costco.com links. Product pages (…/p/…/1234567) are fetched individually, category pages (…/grocery-household.html) are scraped in full, and search pages (…/s?keyword=olive+oil) run as searches. A bare category slug such as 'snacks' also works.

## `search_terms` (type: `array`):

Free-text queries such as 'olive oil' or 'organic eggs'. Each runs separately and its rows are tagged with category 'search:<term>'. When categories are also selected, these act as keyword filters on the category results instead.

## `postal_code` (type: `string`):

Resolves the nearest warehouse and sets the pricing region. Costco returns no results without one. Canadian postal codes are geocoded automatically; for the US site supply latitude/longitude, or a ZIP together with warehouseId.

## `warehouseId` (type: `string`):

Skip the warehouse lookup and use this warehouse number directly (e.g. '552' for Vancouver Expo Blvd). Requires postal\_code to be set as well.

## `shipToState` (type: `string`):

Override the province or state code (e.g. 'BC', 'ON', 'WA'). This is what drives regional pricing and assortment; by default it comes from the resolved warehouse.

## `latitude` (type: `string`):

Latitude to search for the nearest warehouse from, e.g. '47.6062'. Use together with longitude — this is the supported way to pick a US warehouse.

## `longitude` (type: `string`):

Longitude to search for the nearest warehouse from, e.g. '-122.3321'. Use together with latitude.

## `on_sale_only` (type: `boolean`):

Keep only products flagged as on sale — those with a struck-through original price, an active promotion, or a discount badge.

## `max_items` (type: `integer`):

Stop after this many products. Set to 0 for no limit — the full Costco Canada catalog is roughly 11,000 products.

## Actor input object example

```json
{
  "site": "CABC",
  "postal_code": "V6B 1V4",
  "on_sale_only": false,
  "max_items": 1000
}
```

# Actor output Schema

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

Complete dataset of scraped products including names, prices, discounts, images, item numbers, package sizes and derived unit pricing

# 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 = {
    "postal_code": "V6B 1V4"
};

// Run the Actor and wait for it to finish
const run = await client.actor("sunny_eternity/costco-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 = { "postal_code": "V6B 1V4" }

# Run the Actor and wait for it to finish
run = client.actor("sunny_eternity/costco-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 '{
  "postal_code": "V6B 1V4"
}' |
apify call sunny_eternity/costco-scraper --silent --output-dataset

```

## MCP server setup

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