# Shopify Store Catalog Scraper (`cirkit/shopify-store-catalog-scraper`) Actor

Scrape the full public product catalog of any Shopify store. Returns product id, handle, title, URL, vendor, type, tags, images, price, sale and stock status, plus the complete variant list with SKUs. Handles headless Hydrogen storefronts automatically.

- **URL**: https://apify.com/cirkit/shopify-store-catalog-scraper.md
- **Developed by:** [Crikit](https://apify.com/cirkit) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 87.5% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.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

## Shopify Store Catalog Scraper

Scrape the complete public product catalog of any Shopify store. Give the actor one or more store domains and it returns every product with pricing, images, stock status, and the full variant list including SKUs.

This Shopify scraper reads the store's own public catalog data directly. There is no headless browser, no login, and no cookies, so it is fast and cheap: a 25,000 product catalog takes about two and a half minutes.

### What makes this Shopify scraper different

Most Shopify product scrapers stop at product level and tell you a product has 13 variants. This one gives you the 13 variants: variant id, title, SKU, price, compare-at price, per-variant stock status, and the option values behind them.

That matters if you are doing price monitoring, inventory tracking, or catalog sync, because the thing that changes is almost never the product, it is the size that went out of stock or the colour that went on sale.

- **Full variant data with SKUs.** Every variant, every SKU. The leading competing actors return a variant count and no SKUs at all.
- **Real store currency.** Read from the store rather than assumed to be USD. A Canadian store reports CAD.
- **Headless storefronts supported.** Stores built on Shopify Hydrogen and Oxygen do not serve their catalog on the public domain. This actor finds the underlying store origin and scrapes it anyway.
- **You are never billed twice for the same product.** Pagination stops on repeated product ids, not on a page count, so a misbehaving store cannot generate duplicate billable rows.
- **Honest failures.** A store that has switched its catalog off is reported with the reason, per store, instead of silently returning nothing.

### Input

| Field | Type | Description |
|---|---|---|
| `storeUrls` | array | Required. Store domains. Accepts `gymshark.com`, `https://gymshark.com`, or `mystore.myshopify.com`. |
| `collection` | string | Optional. Scrape one collection only. Use the handle from the URL, for example `mens-tops`. |
| `maxProductsPerStore` | integer | Cap per store. `0` means the entire catalog. |
| `includeVariants` | boolean | Include the full variant list. Default `true`. |
| `includeDescription` | boolean | Include the product description as plain text. Default `true`. |
| `proxyConfiguration` | object | Proxy settings. The default Apify datacenter proxy is sufficient. |

```json
{
    "storeUrls": ["https://gymshark.com", "allbirds.com"],
    "maxProductsPerStore": 500,
    "includeVariants": true
}
```

### Output

One row per product. Variants are nested inside the row rather than flattened, so a 13 variant product is one row and one charge, not 13.

```json
{
    "store": "allbirds.com",
    "storeName": "Allbirds",
    "productId": 7292464955472,
    "handle": "mens-cruiser-shadow-blue-natural-white-sole",
    "title": "Men's Cruiser - Shadow Blue (Natural White Sole)",
    "url": "https://allbirds.com/products/mens-cruiser-shadow-blue-natural-white-sole",
    "vendor": "Allbirds",
    "productType": "Shoes",
    "currency": "USD",
    "priceMin": 105,
    "priceMax": 105,
    "compareAtPrice": null,
    "onSale": false,
    "discountPercent": null,
    "available": true,
    "variantCount": 13,
    "availableVariantCount": 11,
    "skus": ["A12856M080", "A12856M085"],
    "variants": [
        {
            "variantId": 41990816759888,
            "title": "8",
            "sku": "A12856M080",
            "price": 105,
            "compareAtPrice": null,
            "available": true,
            "option1": "8",
            "grams": 1000
        }
    ],
    "featuredImage": "https://cdn.shopify.com/s/files/1/1104/4168/files/All-birds_0010.png",
    "imageCount": 5,
    "updatedAt": "2026-08-07T09:14:02-07:00"
}
```

Full field list, types, and the Console table view are declared in the dataset schema.

### Common uses

- **Competitor price monitoring.** Run on a schedule and diff `priceMin`, `compareAtPrice`, and `discountPercent` between runs.
- **Inventory and stockout tracking.** `availableVariantCount` against `variantCount` shows which sizes or colours are selling out.
- **Catalog sync and migration.** `productId` and `handle` are stable keys for joining against your own data.
- **Dropshipping and product research.** Sort a whole catalog by price, vendor, or product type.
- **Brand and MAP monitoring.** Track SKU level pricing across many stores in one run.

### Limits worth knowing

- Shopify serves at most 100 pages of 250 products, so a single catalog listing tops out at **25,000 products**. For larger stores, run again with a `collection` handle to scrape collections one at a time.
- A small number of merchants switch the public catalog endpoint off. Those stores are reported with the reason rather than returned as empty.
- Only publicly published products are returned. Draft and unpublished products are not exposed by the store and cannot be scraped.

### Pricing

Pay per result: **$0.001 per product**, which is **$1.00 per 1,000 products**. You are charged once per unique product row, with its variants included at no extra cost. Stores that return nothing are not charged.

### Data and compliance

This Shopify scraper reads only data the store publishes publicly to any visitor. It collects no personal data, no customer records, and no order information. You are responsible for how you use the data, including complying with the target store's terms and applicable law.

# Actor input Schema

## `storeUrls` (type: `array`):

One or more Shopify stores to scrape, one per line. Accepts a bare hostname (gymshark.com), a full URL (https://gymshark.com), or a Shopify subdomain (mystore.myshopify.com). Any path is ignored, so https://gymshark.com/collections/all is treated as gymshark.com. Each store is scraped independently and every row carries the store it came from.

## `collection` (type: `string`):

Scrape only one collection instead of the whole catalog. Use the handle from the collection URL: for https://gymshark.com/collections/mens-tops enter mens-tops. The same handle is applied to every store in the run. Leave empty to scrape the full catalog.

## `maxProductsPerStore` (type: `integer`):

Cap the number of products returned for each store independently. Scraping 3 stores with a cap of 100 returns up to 300 rows. Products are fetched in pages of 250, which is the maximum Shopify allows per request. Set to 0 for the entire public catalog.

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

Include the full variant list on each product, with variant id, title, SKU, price, compare-at price, per-variant stock status and options. Turn off for a smaller, flatter dataset when you only need product-level pricing.

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

Include the product description as plain text, converted from the store's HTML. Turn off to reduce dataset size noticeably on stores with long descriptions.

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

Proxy used for requests. The default Apify datacenter proxy is sufficient for this actor, since the Shopify catalog endpoint applies no bot protection. Residential proxies are not required and will only add cost.

## Actor input object example

```json
{
  "storeUrls": [
    "https://gymshark.com"
  ],
  "collection": "mens-tops",
  "maxProductsPerStore": 100,
  "includeVariants": true,
  "includeDescription": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Every product in the scraped Shopify catalog, one row per product with its variants nested.

## `resultsCsv` (type: `string`):

The same products as a downloadable CSV file.

# 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 = {
    "storeUrls": [
        "https://gymshark.com"
    ],
    "maxProductsPerStore": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("cirkit/shopify-store-catalog-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 = {
    "storeUrls": ["https://gymshark.com"],
    "maxProductsPerStore": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("cirkit/shopify-store-catalog-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 '{
  "storeUrls": [
    "https://gymshark.com"
  ],
  "maxProductsPerStore": 100
}' |
apify call cirkit/shopify-store-catalog-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,cirkit/shopify-store-catalog-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/rA0BNq8sCuQZRhcOj/builds/sKkmlCdgCx0FK5SdF/openapi.json
