# Shopify Store Scraper: Products, Collections & Store Info (`barefoot_grade/shopify-store-scraper`) Actor

Collect products from any public Shopify store: title, vendor, type, tags, every variant with price, compare-at price, SKU and availability, images and dates. Add collections, store details and public stock counts. Stores that fail are reported and not charged.

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

## Pricing

from $0.50 / 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/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

## Shopify Store Scraper: Products, Collections & Store Info

Turn any Shopify store into a clean product spreadsheet. Paste a store's domain and get every product with its title, vendor, product type, tags, description and dates, every variant with its price, compare-at price, SKU and availability, and every image. Add the store's collections and a store profile (name, currency, location, shipping countries, product and collection counts) with one switch each, and public stock counts where the store shows them.

Give it whole stores, single collections or single product links, as many as you like. Paging is automatic and every run has a per-store and a total cap. Stores that are not on Shopify, are password-protected or do not publish their catalogue are listed in the run summary with a clear reason and are not charged.

### Use cases

- **Competitor price monitoring**: re-run a competitor's catalogue on a schedule and compare prices, discounts and availability over time.
- **Product research**: see what a brand sells, how it prices variants and what goes on sale.
- **Catalogue export**: copy a store's products, variants and images into a spreadsheet, a database or another shop.
- **Stock watching**: follow sold-out variants and public stock counts for products you care about.
- **Market mapping**: profile many Shopify brands at once by currency, location, shipping countries and catalogue size.

### Quick Start

```json
{
  "stores": ["https://www.allbirds.com", "https://colourpop.com"],
  "maxProductsPerStore": 100,
  "includeStoreInfo": true,
  "includeCollections": false
}
```

A store domain collects the whole catalogue (up to your cap). A collection link such as `https://kith.com/collections/mens-footwear` collects only that collection, and a product link such as `https://colourpop.com/products/magical-skies-shadow-palette-and-brush-set` collects one product.

### Input

| Input | Type | Default | Meaning |
| --- | --- | --- | --- |
| `stores` | array | required | Shopify store domains or links, one per line: a store, a collection link (`/collections/...`) or a product link (`/products/...`). Repeated links are read once. |
| `maxProductsPerStore` | integer | `100` | Cap on product rows from each store, across all of its links, up to 25,000. Use `0` to collect only store details or collections. |
| `maxItems` | integer | `1000` | Total cap on rows (products, collections and stores) for the whole run, up to 200,000. |
| `includeStoreInfo` | boolean | `true` | Add one row per store with its name, currency, location, shipping countries and product and collection counts. |
| `includeCollections` | boolean | `false` | Add one row per collection with its title, description, image and product count. |
| `maxCollectionsPerStore` | integer | `250` | Cap on collection rows from each store. |
| `includeInventory` | boolean | `false` | Add per-variant stock quantities where the store shows them. This reads one extra page per product, so runs take longer. |

### Example queries

- `{"stores": ["kith.com"], "maxProductsPerStore": 2000}`: a large catalogue.
- `{"stores": ["https://kith.com/collections/mens-footwear"], "maxProductsPerStore": 500}`: one collection only.
- `{"stores": ["colourpop.com", "allbirds.com", "gymshark.com"], "maxProductsPerStore": 0, "includeCollections": true}`: store profiles and collections, no products.
- `{"stores": ["https://colourpop.com/products/magical-skies-shadow-palette-and-brush-set"], "includeInventory": true}`: one product with stock counts.

### What it returns

Every row has a `recordType`: `product`, `collection` or `store`.

**Product rows**

| Field | Meaning |
| --- | --- |
| `id`, `handle`, `url`, `title` | Product identity and its link on the store. |
| `vendor`, `productType`, `tags` | Brand, product type and the store's tags. |
| `description`, `descriptionHtml` | Description as plain text and as the store's original HTML. |
| `price`, `priceMax`, `currency` | Lowest and highest variant price, in the store's currency. |
| `compareAtPrice`, `onSale` | The original price when a variant is marked down, and whether any variant is. |
| `available` | True when at least one variant can be bought. |
| `totalInventory` | Sum of public variant stock counts, when `includeInventory` is on and the store shows them. |
| `variants`, `variantCount` | Each variant's `id`, `title`, `sku`, `price`, `compareAtPrice`, `available`, `inventoryQuantity`, `options`, `weightGrams`, `requiresShipping`, `taxable` and `imageUrl`. |
| `options` | Option names and values, such as Size or Color. |
| `images`, `imageUrl` | Every image with its size and alt text, plus the main image. |
| `collectionHandle` | The collection the product came from, for collection links. |
| `createdAt`, `updatedAt`, `publishedAt` | Dates as published by the store. |

