# Shopify Store Products Scraper - Full Catalog Export (`scrapers_lat/shopify-store-products-scraper`) Actor

Export any Shopify store's full product catalog: titles, variants, SKUs, prices, compare-at prices, stock, images, tags. Multi-store batch, collection filter, one-row-per-variant. JSON, CSV, Excel.

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

## Pricing

from $8.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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 Products Scraper - Full Catalog Export](https://scrapers.lat/banners/shopify-store-products-scraper.png)](https://apify.com/scrapers_lat/shopify-store-products-scraper)

## Shopify Store Products Scraper - Full Catalog Export

Here is one real result, with the fields the actor returns (one row per product):

```json
{
  "storeDomain": "gymshark.com",
  "productId": 6806612050122,
  "title": "Gymshark Cosy Campus Polo Sweatshirt - Bros Chalk Marl",
  "handle": "gymshark-cosy-campus-polo-sweatshirt-pullovers-brown-aw26",
  "vendor": "Gymshark | Be a visionary.",
  "productType": "Womens>Apparel>Pullovers>crew",
  "tags": ["13/08/26", "activity:Rest Day", "airport-outfits"],
  "createdAt": "2026-02-12T14:14:35-08:00",
  "updatedAt": "2026-08-16T05:22:55-07:00",
  "publishedAt": "2026-08-13T08:07:02-07:00",
  "url": "https://gymshark.com/products/gymshark-cosy-campus-polo-sweatshirt-pullovers-brown-aw26",
  "imageCount": 6,
  "featuredImage": "https://cdn.shopify.com/s/files/1/0156/6146/files/CosyLuxeCampusEditCollaredSweatshirtBROSChalkMarlB7B5R_NDLF_0174.jpg?v=1785830091",
  "variantCount": 7,
  "minPrice": 60,
  "maxPrice": 60,
  "priceRange": "60",
  "currency": null,
  "inStock": true,
  "onSale": false,
  "discountPercent": null,
  "totalInventory": null,
  "options": [{ "name": "Size", "values": ["Extra Small", "Small", "Medium", "Large", "Extra Large"] }],
  "variants": [
    { "variantId": 39797352890570, "title": "Medium", "sku": "B7B5R-NDLF-M", "price": 60, "compareAtPrice": null, "available": true, "option1": "Medium", "option2": null, "option3": null },
    { "variantId": 39797356331210, "title": "Large", "sku": "B7B5R-NDLF-L", "price": 60, "compareAtPrice": null, "available": true, "option1": "Large", "option2": null, "option3": null }
  ],
  "observedAt": "2026-08-16T12:22:56.437Z",
  "error": null
}
```

Export the full public product catalog of any Shopify store: every product, every variant, SKUs, prices, compare-at prices, stock status, images, tags and options. Batch many stores in one run, limit to a single collection, and switch to one-row-per-variant for price and stock monitoring.

**📥 [Input](https://apify.com/scrapers_lat/shopify-store-products-scraper/input-schema) · 📤 [Output](https://apify.com/scrapers_lat/shopify-store-products-scraper/output-schema) · 💰 [Pricing](https://apify.com/scrapers_lat/shopify-store-products-scraper/pricing) · ▶️ [Examples](https://apify.com/scrapers_lat/shopify-store-products-scraper/examples)**

![Apify](https://img.shields.io/badge/Platform-Apify-1CE1CE?logo=apify\&logoColor=white)
![Coverage](https://img.shields.io/badge/Coverage-Any%20Shopify%20store-blue)
![Output](https://img.shields.io/badge/Output-JSON%20%7C%20CSV%20%7C%20Excel-orange)
![Billing](https://img.shields.io/badge/Billing-Pay%20per%20result-brightgreen)

### Table of contents

- [What it does](#what-it-does)
- [Use cases](#use-cases)
- [Quickstart](#quickstart)
- [Input reference](#input-reference)
- [Output reference](#output-reference)
- [One row per variant](#one-row-per-variant)
- [Run via API and CLI](#run-via-api-and-cli)
- [Billing and limits](#billing-and-limits)
- [FAQ and troubleshooting](#faq-and-troubleshooting)

### What it does

Give the actor one or more Shopify store domains. For each store it reads the store's own public storefront product feed, paginates through the entire catalog, and writes one normalized record per product to the run's dataset. Every product includes its full variant list (title, SKU, price, compare-at price, availability, option values), image count and featured image, options, tags, and timestamps.

On top of the raw store data the actor derives fields you would otherwise compute yourself: `minPrice`, `maxPrice`, `priceRange`, `inStock` (true if any variant is available), `onSale` and `discountPercent` (from compare-at prices), `variantCount`, `imageCount`, and the public product `url`.

It accepts a domain in any common form: a bare domain (`allbirds.com`), a full URL (`https://gymshark.com`), or a myshopify subdomain (`mystore.myshopify.com`). Optional filters limit the run to a single collection, a product type, or a vendor.

Many Shopify stores block datacenter IP addresses. The actor defaults to Apify Residential proxy so those stores return data, and rotates the IP on a block. You can override the proxy in the input.

Two optional paid add-ons extend each run. The **store profile** add-on reads each store's public `meta.json` to return store-level context the product feed lacks, including the store **currency**, store name, country, city, myshopify domain, and published product and collection counts. The **AI tags** add-on uses AI to enrich every product with a clean category, sub-category, inferred material, target audience, and 5 to 8 SEO keywords buyers actually search for. Both are off by default, billed only on genuine success, and disabled for free plans.

### Use cases

- Shopify product research and competitor catalog export for market and pricing analysis.
- Ecommerce price monitoring and stock tracking across many Shopify stores by SKU.
- Build a product feed for comparison shopping, affiliate, or dropshipping catalogs.
- Brand and vendor auditing: pull every product, variant, and compare-at price from a store.
- Sale and discount tracking to spot on-sale products and discount percentages in real time.
- Enrich a product dataset with AI category, material, target audience, and SEO keywords for merchandising and search.
- Normalize multi-store catalogs into one JSON, CSV, or Excel export for a data warehouse.
- Currency-aware pricing intelligence using the store profile add-on to attach the correct currency code.

### Quickstart

Open the actor, paste this into the input, and press Run. It exports the first products from two stores.

```json
{
  "storeUrls": ["allbirds.com", "gymshark.com"],
  "maxProductsPerStore": 50
}
```

### Input reference

| Field | Type | Description |
| --- | --- | --- |
| `storeUrls` | array | One or more Shopify store domains or URLs. Bare domain, https URL, or myshopify subdomain are all accepted. |
| `storeUrl` | string | A single store domain/URL, as an alternative to `storeUrls`. |
| `collection` | string | Optional collection handle (e.g. `mens`, `sale`). Limits every store to that collection. |
| `productType` | string | Optional. Keep only products whose product type matches (case-insensitive). |
| `vendor` | string | Optional. Keep only products whose vendor matches (case-insensitive). |
| `oneRowPerVariant` | boolean | Off (default) = one row per product with a nested `variants` array. On = one row per variant. |
| `withStoreProfile` | boolean | Off by default. Paid add-on ($0.012 per store): fetches each store's `meta.json` to add store profile context including **currency**, store name, country, city, myshopify domain, and product/collection counts, as one extra `store_profile` row per store. Charged only on usable data. Disabled for free users. |
| `withAiTags` | boolean | Off by default. Paid AI add-on ($0.012 per product): adds AI category, sub-category, material, target audience, and 5-8 SEO keywords per product. Charged only on usable AI output. Disabled for free users. |
| `maxProductsPerStore` | integer | Max products to capture per store. Empty = whole catalog. |
| `maxProducts` | integer | Max products across all stores combined. Empty = no limit. |
| `proxyConfiguration` | object | Proxy settings. Defaults to Apify Residential. |

### Output reference

One row per product (default mode):

| Field | Description |
| --- | --- |
| `storeDomain` | Store the record came from. |
| `productId` | Shopify product id (unique within the store). |
| `title`, `handle`, `vendor`, `productType` | Core product attributes. |
| `tags` | Array of product tags. |
| `createdAt`, `updatedAt`, `publishedAt` | Product timestamps. |
| `url` | Public product page URL. |
| `imageCount`, `featuredImage` | Image count and primary image URL. |
| `variantCount` | Number of variants. |
| `minPrice`, `maxPrice`, `priceRange` | Price summary across variants. |
| `currency` | `null` from the base feed. Filled with the real currency code when the store profile add-on is enabled (see below). |
| `inStock` | True if any variant is available. |
| `onSale`, `discountPercent` | Derived from compare-at prices. |
| `totalInventory` | Sum of variant inventory when the store exposes it, else `null`. |
| `options` | Product options (name and possible values). |
| `variants` | Nested array: `variantId`, `title`, `sku`, `price`, `compareAtPrice`, `available`, `option1/2/3`. |
| `aiCategory`, `aiSubCategory`, `aiMaterial`, `aiTargetAudience`, `aiKeywords` | AI enrichment fields. `null` unless the AI tags add-on is enabled. `aiKeywords` is an array of SEO search phrases. |
| `observedAt` | Capture timestamp. |
| `error` | `null` on success. Set on an unbilled error row for a store that could not be read. |

When the store profile add-on is enabled, one extra `store_profile` row is written per store (`recordType: "store_profile"`) with `storeName`, `storeCountry`, `storeCity`, `storeProvince`, `storeCurrency`, `myshopifyDomain`, `productCount`, and `collectionCount`.

### One row per variant

Set `oneRowPerVariant` to `true` and each variant becomes its own row, flattened with its parent product fields plus `variantId`, `variantTitle`, `sku`, `price`, `compareAtPrice`, `available`, `onSale`, `discountPercent` and `option1/2/3`. This is the layout you want for price and stock monitoring or for loading into a spreadsheet or database keyed by SKU.

### Run via API and CLI

```bash
## CLI
apify call scrapers_lat/shopify-store-products-scraper --input='{"storeUrls":["allbirds.com"]}'

## API
curl -X POST "https://api.apify.com/v2/acts/scrapers_lat~shopify-store-products-scraper/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"storeUrls":["allbirds.com"],"maxProductsPerStore":100}'
```

Fetch the dataset once the run finishes:

```bash
curl "https://api.apify.com/v2/datasets/DATASET_ID/items?clean=true&format=json"
```

### Billing and limits

This actor is billed pay per result. You are charged one `result` event per output row (one per product, or one per variant in one-row-per-variant mode). Stores that cannot be read produce a single unbilled error row, so a broken or non-Shopify domain never costs you.

Two optional paid add-ons, both off by default and disabled for free users:

- **`store_profile` ($0.012 per store)**, enabled with `withStoreProfile`. Fetches the store's public `meta.json` once per store and writes one `store_profile` row with the store currency, name, country, city, myshopify domain, and product and collection counts. Charged once per store, only when usable data is returned.
- **`ai_tags` ($0.012 per product)**, enabled with `withAiTags`. Uses AI to add a category, sub-category, material, target audience, and 5 to 8 SEO keywords per product. One model call per product, charged only when the model returns usable output.

Free Apify plans are capped at 10 output rows per run and cannot use the paid add-ons. Upgrade for the full catalog, higher volume, and the add-ons.

**Currency note:** the base Shopify storefront product feed does not include a currency code, so `currency` is `null` in the base result. Enable the **store profile add-on** (`withStoreProfile`) to resolve the store currency from its `meta.json`; the currency is then attached to the `store_profile` row as `storeCurrency` and filled into each product's `currency` field.

### FAQ and troubleshooting

**Which stores does this work on?** Any store running on Shopify that leaves its public product feed enabled (the vast majority). A store that is not on Shopify, or that has disabled the feed, returns an unbilled error row.

**Do I need an API key or login for the store?** No. Only public catalog data is read. No account, password, or private token is required.

**A store returned an error row. Why?** Either it is not a Shopify store, its product feed is disabled, or it was temporarily blocking requests. Re-running with the default residential proxy usually resolves temporary blocks.

**Can I monitor prices over time?** Yes. Run on a schedule with `oneRowPerVariant` on and compare `price` and `compareAtPrice` per `sku` between runs.

**How do I get only one collection?** Set `collection` to the collection handle from its URL (`/collections/<handle>`).

**Is inventory quantity included?** Only when the store chooses to expose it. When it is hidden, `totalInventory` is `null` and variant availability is still reported via `available`.

# Actor input Schema

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

One or more Shopify store domains or URLs (bare domain, https URL, or myshopify subdomain). Each store's full public catalog is exported. Example: allbirds.com, https://gymshark.com, mystore.myshopify.com.

## `storeUrl` (type: `string`):

A single Shopify store domain/URL. Use this or Store Domains above.

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

Limit the export to a single collection by its handle, e.g. "mens" or "sale". Applies to every store. Leave empty to export the whole catalog.

## `productType` (type: `string`):

Only keep products whose product\_type exactly matches this value (case-insensitive), e.g. "Shoes".

## `vendor` (type: `string`):

Only keep products whose vendor exactly matches this value (case-insensitive).

## `oneRowPerVariant` (type: `boolean`):

Off (default) = one row per product with a nested variants array. On = one row PER VARIANT (variantId, SKU, price, compare-at price, availability, option values) - ideal for price/stock monitoring.

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

Maximum number of products to capture from each store. Leave empty for the whole catalog.

## `maxProducts` (type: `integer`):

Maximum number of products to capture across all stores combined. Leave empty for no limit. Free Apify plans are capped at 10 output rows.

## `withStoreProfile` (type: `boolean`):

Off by default. When on, fetches each store's public meta.json once per store to add store-level context the product feed lacks, INCLUDING the store CURRENCY, plus store name, country, city, myshopify domain, and product/collection counts. Emitted as one extra store\_profile record per store. Billed $0.012 per store, only when usable data is returned. Disabled for free users.

## `withAiTags` (type: `boolean`):

Off by default. When on, uses AI (OpenRouter, gpt-4o-mini) to produce structured buyer-search tags per product: category, subCategory, material, targetAudience, and 5-8 SEO keywords. One model call per product. Billed $0.012 per product, only on usable AI output. Disabled for free users.

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

Proxy settings. Defaults to Apify Residential proxy because many Shopify stores return 403 to datacenter IPs. You can override with your own selection.

## Actor input object example

```json
{
  "storeUrls": [
    "allbirds.com"
  ],
  "oneRowPerVariant": false,
  "withStoreProfile": false,
  "withAiTags": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# 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": [
        "allbirds.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapers_lat/shopify-store-products-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": ["allbirds.com"] }

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapers_lat/shopify-store-products-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/38tvaO7z2ZFvRoeql/builds/iTyoaXRgyz4BkHlSq/openapi.json
