# Shopify Catalog & Variant Export - CSV + JSON (`cordial_chance/shopify-catalog-variant-export`) Actor

Export permitted Shopify product feeds as one row per variant, with SKUs, options, decimal-string prices, supplied currency and a coverage report. CSV + JSON; safe canonical redirects; no login or proxy.

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

## Pricing

$1.00 / 1,000 verified live variant rows

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 Catalog & Variant Export - CSV + JSON

Export a merchant-authorized Shopify store or collection into variant-level rows for spreadsheets and data pipelines. Works across merchandise categories, not just apparel. This Actor reads anonymous public product feeds; it does not use the Shopify Admin API.

Each row includes product and variant IDs, product URL, title, vendor, product type, SKU, variant title, option names and values, price, compare-at price, observed availability and observation time. IDs and prices are strings in JSON. Currency is supplied by you for each store; it is not detected or converted. Size and color appear only when the feed options support those labels.

Outputs: a default dataset for JSON/API access, RESULTS.csv for spreadsheet import, and REPORT for scope, pagination, limits and delivery status. The CSV escapes formula-like cell values. Treat IDs as text when importing into spreadsheets to avoid number rounding.

Provide 1-5 authorized store or collection URLs. Body-free HEAD requests discover supported HTTPS canonical redirects before crawling, with public-DNS/TLS checks at each socket, a five-hop limit and a hard 15-second deadline per scope. Collection scope and currency are preserved; final-origin robots.txt is checked before any feed request. Loops, unsafe destinations and changed collection paths fail closed. Sites refusing HEAD and mid-crawl feed/robots redirects are unsupported; no GET fallback.

Use it for your own catalog checks, permitted supplier-feed exports and SKU-level spreadsheet work. Set small product, variant, page, time and byte caps for a first run. Reaching a cap before the terminal page marks coverage partial rather than proving the catalog ended.

Limits: public feeds can be restricted, truncated or shifting. Even a finished pagination sweep does not prove exhaustive product or variant coverage. Availability is an observed offer flag, not stock quantity. This version does not verify removals, extract hidden inventory, export images, scrape buyer/contact data or bypass access controls. Cloud runs are export-only; local snapshot comparisons are not supported on Apify.

Use only catalogs you are permitted to access and export. The input permission checkbox records your statement; it is not independent verification. Public access alone does not grant rights to scrape, reuse or resell the data. This is an unofficial tool and is not affiliated with or endorsed by Shopify.

### Public demo and live mode

The default input is `{"demoMode": true, "stores": []}`. It makes one read-only request to Shopify's official Mock.Shop API and exports a fictional sample of at most two products and three variants each. Rows and REPORT show `isDemo: true` and `dataOrigin: official-mock-shop-api`. Prices use the API's explicit currency code (currently CAD), not INR and not a guessed dollar sign. This sample does not test a merchant's public feed, prove a complete catalog, or show real stock. No merchant attestation or snapshots are used. Demo rows emit no paid event. If the official demo API fails, the run fails; no offline fallback rows are invented.

For your own or permitted supplier catalog, disable demo mode and supply stores, for example:

```json
{
    "demoMode": false,
    "stores": [{ "url": "https://your-store.example", "currency": "INR", "merchantAuthorizationConfirmed": true }]
}
```

Replace the placeholder with a catalog you have permission to export and its confirmed currency. Live rows show `isDemo: false`, `dataOrigin: live-storefront`, and `currencySource: caller`. The default example is a fictional API demonstration, not a public merchant scraping target.

### Pricing

$1.00 per 1,000 verified retained live-store variant rows ($0.001 each). No start fee. Official fictional demo mode has no Actor event charges. No monthly subscription. Platform usage is included for standard runs. A product with multiple variants produces multiple billable rows.

The exporter preflights the staged row charges before publishing rows. If your budget cannot cover them, it fails before result billing. No start fee applies. Live rows are charged only after exact dataset readback. Verified rows charged before a later failure or abort can still be billed. Charge failure or a short charge refuses complete-output acknowledgement; inspect rows, BILLING_RECEIPT and charge status before retrying. The per-run receipt is saved before dataset writes and before the charge request. Graceful abort drains in-flight publication and tries one exact readback recovery. An uncertain charge is checked against authoritative run counts and is never automatically retried. Hard termination or persistent storage/API failures can still leave retained but unbilled rows, or an unresolved charge; this is not an atomic exactly-once transaction. A resumed run reconciles its receipt and stops without recrawling or repushing rows. No automatic refund promise.

### Input

