# Shopify Store Scraper — Products, Prices & Inventory (`avant_technologies/shopify-store-scraper`) Actor

Extract full product catalogs from any Shopify store: titles, prices, variants, SKUs, inventory, images. Fast JSON-endpoint extraction with automatic fallback.

- **URL**: https://apify.com/avant\_technologies/shopify-store-scraper.md
- **Developed by:** [Rushi Patel](https://apify.com/avant_technologies) (community)
- **Categories:** E-commerce, Lead generation, Other
- **Stats:** 2 total users, 0 monthly users, 20.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.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/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 Scraper — Products, Prices & Inventory

Extract the full product catalog from any Shopify store — titles, prices, variants, SKUs, availability, images, tags, and more — with one clean dataset record per product, plus a per-store summary saved to the run's key-value store (so you're only charged for actual product records).

This is a fast, reliable **Shopify scraper** built for **product data extraction** at scale: point it at a store URL and get structured product data back. By default it uses Shopify's public JSON endpoints (no browser, no fuss), with an automatic multi-layer fallback so you keep getting data even when the easy path is closed.

***

### Sample output (real data)

Below is genuine data captured from live runs against `deathwishcoffee.com` and `mejuri.com`:

| Store | Title | Type | Price (min–max) | Currency | Variants | Images |
|---|---|---|---|---|---|---|
| Death Wish Coffee | Allfather's Aloha Button Up | Apparel | $40.00 | USD | 6 | 5 |
| Mejuri | (jewelry product) | Jewelry | $98–$398 | CAD | 1 | 5 |

One product record (trimmed):

```json
{
  "storeName": "Death Wish Coffee",
  "productId": 7492694540343,
  "title": "Allfather's Aloha Button Up",
  "vendor": "BAMKO",
  "productType": "Apparel",
  "priceMin": 40, "priceMax": 40, "currency": "USD",
  "tags": ["Apparel", "Men", "Merch"],
  "variants": [{"id": 42323014910007, "title": "S", "sku": "USHVJA02", "price": 40, "compareAtPrice": null, "available": false, "options": {"Size": "S"}}],
  "images": [{"src": "https://cdn.shopify.com/s/files/.../Front_Web2.jpg", "alt": null}],
  "url": "https://www.deathwishcoffee.com/products/allfathers-aloha-button-up-sold-out"
}
```

And the per-store summary (saved to the run's key-value store under `STORE_SUMMARIES`, so it isn't billed as a result):

```json
{"recordType":"store_summary","storeName":"Death Wish Coffee","productCount":291,"collectionCount":124,"priceRange":{"min":11.99,"max":40,"currency":"USD"},"currency":"USD","vendorList":["BAMKO"],"extractionPath":"products_json","status":"success"}
```

***

### Why this scraper — 3-layer reliability fallback

Most tools break the moment a store changes its configuration. When you **scrape a Shopify store** with this actor, it works down a chain of extraction strategies so you keep getting complete data:

1. **Primary — public `products.json` endpoint.** Fast, structured, page-based pagination, no browser required. This is the default path for most stores.
2. **Fallback — sitemap parsing.** If `products.json` is disabled, the actor parses `sitemap.xml` to discover product URLs, then extracts per-product JSON / JSON-LD.
3. **Last resort — opt-in headless browser (`useBrowser`).** For stores behind aggressive bot protection. This uses roughly 10x the compute and is **off by default** — you turn it on only when you need it.

Built to fail loudly, never silently:

- **Shopify detection first.** The actor confirms a URL is actually a Shopify store before doing anything else, and **fails fast with a clear, actionable message** if it isn't — it never silently returns garbage.
- **Password-protected / pre-launch stores are detected and reported**, so you always know why a store returned no products.
- **Transparent extraction path.** Every store's summary records exactly which path was used (`extractionPath`), so you can audit how each result was obtained.

#### Completeness

One record per product with the fields you actually need for **shopify price monitoring** and **ecommerce scraper** workflows: full variant breakdowns, SKUs, availability, compare-at pricing, images with alt text, tags, vendor, product type, and timestamps — plus a store-level summary for the whole catalog.

#### Transparent, per-result pricing

