# Shopify Store Scraper (`aurenic/shopify-scraper`) Actor

Extract products, variants, prices, inventory, images, and collections from any Shopify store via the public /products.json and /collections.json endpoints. No API key, no login, no browser.

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

## Pricing

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

Extract products, variants, prices, inventory, images, and collections from any Shopify store via the public `/products.json` and `/collections.json` endpoints. No API key, no login, no browser.

### What does Shopify Store Scraper do?

Scrape any of the **4.2 million+ Shopify stores** in one actor:

- **Products** — full catalog with title, handle, vendor, product type, tags, price range, compare-at price, calculated discount, availability, and every variant with SKU, barcode, price, weight, and options.
- **Variants** — full variant array per product (sizes, colors, materials).
- **Collections** — all collections with handle, title, description, image, and product count.
- **Store metadata** — store name, description, country, currency, myshopify domain.
- **Optional per-collection filtering** — restrict product scraping to specific collections (e.g. `sale`, `best-sellers`).

Every Shopify store exposes its catalog at the public canonical endpoint `/products.json` — the same endpoint that powers Shopify's own product pickers, search APIs, and feed-export integrations. **No anti-bot, no browser, no proxy needed.**

### Output fields

#### Product

| Field | Description |
|---|---|
| storeHost / storeOrigin | Store domain |
| productId | Shopify product ID |
| title | Product title |
| handle | URL-safe slug |
| url | Direct product page URL |
| vendor | Brand / vendor |
| productType | Shopify product type |
| tags | Comma-separated tags |
| bodyHtml | HTML-stripped description (when `includeProductDetails: true`) |
| publishedAt / createdAt / updatedAt | Timestamps |
| priceMin / priceMax | Variant price range |
| compareAtPriceMin | Lowest compare-at price |
| discountPercent | Calculated discount percentage |
| available | True if any variant is in stock |
| variantCount | Number of variants |
| variants | Full variant array with SKU, barcode, price, weight, options |
| imageCount / featuredImage / images | Image metadata and URLs |
| options | Product options (Size, Color, Material) |

#### Collection

| Field | Description |
|---|---|
| collectionId | Shopify collection ID |
| title / handle / url | Collection identity |
| description | HTML-stripped description |
| productsCount | Number of products in the collection |
| imageUrl | Collection image |
| sortOrder | Manual / best-selling / price-asc / price-desc |

#### Store metadata

| Field | Description |
|---|---|
| shopId | Shopify shop ID |
| name / description | Store name and description |
| primaryDomain / myshopifyDomain | Store domains |
| country / currency | Locale |
| moneyFormat | Currency display format |

#### Diagnostic

Emitted once per store when a domain is not a Shopify store or has `/products.json` disabled. Not charged.

### Who is it for?

- **Dropshippers and product researchers** scanning winning products across thousands of stores
- **Price intelligence teams** monitoring competitor catalogs and discount rates
- **E-commerce aggregators** building multi-store product feeds
- **Brand and MAP monitoring** teams enforcing minimum advertised price
- **D2C analytics** teams detecting Shopify stores in a sales pipeline
- **Recommendation engine builders** training on structured ecommerce data

### Pricing

**$0.90 per 1,000 results.** No subscription.

| Results | Cost |
|---|---|
| 100 | $0.09 |
| 1,000 | $0.90 |
| 10,000 | $9.00 |

### How to use it

1. Paste one or more **Shopify Store URLs** (bare domains or full URLs).
2. Optionally restrict to specific **Collection Handles**.
3. Toggle **Store Metadata**, **Collections**, and **Product Descriptions**.
4. Set **Max Products per Store** (default 1000) and **Max Requests per Second** (default 2).
5. Click **Start**.

### Output example

```json
{
  "recordType": "product",
  "storeOrigin": "https://www.allbirds.com",
  "storeHost": "www.allbirds.com",
  "productId": 4521803710580,
  "title": "Men's Wool Runner Go",
  "handle": "mens-wool-runner-go",
  "url": "https://www.allbirds.com/products/mens-wool-runner-go",
  "vendor": "Allbirds",
  "productType": "Shoes",
  "tags": ["men", "sneakers", "wool"],
  "bodyHtml": "Our lightest everyday sneaker, made with ZQ Merino wool...",
  "publishedAt": "2024-08-12T14:23:00-07:00",
  "priceMin": 100.0,
  "priceMax": 100.0,
  "compareAtPriceMin": 120.0,
  "discountPercent": 16.7,
  "available": true,
  "variantCount": 9,
  "variants": [
    {
      "id": 41234567890123,
      "title": "8 / Natural Black",
      "sku": "A10543-080",
      "price": 100.0,
      "compareAtPrice": 120.0,
      "available": true,
      "grams": 320,
      "weight": 0.32,
      "weightUnit": "kg",
      "barcode": "810010000000",
      "option1": "8",
      "option2": "Natural Black",
      "option3": null,
      "position": 1
    }
  ],
  "imageCount": 6,
  "featuredImage": "https://cdn.shopify.com/s/files/1/0044/4360/7925/products/...",
  "images": ["https://cdn.shopify.com/..."],
  "options": [
    { "name": "Size", "position": 1, "values": ["8", "9", "10", "11"] },
    { "name": "Color", "position": 2, "values": ["Natural Black", "Natural White"] }
  ],
  "scrapedAt": "2026-09-21T12:00:00.000Z"
}
```