| Field               | Bounds                                          | Meaning                                                                                                                                                                                                                 |
| ------------------- | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| demoMode            | Public example true; runtime false when omitted | Fictional official demo, not a merchant feed                                                                                                                                                                            |
| stores              | Required in live mode; 1-5 entries              | Each entry has url, currency and merchantAuthorizationConfirmed:true. Use HTTPS root or /collections/<handle>. Currency must be a supported uppercase ISO code confirmed for the anonymous feed context. No conversion. |
| maxProductsPerStore | Default 100; 1-25,000                           | Maximum distinct products per scope. Start at 100.                                                                                                                                                                      |
| maxVariantsPerStore | Default 500; 1-100,000                          | Maximum variant rows per scope. Start at 500.                                                                                                                                                                           |
| maxPagesPerStore    | Default 3; 1-500                                | Maximum feed pages per scope, up to 250 products per page. A terminal empty page needs room inside the cap.                                                                                                             |
| maxBytesPerResponse | Default 8,000,000; 1,024-16,000,000             | Per-response bytes. Oversized or compressed responses fail closed.                                                                                                                                                      |
| maxTotalBytes       | Default 64,000,000; 1,024-128,000,000           | Per-scope received bytes and separate staged-output limits. Not a run-wide network byte total across all stores.                                                                                                        |
| maxDurationSecs     | Default 60; 10-3,600                            | Crawl time limit. Canonical discovery occurs before the main crawl timer; set an Apify run timeout too.                                                                                                                 |
| requestDelayMillis  | Default 1,000; 1,000-60,000                     | Minimum request delay. Robots crawl-delay can increase it. No request retries.                                                                                                                                          |
| snapshotStoreName   | Default null                                    | Leave null/omitted for cloud use. A non-null value is rejected on Apify; local comparisons require serialized writers.                                                                                                  |

### Read the outputs

REPORT describes pagination, coverage and delivery status. paginationComplete=true means an empty terminal page was reached, not exhaustive Shopify access. outputCompletion=acknowledged means dataset rows were read back and artifact writes accepted. Cloud baselineCommit=disabled. STATE may appear on failure or abort; inspect logs and REPORT/STATE before using incomplete output.

# Actor input Schema

## `demoMode` (type: `boolean`):

Unbilled fictional Mock.Shop API sample, maximum two products and three variants each. Disable for permitted live-store export. Demo accepts no merchant scopes or custom limits.

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

In live mode provide1-5 merchant-authorized scopes with supplied currency. Leave empty in demo mode.

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

Resource cap. Reaching the cap before a valid terminal page marks coverage partial.

## `maxVariantsPerStore` (type: `integer`):

Resource cap. Reaching the cap before a valid terminal page marks coverage partial.

## `maxPagesPerStore` (type: `integer`):

Resource cap. Reaching the cap before a valid terminal page marks coverage partial.

## `maxBytesPerResponse` (type: `integer`):

Resource cap. Reaching the cap before a valid terminal page marks coverage partial.

## `maxTotalBytes` (type: `integer`):

Per-scope received-byte limit and independent run-staged JSON, CSV and per-scope merged-generation byte limits. Up to five scopes can each receive this many bytes. Commit refuses caps, never truncates.

## `maxDurationSecs` (type: `integer`):

Resource cap. Reaching the cap before a valid terminal page marks coverage partial.

## `requestDelayMillis` (type: `integer`):

Minimum delay per origin; robots crawl-delay can increase it. No retries.

## `snapshotStoreName` (type: `string`):

Optional named local store for last-observed comparisons. Platform use is rejected. Omit or null for export only. Run with --no-purge and serialize writers.

## Actor input object example

```json
{
  "demoMode": true,
  "stores": [],
  "maxProductsPerStore": 100,
  "maxVariantsPerStore": 500,
  "maxPagesPerStore": 3,
  "maxBytesPerResponse": 8000000,
  "maxTotalBytes": 64000000,
  "maxDurationSecs": 60,
  "requestDelayMillis": 1000,
  "snapshotStoreName": null
}
```

# Actor output Schema

## `dataset` (type: `string`):

JSON observations including stale unobserved rows

## `report` (type: `string`):

Transport coverage and per-scope commit status

## `csv` (type: `string`):

Spreadsheet formula escaping included

# 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 = {
    "demoMode": true,
    "stores": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("cordial_chance/shopify-catalog-variant-export").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 = {
    "demoMode": True,
    "stores": [],
}

# Run the Actor and wait for it to finish
run = client.actor("cordial_chance/shopify-catalog-variant-export").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 '{
  "demoMode": true,
  "stores": []
}' |
apify call cordial_chance/shopify-catalog-variant-export --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,cordial_chance/shopify-catalog-variant-export"
        }
    }
}
```

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/7FcE4gZqImFkvdgHU/builds/6BgWFL5bdWPcvaFzo/openapi.json
