# Shopify Store Analyzer — Catalogue, Apps & EU Recall Exposure (`northwestsouth/shopify-store-analyzer-no-duplicate-billing`) Actor

Analyzes Shopify stores you supply: catalogue stats, price bands, 295 app detectors, tracking pixels, EU compliance pages and brand-level EU recall exposure. Never charges twice for the same store.

- **URL**: https://apify.com/northwestsouth/shopify-store-analyzer-no-duplicate-billing.md
- **Developed by:** [NorthWestSouth Data](https://apify.com/northwestsouth) (community)
- **Categories:** E-commerce, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $7.00 / 1,000 store analyzeds

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/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 Analyzer — Catalogue, Apps & EU Recall Exposure

Give it a list of Shopify stores. Get back what they sell, what they run on, whether they meet EU legal requirements, and whether their brands have EU product-safety recalls on record.

### You are never charged twice for the same store

This is the point. Every store you receive is remembered across **all** your runs. Send the same list again next month and you pay only for what is genuinely new.

- Already analyzed → skipped, free, and the log tells you exactly how many.
- Store blocked, offline or not Shopify → **free**, and the reason lands in a separate `FAILED-STORES` dataset. Failures never touch your bill.
- Want fresh data anyway? Set `chargeForPreviouslyAnalyzed` to true. Nothing is hidden, nothing is automatic.

There are **no hidden row limits**. What you ask for is what you get.

### What you get per store

**Catalogue** — product and variant counts, availability rate, vendor and product-type breakdown, price min/median/max, price bands ($0-25 / 25-50 / 50-100 / 100-250 / 250+), and new-product velocity over 7, 30 and 90 days (a good proxy for how actively a store is run).

**Tech stack** — installed Shopify apps detected from **295 fingerprints**, plus theme name, Shopify Plus status, and tracking pixels (GA4, Google Tag Manager, Meta, TikTok, Pinterest, Klaviyo, Hotjar).

**EU compliance pages** — whether Impressum, Widerrufsbelehrung, AGB, Datenschutz, Versand, Kontakt and product-safety pages are linked. A fast way to separate EU-ready stores from ones that are not.

**EU recall exposure (unique to this actor)** — the store's vendor names matched against **46,506 official EU Safety Gate (RAPEX) recall alerts** going back to 2005: alert counts per brand, how many were serious risk, the most recent alert and the dominant hazard types.

### Honest limitations — please read

**Recall matching is brand-level, not product-level.** Shopify strips the `barcode` field from the public `products.json`, so an exact GTIN match is impossible from this data. We match on vendor name, which is fuzzy: a hit means *this brand appears in EU recall records*, not *this specific product is recalled*. Treat it as a screening signal.

**Some stores block automated requests.** Large brands occasionally return 403 or 429 at their CDN edge. Those stores are reported as failures — and cost you nothing.

**You supply the store list.** This actor does not discover stores. Every discovery method in this category either scrapes a Shopify property that disallows it, or resells a database whose origin is never stated. We do neither.

### Choose your fields

Set `outputFields` to just the fields you want — for example `["product_count", "top_vendors", "detected_apps"]` — and your export contains nothing else.

### Input

```json
{
  "storeUrls": ["snocks.com", "allbirds.com"],
  "includeCatalogue": true,
  "includeApps": true,
  "includeCompliance": true,
  "includeRecallExposure": true,
  "maxProductsPerStore": 250
}
```

Bare domains, full URLs and `*.myshopify.com` hosts all work.

### Pricing

Pay per **successfully analyzed store**. Not per product, not per row. Reading 2,000 products from a store costs exactly the same as reading 50.

### Sources and licensing

- App fingerprints derived from [feracommerce/shopify\_app\_detector](https://github.com/feracommerce/shopify_app_detector), Apache-2.0.
- Recall data: Alerts from the Rapid Alert System for dangerous non-food products, published free of charge on the [Safety Gate website](https://ec.europa.eu/safety-gate-alerts) © European Union, 2005–2026. Reused under Commission Decision 2011/833/EU.
- Catalogue data comes from each store's own public `/products.json` endpoint, which Shopify's robots.txt does not disallow. Legal pages are detected by the **presence of links** on the homepage; pages under `/policies/` are never fetched, because robots.txt disallows crawling them.

### Support

Missing a field, or a store that should work but doesn't? Open an issue on this actor — I read them and reply.

# Actor input Schema

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

The stores to analyze — bare domains (snocks.com), full URLs or myshopify hosts all work. You supply the list; this actor never harvests store lists from third-party databases.

## `includeCatalogue` (type: `boolean`):

Product and variant counts, vendor and product-type breakdown, price bands, availability rate, new-product velocity (7/30/90 days).

## `includeApps` (type: `boolean`):

Detects installed Shopify apps using 295 fingerprints, plus theme, Shopify Plus status and tracking pixels (GA4, GTM, Meta, TikTok, Pinterest, Klaviyo, Hotjar).

## `includeCompliance` (type: `boolean`):

Checks whether Impressum, Widerrufsbelehrung, AGB, Datenschutz, Versand and product-safety pages exist. Useful for EU/DACH market research.

## `includeRecallExposure` (type: `boolean`):

Matches the store's vendor names against 46,506 official EU Safety Gate (RAPEX) recall alerts. Brand-level and fuzzy — Shopify does not expose barcodes publicly, so this is not a product-level verdict.

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

How many products to read per store (50-2000). Higher means better statistics and slightly longer runs. Does not affect the price — you pay per store, not per product.

## `outputFields` (type: `array`):

Leave empty for everything. Otherwise list the exact fields you want, e.g. product\_count, top\_vendors, detected\_apps — so your export contains no noise.

## `chargeForPreviouslyAnalyzed` (type: `boolean`):

OFF by default: stores analyzed in any earlier run are skipped and NOT charged again. Turn this on only when you deliberately want fresh data for stores you already have.

## Actor input object example

```json
{
  "storeUrls": [
    "snocks.com",
    "allbirds.com"
  ],
  "includeCatalogue": true,
  "includeApps": true,
  "includeCompliance": true,
  "includeRecallExposure": true,
  "maxProductsPerStore": 250,
  "outputFields": [],
  "chargeForPreviouslyAnalyzed": false
}
```

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

// Run the Actor and wait for it to finish
const run = await client.actor("northwestsouth/shopify-store-analyzer-no-duplicate-billing").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": [
        "snocks.com",
        "allbirds.com",
    ],
    "outputFields": [],
}

# Run the Actor and wait for it to finish
run = client.actor("northwestsouth/shopify-store-analyzer-no-duplicate-billing").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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": [
    "snocks.com",
    "allbirds.com"
  ],
  "outputFields": []
}' |
apify call northwestsouth/shopify-store-analyzer-no-duplicate-billing --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=northwestsouth/shopify-store-analyzer-no-duplicate-billing",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/SSfvDalorA2xLWJPt/builds/axZhGckFiJYWhDo9D/openapi.json
