# VariantLens — Shopify Feed & Variant Checker (`nathancole1992/variant-lens`) Actor

Compare shopping-feed prices, stock and variant links with exact Shopify product data, rendered selection and JSON-LD. Optional GPT-6 Luna advice.

- **URL**: https://apify.com/nathancole1992/variant-lens.md
- **Developed by:** [Nathan Cole](https://apify.com/nathancole1992) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$20.00 / 1,000 checked variants

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

## VariantLens — Shopify Feed & Variant Checker

Find exact-variant differences between a shopping feed and a Shopify storefront. VariantLens compares feed values with product data, variant-linked JSON-LD and supported rendered page signals, then produces an evidence report with screenshots. Optional GPT-6 Luna advice explains what to inspect next.

**Cloud access requirement:** Shopify may block cloud audits with HTTP 429. Store owners should create a signature in **Shopify Admin → Online Store → Preferences → Crawler access**, for the exact hostname being checked, and paste its `Signature-Input` and `Signature` values into the two encrypted Actor inputs. VariantLens adds the required `Signature-Agent`. The operator bot identity is signed but is not yet registered with Shopify; unrestricted cloud access is not promised. See [Shopify’s crawler setup guide](https://help.shopify.com/en/manual/promoting-marketing/seo/crawling-your-store).

**Early beta:** tested on three public variants in Shopify’s official Dawn demonstration store using a constructed test feed, including deliberate price, stock and size errors. This is limited theme coverage, not a merchant-feed accuracy benchmark. A result is a point-in-time diagnostic, not Merchant Center approval or a complete policy audit.

### Try the fictional demo

Run the default input with `mode: demo`. Its six fictional variants demonstrate a matching page, price mismatch, stock mismatch, missing markup, blocked page and wrong selected variant. No merchant is contacted. AI is off by default.

### Check your store

1. Export up to 25 feed rows in CSV, TSV or JSON. Required fields: `id`, `link`, `price`, `availability`.
2. Select `live`, enter the exact HTTPS store hostname and paste the feed into `feedText`.
3. Confirm you own or have permission to audit the store. Links must identify the product and numeric Shopify variant, for example `https://your-store.example/products/tee?variant=123`.
4. For cloud access, supply a valid Shopify crawler signature for this hostname in the encrypted fields. These headers are never sent to other hosts or copied into reports. Expired or malformed credentials fail before store requests.
5. Keep rendering enabled to collect screenshots and visible evidence. Static checks cannot establish a landing-page match.
6. Optionally enable AI and supply your own OpenAI key in the encrypted input field. OpenAI charges are separate. Only diagnostic findings, counts and limitations are sent; HTML and screenshots are not sent to AI.

On supported Dawn markup, exact selected-variant data is read directly from the matching product component in the original page, avoiding a redundant product-JSON request. Other themes use the public Ajax product endpoint. The report records the source; ambiguous data is not accepted.

Optional columns include title, SKU, colour, size, currency, sale price and a timezone-aware sale interval. Prices are compared with decimal arithmetic. Ambiguous currencies and unsupported values require review instead of an assumed match.

### Outputs

- `OUTPUT`: complete JSON report with row results, findings, timestamps, evidence and request-health diagnostics (counts, cache hits, retries and bounded error metadata).
- `REPORT`: readable HTML report containing screenshots, request health and any AI advice.
- `ROWS`: CSV summary, with formula-like cells neutralised.
- Dataset: one item per input variant.
- `SCREENSHOT-N`: available screenshot records.

Results are **matched**, **mismatch**, **needs_review** or **blocked**. A mismatch can coexist with incomplete evidence; inspect every finding. AI suggestions are linked to finding IDs and cannot change the results. If the AI request fails, the underlying report is still saved.

### Coverage and limits

One store and anonymous market context per run; up to 25 rows and 1 MB feed text. Only public pages on the authorised hostname and selected Shopify asset hosts are requested. Robots rules and access restrictions are respected. No login, checkout, feed edits or bot-challenge bypasses are performed. Cloud data-centre requests can receive HTTP 429 even when a page works locally; affected checks are blocked/incomplete and carry no variant event fee. Direct connections are the default. Optional datacenter or residential modes use one fixed Apify session. Residential mode fetches public Shopify CDN assets directly to reduce transfer cost. Proxy tests also received persistent 429s; changing proxy mode does not replace crawler authorization. Proxy usage is included in the variant price; the selected proxy group must be available to your Apify account. Proxy setup must succeed before an audit starts. Requests are spaced, eligible public theme assets are cached for up to 120 seconds and product JSON for up to 30 seconds within the audit, and a 429 can receive one retry after Retry-After when the time budget permits. Retry waits share a 65-second budget; repeated rejection stops further requests to that host. HTML and private/no-store responses are not reused. No automatic session rotation or connection fallback occurs after an error.

Not covered: checkout totals, tax/shipping rules, customer discounts, subscriptions, every theme/locale, product images/descriptions or Google's crawl history. Unsupported visible selectors, blocked dependencies and unknown values need review. In the Dawn test, all baseline values agreed but the results correctly retained review warnings because tracking/checkout dependencies were blocked. A detected mismatch can still be reported alongside those warnings. JSON and HTML include the blocked-resource details. A matching row only means that the listed collected signals agree.

There is a 180-second batch admission budget, 45-second page captures, per-page request and byte limits, and bounded AI output with no automatic retry. Set a run timeout and spending limit in Apify. Use the default 2 GB memory setting initially and measure real runs before reducing it. Retain/share downloaded reports carefully; Apify output and input retention follow your account settings.

### Charging

The `checked-variant` event applies only to live rows with an exact Shopify variant price and purchase availability, a rendered purchase-form selection, and one visible price in the feed currency. A qualifying row may still be `needs_review` or `mismatch`; this fee pays for collected evidence, not a guaranteed match or complete page load. Demo, static-only, blocked and incomplete captures have no variant event fee. Reports are saved before charging. Apify platform usage is included in the event price. Optional OpenAI usage is billed separately by OpenAI. The run spending limit must cover all submitted rows before any store is contacted; only qualifying results are then charged. See the Pricing tab for the current rate.

### AI

Uses GPT-6 Luna with your key, strict structured output and `store: false`. There is no model substitution. Advice is optional and requires human review. OpenAI's applicable service data policies still apply. Do not include secrets in the feed.

### Support

When reporting a problem, include the run ID, affected theme, currency, expected behaviour and a redacted example row. Never include API keys or private customer data. VariantLens is independent of Shopify and Google.

# Actor input Schema

## `mode` (type: `string`):

Demo uses fictional fixtures without contacting a store. Live checks your authorized store.

## `storeDomain` (type: `string`):

Exact store hostname, without https:// or a path. Redirects may not leave this hostname.

## `feedText` (type: `string`):

1–25 rows in CSV, TSV or JSON. Required: id, link with numeric variant, price, availability. Optional: sku, color, size, sale_price, sale_price_effective_date, currency.

## `authorized` (type: `boolean`):

Required for live mode. Only public product pages are checked.

## `renderPages` (type: `boolean`):

Check visible price and selected purchase-form variant. Static-only checks cannot establish a landing-page match.

## `allowAI` (type: `boolean`):

Optional. Uses GPT-6 Luna and your OpenAI key. API charges are separate; one bounded request, no automatic retry. AI does not change verdicts.

## `openaiApiKey` (type: `string`):

Optional encrypted key, required if AI is enabled. Never include it in the feed. No creator key is bundled.

## `connectionMode` (type: `string`):

Direct is the default. Optional proxy modes use one fixed Apify session, without automatic rotation or fallback. Proxies do not replace Shopify crawler authorization and can still receive 429s. Proxy usage is included in the per-variant fee; your account must allow the chosen group. Demo makes no proxy requests.

## `shopifySignatureInput` (type: `string`):

Optional: copy the complete Signature-Input header value from Shopify Admin > Online Store > Preferences > Crawler access. Create the signature for the exact Store hostname above. Supply Signature below too.

## `shopifySignature` (type: `string`):

Optional encrypted Signature header value from the same Shopify crawler signature. VariantLens adds Signature-Agent automatically and only sends these headers to your exact store hostname. Never paste either header in the feed.

## Actor input object example

```json
{
  "mode": "demo",
  "storeDomain": "demo.variantlens.test",
  "feedText": "id,title,link,price,availability,sku,color,size\nVL-101,Studio cotton tee,https://demo.variantlens.test/products/studio-cotton-tee?variant=101,29.00 GBP,in_stock,VL-101,Ink,M\nVL-102,Everyday canvas tote,https://demo.variantlens.test/products/everyday-canvas-tote?variant=102,24.00 GBP,in_stock,VL-102,Oat,One size\nVL-103,Ribbed wool beanie,https://demo.variantlens.test/products/ribbed-wool-beanie?variant=103,32.00 GBP,in_stock,VL-103,Clay,One size\nVL-104,Linen weekend shirt,https://demo.variantlens.test/products/linen-weekend-shirt?variant=104,64.00 GBP,in_stock,VL-104,Chalk,L\nVL-105,Trail bottle,https://demo.variantlens.test/products/trail-bottle?variant=105,22.00 GBP,in_stock,VL-105,Forest,750ml\nVL-106,Merino everyday socks,https://demo.variantlens.test/products/merino-everyday-socks?variant=106,18.00 GBP,in_stock,VL-106,Ink,M\n",
  "authorized": false,
  "renderPages": true,
  "allowAI": false,
  "connectionMode": "direct"
}
```

# Actor output Schema

## `json` (type: `string`):

No description

## `html` (type: `string`):

No description

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

No description

## `dataset` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("nathancole1992/variant-lens").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("nathancole1992/variant-lens").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 '{}' |
apify call nathancole1992/variant-lens --silent --output-dataset

```

## MCP server setup

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

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/cMzHowR5R9FCBIk04/builds/wxzkEMczYMdcGzaVy/openapi.json