**Collection rows** carry `id`, `handle`, `url`, `title`, `description`, `productsCount`, `imageUrl`, `publishedAt` and `updatedAt`.

**Store rows** carry `storeName`, `url`, `description`, `myshopifyDomain`, `currency`, `country`, `province`, `city`, `shipsToCountries`, `productsCount` and `collectionsCount`.

Every row also has `storeDomain`, `storeName` and `scrapedAt` (collection time, UTC). The run summary (`OUTPUT`) reports `products`, `collections`, `stores`, `storesRequested`, `storesSucceeded`, `errors` and the list at `storeErrors`, each with the link and a reason code such as `NOT_SHOPIFY`, `STORE_LOCKED`, `CATALOGUE_NOT_PUBLIC`, `PRODUCT_NOT_FOUND` or `COLLECTION_NOT_FOUND`.

### Output example

```json
{
  "recordType": "product",
  "storeDomain": "www.allbirds.com",
  "storeName": "Allbirds",
  "id": 7340901859408,
  "handle": "womens-allbirds-flip-flop-dusty-pink",
  "url": "https://www.allbirds.com/products/womens-allbirds-flip-flop-dusty-pink",
  "title": "Women's Allbirds Flip Flop - Dusty Pink",
  "vendor": "Allbirds",
  "productType": "Shoes",
  "tags": [
    "allbirds::gender => womens",
    "allbirds::material => sugar",
    "OOS DNS",
    "shoprunner"
  ],
  "description": "Sun on your feet. Comfort underneath. Light, easy, and made for warm weather, these flip flops bring everyday comfort to sunny days, beach walks, and everything in between. Just slip them on and go.",
  "descriptionHtml": null,
  "currency": "USD",
  "price": 25.0,
  "priceMax": 25.0,
  "compareAtPrice": 50.0,
  "onSale": true,
  "available": true,
  "totalInventory": null,
  "variantCount": 7,
  "variants": [
    {
      "id": 42146889105488,
      "title": "7",
      "sku": "A12513W070",
      "price": 25.0,
      "compareAtPrice": 50.0,
      "available": false,
      "inventoryQuantity": null,
      "options": [
        "7"
      ],
      "weightGrams": 503,
      "requiresShipping": true,
      "taxable": true,
      "imageUrl": null
    },
    {
      "id": 42146889138256,
      "title": "8",
      "sku": "A12513W080",
      "price": 25.0,
      "compareAtPrice": 50.0,
      "available": false,
      "inventoryQuantity": null,
      "options": [
        "8"
      ],
      "weightGrams": 516,
      "requiresShipping": true,
      "taxable": true,
      "imageUrl": null
    }
  ],
  "options": [
    {
      "name": "Size",
      "values": [
        "5",
        "6",
        "7",
        "8",
        "9"
      ]
    }
  ],
  "images": [
    {
      "url": "https://cdn.shopify.com/s/files/1/1104/4168/files/A12513_26Q2_Allbirds-Flip-Flop-Dusty-Pink_PDP_LEFT.png?v=1774646345",
      "alt": null,
      "width": 4000,
      "height": 4000
    }
  ],
  "imageUrl": "https://cdn.shopify.com/s/files/1/1104/4168/files/A12513_26Q2_Allbirds-Flip-Flop-Dusty-Pink_PDP_LEFT.png?v=1774646345",
  "collectionHandle": null,
  "createdAt": "2026-03-27T14:03:50-07:00",
  "updatedAt": "2026-10-19T17:49:09-07:00",
  "publishedAt": "2026-09-25T16:58:13-07:00",
  "scrapedAt": "2026-10-20T00:55:12Z"
}
```