Flat **pay-per-result** pricing you can predict before you press Start. No monthly rental, no surprise platform-usage bills. See [Pricing](#pricing).

***

### Input

Fill in only `storeUrls` and you'll get the full catalog with sensible defaults.

| Field | Type | Default | Description |
|---|---|---|---|
| `storeUrls` | array of strings | — (**required**) | Shopify store root URLs, e.g. `https://www.allbirds.com` |
| `scope` | enum: `all_products` | `collections` | `single_products` | `all_products` | What to extract |
| `collectionHandles` | array | optional | Used with `scope=collections`; empty = all collections |
| `productUrls` | array | optional | Used with `scope=single_products` |
| `includeVariants` | boolean | `true` | Include per-variant data |
| `includeImages` | boolean | `true` | Include product images |
| `maxProductsPerStore` | integer | `0` (unlimited) | Cap products per store |
| `useBrowser` | boolean | `false` | Opt-in headless browser for stores behind aggressive bot protection (~10x compute) |
| `useResidentialProxy` | boolean | `false` | Route requests through residential proxy |

***

### Output

One dataset record per product. A per-store `store_summary` is saved to the run's key-value store (`STORE_SUMMARIES`) — **you're only charged for product records, not summaries.**

**Per-product record:**

`storeUrl`, `storeName`, `productId`, `handle`, `title`, `description` (plain text, HTML stripped), `vendor`, `productType`, `tags[]`, `createdAt`, `updatedAt`, `publishedAt`, `priceMin`, `priceMax`, `currency`, `totalInventory` (usually `null` — public endpoints rarely expose inventory), `variants[]` `{id, title, sku, price, compareAtPrice, available, inventoryQuantity, options}`, `images[]` `{src, alt}`, `url`, `scrapedAt`.

> Currency is reported **as-is and never converted**.

**Per-store summary** (key-value store, key `STORE_SUMMARIES`):

```json
{
  "recordType": "store_summary",
  "storeUrl": "...",
  "storeName": "...",
  "productCount": 291,
  "collectionCount": 124,
  "priceRange": { "min": 11.99, "max": 40, "currency": "USD" },
  "currency": "USD",
  "vendorList": ["BAMKO"],
  "extractionPath": "products_json",
  "status": "success",
  "scrapedAt": "..."
}
```

***

### Quickstart

1. Paste one or more store URLs into `storeUrls`.
2. Click **Start**.
3. Get one row per product; the per-store summary is in the run's key-value store.

Minimal input:

```json
{ "storeUrls": ["https://www.allbirds.com"] }
```

That's it — filling only `storeUrls` produces the full product catalog with defaults applied.

***

### Scheduling recipe — monitor competitor prices weekly

Turn this into a hands-off **shopify price monitoring** pipeline:

1. Add your competitors' store URLs to `storeUrls`.
2. Create an **Apify Schedule** that runs this actor every Monday.
3. Between runs, diff `priceMin` / `priceMax` per `productId` to catch price changes.

Wire it into your stack with **Apify Schedules + integrations** — for example, a webhook that pushes changes to **Slack** or appends new rows to **Google Sheets** — so price movements land where your team already works.

***

### Pricing

**Pay-per-result: $2.50 per 1,000 products.**

Transparent, flat, and predictable — no monthly rental and no surprise platform-usage bills. You know your cost before you run.

The value here is **reliability + predictable pricing**: the 3-layer fallback keeps results flowing, and the per-result model means you pay for products, not for platform time. (Browser mode is more compute-intensive and is **opt-in** — it's off unless you enable `useBrowser`.)

***

### FAQ

**"It says my store isn't Shopify."**
The actor detects whether a URL is actually a Shopify store before extracting, and fails fast with a clear message if it can't confirm one. If you're certain the site is Shopify but it's behind bot protection, enable `useResidentialProxy` and/or `useBrowser` and try again.

**What happens with password-protected or pre-launch stores?**
They're detected and reported in the store summary. You'll get a clear status explaining why no products were returned, rather than an empty result with no explanation.

**Why is `totalInventory` (and often `inventoryQuantity`) null?**
Public Shopify endpoints rarely expose inventory figures, so these fields are usually `null`. This reflects what the store makes publicly available.

**How is non-USD currency handled?**
Currency is reported exactly as the store lists it (e.g. `CAD` for Mejuri) and is **never converted**. Handle any conversion downstream if you need a single currency.

**Can it handle very large stores?**
Yes. Results are streamed per page as they're extracted. Use `maxProductsPerStore` to cap how many products you pull from each store when you don't need the whole catalog.

**Can I scrape a specific collection?**
Yes. Set `scope=collections` and list the collection handles in `collectionHandles`. Leave `collectionHandles` empty to scrape all collections.

**How do pagination and de-duplication work?**
The primary path uses page-based pagination against `products.json`. Products are **de-duplicated by `productId` per store**, so you get one clean record per product even across paginated pages.

**Do I need to enable the browser?**
No — the browser is opt-in. Most stores are handled by the fast public-JSON and sitemap paths. Only enable `useBrowser` for stores behind aggressive bot protection, and expect roughly 10x the compute cost when you do.

***

#### Keywords

Shopify scraper · Shopify product scraper · scrape Shopify store · Shopify price monitoring · ecommerce scraper · product data extraction.

# Actor input Schema

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

Shopify store root URLs, e.g. https://www.allbirds.com. One record is produced per product, plus a summary per store.

## `scope` (type: `string`):

What to scrape from each store.

## `collectionHandles` (type: `array`):

Only with scope=collections. Collection handles (the slug in /collections/{handle}). Leave empty to scrape every collection.

## `productUrls` (type: `array`):

Only with scope=single\_products. Full product page URLs, e.g. https://store.com/products/some-handle.

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

Include the full variants array (id, sku, price, compareAtPrice, availability, options) on each product.

## `includeImages` (type: `boolean`):

Include the images array (src + alt) on each product.

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

Cap the number of products per store. 0 = unlimited.

## `useBrowser` (type: `boolean`):

Enable the headless-browser fallback for stores behind aggressive bot protection. ~10x the compute cost — leave off unless a store fails without it.

## `useResidentialProxy` (type: `boolean`):

Route requests through Apify residential proxy. Helps with stores that block datacenter IPs.

## Actor input object example

```json
{
  "storeUrls": [
    "https://www.allbirds.com",
    "https://www.mejuri.com"
  ],
  "scope": "all_products",
  "collectionHandles": [
    "mens",
    "sale"
  ],
  "productUrls": [
    "https://www.allbirds.com/products/mens-wool-runners"
  ],
  "includeVariants": true,
  "includeImages": true,
  "maxProductsPerStore": 0,
  "useBrowser": false,
  "useResidentialProxy": false
}
```

# Actor output Schema

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

One dataset record per product. A per-store summary is in the run's key-value store (STORE\_SUMMARIES).

# 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.deathwishcoffee.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("avant_technologies/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 = { "storeUrls": ["https://www.deathwishcoffee.com"] }

# Run the Actor and wait for it to finish
run = client.actor("avant_technologies/shopify-store-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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.deathwishcoffee.com"
  ]
}' |
apify call avant_technologies/shopify-store-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=avant_technologies/shopify-store-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/KUm7oLCihAvD0Zd57/builds/g1knhstzUx2T01bZa/openapi.json