### Technical details

- **No API key, no login, no browser.** Uses Shopify's canonical public endpoints.
- **Endpoints used:** `/products.json`, `/collections.json`, `/meta.json`, and `/collections/{handle}/products.json`.
- **Pagination:** 250 products per page, up to 200 pages per store.
- **Per-host rate limit:** 2 requests/second by default (Shopify throttles aggressive crawlers above ~40 req/min per IP).
- **Multi-store:** pass up to dozens of stores in one run.
- **Graceful diagnostics:** non-Shopify domains or stores with `/products.json` disabled emit a single diagnostic record and are not charged.
- **No proxy required.** Datacenter IPs work on 99% of stores.

### Known limits

- **Only published products** appear in `/products.json`. Draft and unpublished products are not exposed.
- **Inventory quantity is not in the public feed.** Per-variant stock is reported as the boolean `available`.
- **Some stores disable `/products.json`.** Those return a diagnostic record with `errorCode: NOT_SHOPIFY_OR_DISABLED`.
- **Price is a string in Shopify's feed.** The actor parses it to a number (`priceMin`, `priceMax`, per-variant `price`).
- **`body_html` is truncated at 5,000 characters** after HTML stripping.

### FAQ

**Do I need a Shopify API key?** No. The `/products.json` endpoint is public by design — it's the same endpoint Shopify uses for product pickers and feed exports.

**Do I need a proxy?** No. Datacenter IPs work on almost every store. Enable proxy only if a specific store blocks you.

**Why did my store return a diagnostic record?** Either the domain isn't Shopify, or the store disabled `/products.json`. The `errorCode` field tells you which.

**How many products can I get per store?** Up to 50,000 (200 pages × 250 per page). For larger catalogs, run multiple times with `maxProductsPerStore` and dedupe by `productId`.

**Can I scrape reviews too?** Not in this version. Review platforms (Judge.me, Yotpo, Okendo) each require their own endpoint — planned for a follow-up.

**How do I export data?** After a run, go to Storage → Export as JSON, CSV, Excel.

### Support

Open an issue on the Actor's page for bugs or feature requests.

# Actor input Schema

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

One or more Shopify store URLs or bare domains (e.g. allbirds.com, https://www.gymshark.com). Duplicates and paths are stripped automatically.

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

Optional. Restrict product scraping to specific collection handles (e.g. sale, best-sellers). Leave empty to scrape the entire catalog.

## `includeMeta` (type: `boolean`):

Fetch /meta.json — store name, description, country, currency, myshopify domain.

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

Fetch /collections.json — all collection handles, titles, descriptions, and product counts.

## `includeProductDetails` (type: `boolean`):

Attach stripped plain-text body\_html to each product record.

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

Hard cap on products per store.

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

Hard cap on collections per store.

## `maxRequestsPerSecond` (type: `integer`):

Per-store request rate limit. Shopify's public JSON endpoints throttle above ~2 req/sec per IP. Lower this if you see 429s.

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

Reserved — cross-store concurrency is scheduled sequentially per host in this version.

## `useProxy` (type: `boolean`):

The public JSON endpoint has no anti-bot protection. Enable only if a specific store blocks your IP.

## Actor input object example

```json
{
  "storeUrls": [
    "https://www.allbirds.com",
    "https://www.gymshark.com"
  ],
  "collections": [],
  "includeMeta": true,
  "includeCollections": true,
  "includeProductDetails": true,
  "maxProductsPerStore": 1000,
  "maxCollectionsPerStore": 200,
  "maxRequestsPerSecond": 2,
  "maxConcurrency": 4,
  "useProxy": false
}
```

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

// Run the Actor and wait for it to finish
const run = await client.actor("aurenic/shopify-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://www.allbirds.com",
        "https://www.gymshark.com",
    ],
    "collections": [],
}

# Run the Actor and wait for it to finish
run = client.actor("aurenic/shopify-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://www.allbirds.com",
    "https://www.gymshark.com"
  ],
  "collections": []
}' |
apify call aurenic/shopify-scraper --silent --output-dataset

```

## MCP server setup

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