```json
{
  "recordType": "collection",
  "storeDomain": "www.allbirds.com",
  "storeName": "Allbirds",
  "id": 270995030096,
  "handle": "30-off-tree-runner-go-tree-gliders",
  "url": "https://www.allbirds.com/collections/30-off-tree-runner-go-tree-gliders",
  "title": "30% Off Tree Runner Go & Tree Gliders",
  "description": null,
  "productsCount": 107,
  "imageUrl": null,
  "publishedAt": "2024-09-07T20:37:09-07:00",
  "updatedAt": "2026-10-19T04:02:25-07:00",
  "scrapedAt": "2026-10-20T00:55:12Z"
}
```

```json
{
  "recordType": "store",
  "storeDomain": "www.allbirds.com",
  "storeName": "Allbirds",
  "url": "https://www.allbirds.com",
  "description": "The world’s most comfortable shoes, made with natural materials like merino wool, eucalyptus tree fiber, and sugar cane, Allbirds has created the comfiest shoes on the planet.",
  "myshopifyDomain": "weareallbirds.myshopify.com",
  "currency": "USD",
  "country": "US",
  "province": "California",
  "city": "Beverly Hills",
  "shipsToCountries": [
    "US"
  ],
  "productsCount": 692,
  "collectionsCount": 1346,
  "scrapedAt": "2026-10-20T00:55:12Z"
}
```

### Price

**$0.0005 per result** delivered (one product, collection or store row), plus **$0.005 per run start**. The run-start event is charged per GB of memory; the default 512 MB run is one start event. The start is charged even if the run saves no results. Stores and links that fail are not charged. Platform usage is included in these prices.

### Good to know

- Works with stores built on Shopify's standard online store, which is most Shopify shops. Some large brands run their own custom storefront on top of Shopify and do not publish their catalogue; those are reported as `CATALOGUE_NOT_PUBLIC` and are not charged.
- A store returns at most 25,000 products per run, across all of its links; products found twice are delivered once.
- Prices are the store's own prices in its main currency, as a signed-out visitor sees them. Stores that sell in several countries may show other prices to local visitors.
- Stock counts are shown only by stores that publish them; elsewhere `inventoryQuantity` stays empty and `available` still tells you whether a variant can be bought.
- Password-protected stores (`STORE_LOCKED`) and sites that are not Shopify stores (`NOT_SHOPIFY`) are listed in the run summary. If no store at all returns data, the run fails with a clear message.
- The scraper reads one store at a time at a gentle pace. A 1,000-product store usually takes well under a minute; with stock counts on, allow about half a second per product.

# Actor input Schema

## `stores` (type: `array`):

Shopify store domains or links, one per line: a store (allbirds.com) collects its whole catalogue, a collection link (/collections/...) collects that collection, and a product link (/products/...) collects one product.

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

Cap on product rows from each store, across its links. Use 0 to skip products and collect only store details or collections.

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

Total cap on rows (products, collections and stores) for the whole run.

## `includeStoreInfo` (type: `boolean`):

Add one row per store with its name, currency, location, shipping countries and product and collection counts.

## `includeCollections` (type: `boolean`):

Add one row per collection with its title, description, image and product count.

## `maxCollectionsPerStore` (type: `integer`):

Cap on collection rows from each store when collections are included.

## `includeInventory` (type: `boolean`):

Add per-variant stock quantities where the store shows them. This reads one extra page per product, so runs take longer.

## Actor input object example

```json
{
  "stores": [
    "https://www.allbirds.com",
    "https://colourpop.com"
  ],
  "maxProductsPerStore": 100,
  "maxItems": 1000,
  "includeStoreInfo": true,
  "includeCollections": false,
  "maxCollectionsPerStore": 250,
  "includeInventory": false
}
```

# Actor output Schema

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

No description

## `summary` (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 = {
    "stores": [
        "https://www.allbirds.com",
        "https://colourpop.com"
    ],
    "maxProductsPerStore": 100,
    "maxItems": 1000
};

// Run the Actor and wait for it to finish
const run = await client.actor("barefoot_grade/shopify-store-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 = {
    "stores": [
        "https://www.allbirds.com",
        "https://colourpop.com",
    ],
    "maxProductsPerStore": 100,
    "maxItems": 1000,
}

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

```

## MCP server setup

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