# Shopify Products API & Scraper (`rocketyard/shopify-products-scraper`) Actor

Shopify products API: exports the whole public catalog of a Shopify store (title, vendor, tags, price range, discount, currency, stock flag and more) over REST. Filter by vendor, type, tag, keyword, stock or update date before billing. JSON, CSV or Excel. $0.50 per 1,000 products, no subscription.

- **URL**: https://apify.com/rocketyard/shopify-products-scraper.md
- **Developed by:** [Rocketyard](https://apify.com/rocketyard) (community)
- **Categories:** E-commerce, Developer tools
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.33 / 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/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 Products API & Scraper

**Shopify Products API & Scraper** is a REST API on the Apify platform: one request returns the whole public catalog of a Shopify store, as JSON, CSV or Excel. You can also run it from a form in the Apify Console, without code.

### What does Shopify Products API & Scraper do?

Shopify Products API & Scraper exports the whole public catalog of a Shopify store: one clean record per product, with typed values (numbers, booleans, ISO dates) ready for spreadsheets, databases and AI pipelines.

- The whole public catalog of a store from Shopify's own JSON feed: no browser, no login, no API key
- One record per product, or one per variant for spreadsheets and price tracking
- Every variant with SKU, options, price, earlier price, stock flag and weight; products with price range, discount and images
- The currency of the prices, taken from the store's answer for them, and left empty if the store names none
- Filters run before billing: vendor, type, tag, keyword, in stock, updated since
- A store that refuses, or isn't on Shopify, gets a free error item with the reason, and the others carry on
- Pay only per result: no monthly rental, no minimums

### Use cases

- **Export a competitor's whole catalog with prices, variants and stock flags**
- **Track price changes, discounts and sold-out variants on a schedule**
- **Build product feeds, comparison sites and market research datasets from many stores**
- **Feed clean product data into AI agents, RAG pipelines and BI tools**

### Why this Shopify product scraper?

- Several competitors have unreliable runs (<90% success in 30 days)
- Cheaper than typical alternatives ($0.50 vs $1.10 per 1,000 results)

### How it compares

| Shopify product scraper | Users (last 30 days) | Successful runs (last 30 days) | Price per 1,000 results |
| --- | --- | --- | --- |
| Shopify Scraper - Products, Prices, Stock & Inventory | 111 | 93.6% | $1.00 |
| Shopify Products Scraper | 105 | 99.2% | $1.00 |
| Shopify Product Scraper | 11 | 93.4% | $10.00 |
| **This Actor** | new | every release is tested on live pages first | **$0.50** |

Apify Store data from 2026-11-05, free-plan prices. Prices and stats change; check each listing before you compare.

### Shopify products API

Every Apify Actor is also a REST endpoint, so Shopify Products API & Scraper works as a Shopify products API, a Shopify product data API, a Shopify catalog API or a Shopify scraper API, without a server of your own. One `POST` starts a run, waits for it and returns the results:

```text
POST https://api.apify.com/v2/acts/rocketyard~shopify-products-scraper/run-sync-get-dataset-items
```

Send your [Apify API token](https://console.apify.com/settings/integrations) in the `Authorization` header and the [input](#input-example) as the JSON body. Add `?format=csv` or `?format=xlsx` to get CSV or Excel instead of JSON. The request waits up to 300 seconds; for a longer run, start it with `POST /v2/acts/rocketyard~shopify-products-scraper/runs` and read the dataset when it finishes.

### How it works

Stores on Shopify's standard storefront publish their catalog as JSON at `/products.json` and `/collections/<handle>/products.json`, with no login or API key. The Actor reads those pages over plain HTTP, 250 products per request and one request per second, until the catalog ends or your limit is reached. It honours each store's robots.txt and crawl-delay, waits and retries a bounded number of times when a store asks it to slow down, and turns the JSON into typed records: prices as numbers, dates in ISO 8601, descriptions as clean text. The currency comes from the store's own answer for those prices. A store that refuses, or that isn't on Shopify, gets an error item that says why, and isn't charged.

### How to use it

1. Click **Try for free**.
2. Add store URLs to **Store, collection or product URLs**, or domains to **Store domains**.
3. Optionally pick **Variant** records, and keep only what you need with the filters. Filters run before billing.
4. Click **Start**, then download results as JSON, CSV or Excel, or read them through the API.

### Input

| Field | JSON key | What it does |
|---|---|---|
| Store, collection or product URLs | `startUrls` | Store URLs read the whole catalog. A collection URL (…/collections/sale) reads that collection. A product URL (…/products/some-handle) returns that product. Leave empty if you use Store domains. |
| Store domains | `stores` | Store domains such as "muji.us", as an alternative to URLs. Each one reads the whole catalog. |
| One record per | `recordType` | Product (default) keeps all variants in one record, in the `variants` list. Variant gives one flat row per variant, which suits spreadsheets and price tracking. Each stored record is one paid result. |
| Keyword | `keyword` | Keep products with this word in the title, tags, vendor, type, handle, variant title or SKU. Separate alternatives with commas. |
| Vendor | `vendor` | Keep products whose vendor contains this text. Separate alternatives with commas. |
| Product type | `productType` | Keep products whose type contains this text. Separate alternatives with commas. |
| Tag | `tag` | Keep products with exactly this tag (any capitalization). Separate alternatives with commas. |
| In stock only | `inStockOnly` | Keep only products with a variant that can be bought. For variant records, keep only the variants that can be bought. |
| Updated since | `updatedSince` | Keep products changed since this date, such as "2026-10-01", or within this age, such as "7 days". On a schedule, this returns only what changed. |
| Market country | `country` | Two-letter code such as "US" or "DE": read each store as shoppers in that country see it, with that market's prices, currency and availability. Without it, stores answer for the location of the run. Stores without that market answer for their default, and every record says its currency. |
| Max results | `maxItems` | Stop after this many records in total, over all stores. This also caps the cost of the run. |
| Max results per store | `maxItemsPerStore` | Stop reading a store or collection after this many records. Leave empty for its whole catalog. |
| Max concurrency | `maxConcurrency` | Stores read in parallel. Without a proxy, a run still sends one request per second overall, because Shopify rate-limits clients that read faster. |
| Proxy configuration | `proxyConfiguration` | Optional Apify Proxy for ordinary routing. A proxy changes the location a store sees, which can change the market it answers for. It is not a way around a store that refuses access. |

### Input example

```json
{
  "startUrls": [
    {
      "url": "https://muji.us"
    }
  ],
  "stores": [
    "deathwishcoffee.com"
  ],
  "country": "US",
  "inStockOnly": true,
  "maxItems": 1000
}
```

### Output example

A real record from the latest test run (tentree.com) on 2026-11-05. Fields the page didn't publish are left out here; the Actor returns them as `null`.

```json
{
  "url": "https://tentree.com/products/slogan-peak-hat-deep-olive-i-like-your-dog",
  "type": "Product",
  "store": "tentree.com",
  "productId": 8143518761146,
  "title": "Slogan Peak Hat",
  "handle": "slogan-peak-hat-deep-olive-i-like-your-dog",
  "description": "Show them what's on your mind with these fun, embroidered caps — each of which is made using organic cotton that's super soft and good for our planet.",
  "vendor": "tentree",
  "productType": "Accessories",
  "tags": [
    "accessories",
    "baseball-cap",
    "best-sellers",
    "dirty-deals",
    "final-sale",
    "gh-unisex-slogan-peak-hat-meteorite-black-overthinking",
    "gift-guide-25-all",
    "gifts-best-sellers-26"
  ],
  "options": [
    {
      "name": "Color",
      "values": [
        "DEEP OLIVE I LIKE YOUR DOG"
      ]
    },
    {
      "name": "Size",
      "values": [
        "ONE"
      ]
    }
  ],
  "priceMin": 36,
  "priceMax": 36,
  "compareAtPrice": 45,
  "onSale": true,
  "discountPercent": 20,
  "currency": "USD",
  "available": true,
  "variantCount": 1,
  "availableVariantCount": 1,
  "variants": [
    {
      "id": 44904928411834,
      "sku": "TAU5925-5831-ONE",
      "title": "DEEP OLIVE I LIKE YOUR DOG / ONE",
      "options": {
        "Color": "DEEP OLIVE I LIKE YOUR DOG",
        "Size": "ONE"
      },
      "price": 36,
      "compareAtPrice": 45,
      "available": true,
      "weightGrams": 300,
      "requiresShipping": true,
      "taxable": true,
      "image": "https://cdn.shopify.com/s/files/1/2341/3995/files/Green-Organic-Cotton-Low-Profile-Embroidered-Baseball-Cap-TAU5925-5831_1.jpg?v=1749230208",
      "updatedAt": "2026-11-05T18:07:35.000Z"
    }
  ],
  "image": "https://cdn.shopify.com/s/files/1/2341/3995/files/Green-Organic-Cotton-Low-Profile-Embroidered-Baseball-Cap-TAU5925-5831_1.jpg?v=1749230208",
  "images": [
    {
      "url": "https://cdn.shopify.com/s/files/1/2341/3995/files/Green-Organic-Cotton-Low-Profile-Embroidered-Baseball-Cap-TAU5925-5831_1.jpg?v=1749230208",
      "width": 960,
      "height": 1200,
      "variantIds": [
        44904928411834
      ]
    },
    {
      "url": "https://cdn.shopify.com/s/files/1/2341/3995/files/Green-Organic-Cotton-Low-Profile-Embroidered-Baseball-Cap-TAU5925-5831_3.jpg?v=1749230208",
      "width": 960,
      "height": 1200,
      "variantIds": []
    }
  ],
  "publishedAt": "2026-10-28T02:51:19.000Z",
  "createdAt": "2025-06-06T17:16:44.000Z",
  "updatedAt": "2026-11-05T18:07:35.000Z",
  "sourceUrl": "https://tentree.com",
  "scrapedAt": "2026-11-05T18:07:35.372Z"
}
```

#### Output fields

| Field | Description | Filled |
|---|---|---|
| `url` | Product page | 100% |
| `type` | `Product`, or `ProductVariant` for one record per variant | always |
| `store` | Store domain, without `www.` | 100% |
| `title` | Product title | 100% |
| `handle` | The product's URL name in the store | 100% |
| `productId` | Shopify product ID | 100% |
| `description` | Description as clean text, with HTML removed | 92.4% |
| `vendor` | Vendor or brand, as the store enters it | 100% |
| `productType` | Product type, as the store enters it | 96% |
| `tags` | Tags, as a list | 96.3% |
| `options` | Option names and their values, such as Size: S, M, L. Empty for products with no options | 71.6% |
| `priceMin` | Lowest variant price, as a number | 100% |
| `priceMax` | Highest variant price, as a number | 100% |
| `compareAtPrice` | Earlier price of the most discounted variant, only when it is above that variant's price. Variant records: this variant's | 23.3% |
| `onSale` | True when a variant has an earlier price above its price. Variant records: this variant | 100% |
| `discountPercent` | Discount of the most discounted variant, in percent, worked out from the two prices. Variant records: this variant | 23.3% |
| `currency` | ISO 4217 code of these prices, as the store named it in the same response. Empty when the store did not name one | 100% |
| `available` | True when a variant can be bought in the market read, false when none can. A flag, not a stock count. Variant records: this variant | 100% |
| `variantCount` | Number of variants | 100% |
| `availableVariantCount` | Number of variants that can be bought | 100% |
| `variants` | Every variant: `id`, `sku`, `title`, `options` (name to value), `price`, `compareAtPrice`, `available`, `weightGrams`, `requiresShipping`, `taxable`, `image`, `updatedAt`. Left out of variant records | 100% |
| `image` | Main image URL. Variant records: the image of this variant when it has one | 96.7% |
| `images` | Every image: `url`, `width`, `height`, `variantIds` | 96.7% |
| `publishedAt` | Published (ISO 8601, UTC) | 100% |
| `createdAt` | Created (ISO 8601, UTC) | 100% |
| `updatedAt` | Last updated (ISO 8601, UTC). Variant records: this variant's | 100% |
| `sourceUrl` | The store or collection the record was read from | always |
| `variantId` | Variant records only: Shopify variant ID | 100% |
| `variantTitle` | Variant records only: variant title, such as "Black / M". Empty for products with no options | 81.9% |
| `sku` | Variant records only: SKU, when the store sets one | 98.3% |
| `selectedOptions` | Variant records only: this variant's options, such as {"Size": "M"} | 81.9% |
| `price` | Variant records only: this variant's price, as a number | 100% |
| `weightGrams` | Variant records only: weight in grams, when the store sets one | 67.5% |
| `requiresShipping` | Variant records only: whether it ships | 100% |
| `taxable` | Variant records only: whether it is taxed | 100% |
| `scrapedAt` | ISO timestamp of the extraction | always |

"Filled" is the share of records with a value, measured through this Actor's mapping on 11 stores on 2026-11-05: 2,430 products, and 2,714 variant records for the fields only those have. Stores differ: a store that enters no product types has none.

### Error items

When an input produces no data, the dataset gets one **error item** for it, so nothing is skipped silently. Error items are **free**: only result records are charged.

```json
{
  "url": "https://example.com",
  "input": "https://example.com",
  "error": {
    "type": "https://rocketyard.dev/errors#no-structured-data",
    "title": "No structured data found",
    "status": 404,
    "detail": "example.com does not serve Shopify's public catalog (HTTP 404): it is not a Shopify store, or it runs Shopify behind its own front end.",
    "instance": "https://example.com",
    "code": "NO_STRUCTURED_DATA"
  }
}
```

The `error` object follows [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) (Problem Details). Its `type` links to the [explanation of the code](https://rocketyard.dev/errors), and `status` is the site's HTTP status when there was one. Filter on `error.code` to separate failures from data; it has its own column in CSV and Excel exports.

| Code | Meaning | Retry? |
|---|---|---|
| [`ROBOTS_DISALLOWED`](https://rocketyard.dev/errors#robots-disallowed) | The site's robots.txt does not allow automated access to this URL (or to the page it redirects to), so it was not fetched. | no |
| [`ROBOTS_UNREACHABLE`](https://rocketyard.dev/errors#robots-unreachable) | The site's robots.txt could not be loaded because of a server or network error. Under RFC 9309, the page is then not fetched. | yes |
| [`PRIVATE_ADDRESS`](https://rocketyard.dev/errors#private-address) | The URL, or a redirect from it, points to a private or local network address. Only public websites are fetched. | no |
| [`NOT_FOUND`](https://rocketyard.dev/errors#not-found) | The page or source does not exist (HTTP 404 or 410). | no |
| [`BLOCKED`](https://rocketyard.dev/errors#blocked) | The site refused access (HTTP 401, 403 or 429) or answered with a bot-check or consent page instead of the content. | sometimes |
| [`HTTP_ERROR`](https://rocketyard.dev/errors#http-error) | The site answered with another HTTP error: a server error (5xx) that persisted after retries, or an unexpected 4xx status. | sometimes |
| [`TIMEOUT`](https://rocketyard.dev/errors#timeout) | The site did not answer in time, even after retries. | yes |
| [`NETWORK_ERROR`](https://rocketyard.dev/errors#network-error) | The connection failed (DNS, TLS or a reset connection), even after retries. | yes |
| [`TOO_LARGE`](https://rocketyard.dev/errors#too-large) | The response exceeded the size limit (10 MiB for web pages, 48 MiB for API responses). | no |
| [`PARSE_ERROR`](https://rocketyard.dev/errors#parse-error) | The response could not be read (malformed HTML or JSON). | sometimes |
| [`NO_STRUCTURED_DATA`](https://rocketyard.dev/errors#no-structured-data) | The page loaded but has none of the data the Actor extracts: no schema.org data (JSON-LD or microdata), or, for the Shopify Actor, no public Shopify catalog on the site. | no |
| [`EMPTY`](https://rocketyard.dev/errors#empty) | The source has nothing to return right now: a list with no open items, a store or collection with no products, a search with no results, or a web page whose HTML has no readable text (often a page built only by JavaScript in the browser). | no |
| [`NO_MATCHES`](https://rocketyard.dev/errors#no-matches) | The source has items, but none of them matched your filters. | no |

### Limits

- On 2026-11-05, 11 of 14 well-known stores served their catalog. Two run Shopify behind their own front end or don't publish the feed, and one refused with a bot check.
- No inventory quantities and no barcodes: `/products.json` doesn't publish them. `available` is the store's in-stock flag, not a count.
- Shopify serves one listing up to an offset of 25,000 products (HTTP 400 after page 100). A larger store returns those 25,000 and a free `HTTP_ERROR` item that says so. Add its collection URLs to reach more; a product in several inputs is charged once.
- Sites that run Shopify behind their own front end usually don't serve the feed, and return a free `NO_STRUCTURED_DATA` item, like any site not on Shopify.
- Some stores refuse automated reads or rate-limit them. Those return a free `BLOCKED` item. The Actor never logs in, solves a check or disguises itself, and a proxy will not change a refusal aimed at the feed itself.
- A store selling in several markets answers for one of them, and prices, currency and `available` all follow it. Without **Market country** that is the market of where the run comes from, so set it to compare runs. On 2026-11-05, one store showed 0 of 26 variants available to a visitor in Kazakhstan, and 37 of 51 with `US`.
- A product URL is found by reading its store or collection until the product turns up. The reading is free, but on a large catalog it takes a minute or two.

### Pricing

Pay per result: **$0.50 per 1,000 products**, plus a tiny per-run start fee. Products removed by your filters are not charged, and neither are inputs that fail. Each stored record is one result, so with **Variant** records each variant counts. There is no monthly rental, and you can cap spend per run with **Max results** or **Maximum cost per run**.

### Integrations and API

Run it from the [Apify API](https://docs.apify.com/api/v2), the JavaScript/Python clients, Make, Zapier, n8n, LangChain or any MCP-compatible AI agent, and send results to Google Sheets, webhooks, S3 and more. Schedule it to track changes over time.

### FAQ

**Which stores does it work on?** Stores on Shopify's standard storefront, which is most Shopify stores. You can check any store by opening `https://<store>/products.json` in a browser: if you see JSON with a `products` list, the Actor can read it.

**Can I read `/products.json` myself instead?** Yes, and for one small store you read once, you may not need this Actor: it's free and needs no key. The Actor adds paging to the end of the catalog, filters, clean typed fields, the currency of the prices, one format across stores, retries, error items, schedules and Apify's integrations.

**Is this Shopify's official API?** No. Shopify's Admin and Storefront APIs need the store owner's access. This Actor reads the public catalog feed any visitor can open, and works as an API because every Apify Actor is a REST endpoint.

**Does it return stock quantities?** No. The feed publishes whether a variant can be bought (`available`), not how many are left, so the Actor doesn't claim a number.

**What currency are the prices in?** The `currency` field says, for every record. It comes from the store's answer to the same request, because a store selling in several markets can answer in another currency than its home one. Set **Market country** to read a specific market.

**How do I get only what changed since the last run?** Schedule the Actor with **Updated since** set to an age such as `1 day`. You pay only for the products that changed.

**How much does it cost?** You pay per result: $0.50 per 1,000 products, plus a start fee of $0.00005 per run, with no subscription. Cap any run with **Maximum cost per run**.

**How do I call it from the API?** One request starts a run and returns its results, using your [Apify API token](https://console.apify.com/settings/integrations):

```bash
curl -X POST "https://api.apify.com/v2/acts/rocketyard~shopify-products-scraper/run-sync-get-dataset-items" -H "Authorization: Bearer $APIFY_TOKEN" -H "Content-Type: application/json" -d '{"startUrls":[{"url":"https://muji.us"}],"stores":["deathwishcoffee.com"],"country":"US","inStockOnly":true,"maxItems":1000}'
```

**How do I use it with AI agents?** Connect Apify's MCP server at `https://mcp.apify.com?tools=rocketyard/shopify-products-scraper`, and the agent can call this Actor as a tool.

**Is it legal to scrape Shopify data?** The Actor reads only the catalog a store publishes for anyone at `/products.json`, honours robots.txt, sends no cookies, and doesn't work around any refusal. The feed holds product data and no customer data. Some stores' terms of service restrict automated access, so check the terms of the stores you read. You are responsible for how you use the data, including copyright in descriptions and photos.

**What happens when an input fails?** If a store can't be read, the dataset gets one [error item](#error-items) for it with a code and the reason. Error items are free, and the other stores still run.

**I need a field that is not supported.** Open an issue on the Actor's Issues tab. Requests are reviewed regularly and drive new features.

### You might also like

- [Product Data API - Prices & Stock from Any Store](https://apify.com/rocketyard/product-schema-scraper): product data from any website with schema.org markup
- [Events Scraper - Any Event Site to Structured Data](https://apify.com/rocketyard/event-schema-scraper): event data from any website with schema.org markup
- [Company Info Scraper - Name, Logo & Social Profiles](https://apify.com/rocketyard/organization-schema-scraper): organization data from any website with schema.org markup
- [App Store & Google Play Scraper - Ratings & Prices](https://apify.com/rocketyard/softwareapp-schema-scraper): app data from any website with schema.org markup
- [Article Scraper - Any Website (Schema.org)](https://apify.com/rocketyard/article-schema-scraper): article data from any website with schema.org markup

### Made by Rocketyard

[Rocketyard](https://rocketyard.dev) builds pay-per-result scrapers for public web data, and every release is tested on live pages before it ships. Guides for this Actor: [overview](https://rocketyard.dev/shopify-products-scraper), [REST API](https://rocketyard.dev/shopify-products-scraper#api), [MCP for AI agents](https://rocketyard.dev/shopify-products-scraper#mcp) and [n8n, Make and Zapier](https://rocketyard.dev/shopify-products-scraper#automation).

# Actor input Schema

## `startUrls` (type: `array`):

Store URLs read the whole catalog. A collection URL (…/collections/sale) reads that collection. A product URL (…/products/some-handle) returns that product. Leave empty if you use Store domains.

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

Store domains such as "muji.us", as an alternative to URLs. Each one reads the whole catalog.

## `recordType` (type: `string`):

Product (default) keeps all variants in one record, in the `variants` list. Variant gives one flat row per variant, which suits spreadsheets and price tracking. Each stored record is one paid result.

## `keyword` (type: `string`):

Keep products with this word in the title, tags, vendor, type, handle, variant title or SKU. Separate alternatives with commas.

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

Keep products whose vendor contains this text. Separate alternatives with commas.

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

Keep products whose type contains this text. Separate alternatives with commas.

## `tag` (type: `string`):

Keep products with exactly this tag (any capitalization). Separate alternatives with commas.

## `inStockOnly` (type: `boolean`):

Keep only products with a variant that can be bought. For variant records, keep only the variants that can be bought.

## `updatedSince` (type: `string`):

Keep products changed since this date, such as "2026-10-01", or within this age, such as "7 days". On a schedule, this returns only what changed.

## `country` (type: `string`):

Two-letter code such as "US" or "DE": read each store as shoppers in that country see it, with that market's prices, currency and availability. Without it, stores answer for the location of the run. Stores without that market answer for their default, and every record says its currency.

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

Stop after this many records in total, over all stores. This also caps the cost of the run.

## `maxItemsPerStore` (type: `integer`):

Stop reading a store or collection after this many records. Leave empty for its whole catalog.

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

Stores read in parallel. Without a proxy, a run still sends one request per second overall, because Shopify rate-limits clients that read faster.

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

Optional Apify Proxy for ordinary routing. A proxy changes the location a store sees, which can change the market it answers for. It is not a way around a store that refuses access.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://muji.us"
    }
  ],
  "recordType": "product",
  "inStockOnly": false,
  "maxItems": 100,
  "maxConcurrency": 5
}
```

# Actor output Schema

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

One record per Shopify product, plus a free error item for each input that yielded no data, as JSON, CSV or Excel.

## `runSummary` (type: `string`):

Stores read, catalog pages, records stored, stores refused or skipped, and how long the run took.

# 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 = {
    "startUrls": [
        {
            "url": "https://muji.us"
        }
    ],
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("rocketyard/shopify-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 = {
    "startUrls": [{ "url": "https://muji.us" }],
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("rocketyard/shopify-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 '{
  "startUrls": [
    {
      "url": "https://muji.us"
    }
  ],
  "maxItems": 100
}' |
apify call rocketyard/shopify-products-scraper --silent --output-dataset

```

## MCP server setup

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