# Shopify Variant & Option Mapper CSV (`practical_ai_lab_jp/pal-shopify-store-variant-option-mapper`) Actor

Review published option and variant mappings for product-feed completeness and inconsistencies. For Shopify catalog QA and conversion optimization teams. Check the live Pricing tab and input limits.

- **URL**: https://apify.com/practical_ai_lab_jp/pal-shopify-store-variant-option-mapper.md
- **Developed by:** [Practical AI Lab](https://apify.com/practical_ai_lab_jp) (community)
- **Categories:** E-commerce, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 mapped products

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 Variant & Option Mapper CSV

Turn a public Shopify store's product feed into one flat, normalized row per variant, with size and color columns and a list of variant integrity problems. It is built for catalog cleanup, SKU mapping between systems, and pre-migration audits.

### What it does

For every variant it outputs:

- Product and variant identifiers, SKU, barcode, price, compare-at price, availability.
- Up to three option name/value pairs (`option1_name`, `option1_value`, ...).
- `size_value` and `color_value` picked from options whose names contain "size", "color" or "colour".
- `option_combo_key`, a lowercase key such as `size=s|color=red`, for joining against other systems.
- Product-level grid statistics: variant count, expected option combinations, missing combinations.
- `issues`, a semicolon-separated list of detected problems, plus `issue_count` and `has_issues`.

#### Integrity checks

| Issue | Meaning |
| --- | --- |
| `MISSING_SKU` | Variant has an empty SKU. |
| `DUPLICATE_SKU_IN_PRODUCT` | Same SKU (case-insensitive) used by several variants of one product. |
| `DUPLICATE_SKU_IN_STORE` | SKU already seen on an earlier product in this run (later occurrences are flagged). |
| `DUPLICATE_BARCODE_IN_STORE` | Barcode already seen earlier in this run. |
| `MISSING_OPTION_VALUE` | One of the product's options is empty for this variant. |
| `DUPLICATE_OPTION_COMBINATION` | Two variants share the same option combination. |
| `OPTION_VALUE_SPELLING_VARIANT` | Values differ only by case or whitespace (for example `Red` and `red `). |
| `MISSING_OR_ZERO_PRICE` | Price is empty, not numeric, or zero. |
| `COMPARE_AT_BELOW_PRICE` | Compare-at price is lower than the price. |

### Sample input

```json
{
    "storeUrls": ["https://www.allbirds.com"],
    "maxProductsPerStore": 50,
    "onlyRowsWithIssues": false,
    "requestDelayMs": 1000
}
```

Replace the sample store with stores you are allowed to analyze. To work without any network request, paste an existing `products.json` into `inlineProductsJson`.

| Field | Description |
| --- | --- |
| `storeUrls` | Up to 10 public HTTPS store URLs. Only the domain is used. |
| `maxProductsPerStore` | 1-2000, default 50. |
| `collectionHandle` | Optional single public collection, for example `mens-shoes`. |
| `onlyRowsWithIssues` | Output only variants with at least one issue. |
| `requestDelayMs` | 500-5000 ms between requests, default 1000. |
| `inlineProductsJson` | Optional pasted feed text; disables network access. |

### Output

- **Dataset**: one item per variant (views: "Variant map" and "Integrity checks").
- **Key-value store `VARIANT_MAP_CSV`**: the same rows as a CSV file.
- **Key-value store `SUMMARY`**: per-store status, issue counts, rejected URLs and caveats.

### Safety and politeness

- Only HTTPS domain names are accepted: no IP addresses, custom ports, credentials or local-looking hosts.
- Resolved addresses must be publicly routable; redirects are followed only within the same site and path.
- `robots.txt` is read first; if it disallows the feed or cannot be read reliably, the store is skipped.
- Requests are sequential, paced, and responses are size-capped. No proxies, logins or personal data are used.

### Limitations and sample-size caveats

- Only the public `products.json` feed is used. Stores may disable, cache, paginate or trim it; hidden or draft products are not visible.
- Missing-combination counts compare the option grid visible in the feed. A "missing" combination may be intentional.
- Duplicate checks only see products read in this run, and flag later occurrences only. A small `maxProductsPerStore` can miss duplicates and gives a poor picture of the whole catalog.
- Stores that redirect to a different domain are reported as errors rather than followed.
- Size and color detection relies on option names; unusual or non-English names appear only in the raw option columns.
- DNS is checked before each request, but a determined DNS-rebinding race cannot be fully excluded.
- `available` can be empty when the feed does not expose it.

### Billing

The code references one pay-per-event name, `mapped-product`, charged once per product that produced output rows. Failed stores, failed pages and invalid input are never charged. No payable plan or price is configured in this project.

### Local tests

The unit tests run offline with the standard library: `python -m unittest discover -s tests -t .`

# Actor input Schema

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

Public HTTPS storefront URLs (up to 10). Only the domain is used; the Actor reads the store's public /products.json feed after checking robots.txt. Only analyze stores you are allowed to analyze.

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

Upper bound on products read from each store (1-2000). Each page holds up to 250 products.

## `collectionHandle` (type: `string`):

Limit the analysis to one public collection, for example 'mens-shoes'. Lowercase letters, digits, hyphens and underscores only. Leave empty for the whole catalog feed.

## `onlyRowsWithIssues` (type: `boolean`):

When enabled, variant rows without any detected issue are skipped, which gives a short fix list.

## `requestDelayMs` (type: `integer`):

Pause between HTTP requests to the same run (500-5000). Keep it polite.

## `inlineProductsJson` (type: `string`):

Paste the content of a products.json file you already have. When provided, no network request is made and the store URLs are ignored.

## Actor input object example

```json
{
  "storeUrls": [
    "https://www.allbirds.com"
  ],
  "maxProductsPerStore": 50,
  "onlyRowsWithIssues": false,
  "requestDelayMs": 1000
}
```

# Actor output Schema

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

Download rows from the latest run in JSON/CSV.

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

// Run the Actor and wait for it to finish
const run = await client.actor("practical_ai_lab_jp/pal-shopify-store-variant-option-mapper").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"] }

# Run the Actor and wait for it to finish
run = client.actor("practical_ai_lab_jp/pal-shopify-store-variant-option-mapper").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"
  ]
}' |
apify call practical_ai_lab_jp/pal-shopify-store-variant-option-mapper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,practical_ai_lab_jp/pal-shopify-store-variant-option-mapper"
        }
    }
}
```

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/c267J9fYy8oK4kvCZ/builds/s29Xmb6AEBnhuXusn/openapi.json
