# Shopify Store Analyzer - Theme, Apps, Products, Prices, Socials (`neverempty/shopify-store-inspector`) Actor

For agencies, app developers and e-commerce analysts: one row per Shopify store with its name, country, currency, myshopify domain, product and collection counts, price range, top vendors, newest products, theme, app hints and social links. Non-Shopify sites come back as free rows.

- **URL**: https://apify.com/neverempty/shopify-store-inspector.md
- **Developed by:** [NeverEmpty](https://apify.com/neverempty) (community)
- **Categories:** E-commerce, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $6.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.
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 Store Analyzer - Theme, Apps, Products, Prices, Socials

Give it a list of store URLs and get **one row per Shopify store**: store name, country, city, currency and myshopify domain, **how many products and collections it publishes, its price range (lowest, median, highest), its top vendors and product types, how fresh its catalog is, which theme it runs, which apps leave a trace on its home page, and its social links**.

Built for agencies and app developers qualifying leads, and for e-commerce analysts sizing up competitors. A site that is not on Shopify, or cannot be read, comes back as a **free row that says why**.

Unofficial. Reads only what a Shopify store serves publicly to any visitor - `/meta.json`, `/products.json`, the home page and (when needed) `/collections.json` - after reading the store's `robots.txt`. No login, no Shopify account, no API key, no cart, no checkout, no search pages.

### What you get

One row per store.

| Column | Example |
|---|---|
| `status`, `isShopify` | ok, true |
| `store`, `storeInput` | www.allbirds.com (the address that answered), allbirds.com (what you typed) |
| `storeName`, `description` | Allbirds, the store's own description |
| `country`, `province`, `city`, `currency` | US, California, Beverly Hills, USD |
| `myshopifyDomain`, `primaryDomain`, `shopId` | weareallbirds.myshopify.com, www.allbirds.com, 11044168 |
| `shipsToCountries` | `["US"]` - as the store profile lists them |
| `productCount`, `productCountSource` | 692, meta.json - the store's own count of published products |
| `collectionCount` | 1346 |
| `productsAnalyzed`, `productsAnalyzedComplete` | 692, true - how many products the statistics below are computed from, and whether that is the whole list |
| `priceMin`, `priceMedian`, `priceMax` | 0.8, 105, 165 - lowest variant price, median of each product's lowest price, highest variant price |
| `vendorCount`, `topVendors` | 2, `[{ "vendor": "Allbirds", "products": 691 }, { "vendor": "re:do", "products": 1 }]` (up to 5) |
| `topProductTypes` | `[{ "productType": "Shoes", "products": 602 }, { "productType": "Socks", "products": 57 }, ...]` (up to 5) |
| `productsInStock`, `productsOnSale` | products with at least one variant in stock; products with a variant priced below its compare-at price |
| `newestProductPublishedAt`, `productsPublishedLast30Days` | 2026-09-25T23:58:13.000Z, 398 |
| `lastProductUpdateAt`, `daysSinceLastProductUpdate` | 2026-10-03T15:41:36.000Z, 0 |
| `themeName`, `themeSchemaName`, `themeSchemaVersion`, `themeStoreId` | the theme's name in the store admin, the theme it is built on (for example Dawn), its version, its Shopify Theme Store ID (`null` for custom themes) |
| `themeAppExtensions` | `["redo"]` - app names taken from the app extension scripts the home page loads |
| `scriptHints` | `["Klaviyo", "Yotpo", "Recharge"]` - tools recognized by the script addresses on the home page |
| `instagramUrl`, `facebookUrl`, `tiktokUrl`, `twitterUrl`, `youtubeUrl`, `pinterestUrl`, `linkedinUrl` | the profile links found on the home page |
| `partsRead`, `note`, `checkedAt` | which of the public sources were read, anything that limits the row, when it was read |

**A value the store does not publish is `null`, never 0.** A count that was really counted and came out as zero is 0.

Things to know before you rely on a column:

- **Prices are numbers in the store's own listing**, as answered to a visitor from the United States without cookies; `currency` is the store's base currency from its profile.
- A home page that redirects to a language or country page (for example `/en-us`) is followed once; any other redirect is not followed, and theme, app hints and social links are then `null`.
- **Statistics come from the products that were read** - by default up to 1,000 per store (`maxProductsPerStore`, up to 5,000). When a store lists more, `productsAnalyzedComplete` is false, `note` says how many products the statistics use, and `productsPublishedLast30Days`, vendors and prices describe those products only. `productCount` is not affected: it is the store's own number.
- **`themeAppExtensions` and `scriptHints` are hints, not a full app list.** They show only apps that load something on the home page. Apps that work in the admin, at checkout or on other pages leave no trace there.
- **Social links are the ones present on the home page.** Share buttons and links to single posts are skipped. A store with no such links gets `null`.
- Shopify does not publish revenue, traffic, order counts or stock quantities, and this Actor does not estimate them.
- Some stores switch `/meta.json` off. They still get a row from the product list and the home page; store name, country and currency are then `null`, and `productCount` is given only when the whole list was read.

### Input

| Field | What it does |
|---|---|
| `stores` | Stores to analyze, one per line: a domain (`allbirds.com`) or any URL of the store (only the domain is used). Up to 200 per run. Empty = one example store. |
| `maxProductsPerStore` | How many products per store are read for the statistics (1-5000). Empty = 1000. |

Example:

```json
{ "stores": ["allbirds.com", "kyliecosmetics.com"] }
```

### Sites that are not analyzed

The Actor does not work around stores that do not serve these pages. Each of these comes back as one **free** row with the reason in `note`:

| `status` | Meaning |
|---|---|
| `not-shopify` | no Shopify store profile and no Shopify products were found, and the home page carries no Shopify theme object: another platform, or Shopify behind a custom storefront |
| `shopify-data-not-public` | the home page shows it is a Shopify store, but neither the store profile nor the product list could be read; theme, app hints and social links are still in the row |
| `robots-disallowed` | the store's `robots.txt` disallows every path this Actor uses for all crawlers; nothing was requested |
| `password-protected` | the store is behind a store password |
| `blocked` | the store refused the request (HTTP 403, 429 or 430) also when asked once more through a residential IP address, or showed a bot check page. Check pages are not solved or bypassed |
| `unreadable` | the site did not answer, or answered with errors, also on a second try |
| `duplicate-store` | two inputs led to the same store; it was analyzed once |
| `budget-reached` | the run reached its maximum total charge; the row says what was not returned |
| `bad-input` | the input could not be used; nothing was requested |

When `robots.txt` disallows only some of the paths, those are skipped, the rest is read, and `note` lists what was skipped.

A store that refuses datacenter IP addresses is read through a residential IP address, with one page of its product list (250 products) instead of four, and at most 40 such requests per run; the row says so.

### Pricing

Pay per event: one `store-analyzed` event for each store row with `status` ok. Rows with any other status are free. There is no start fee.

A run stops when it reaches the maximum total charge you set for it; stores that were not reached are not requested and not charged.

### FAQ

**How is this different from a product scraper?** This returns one summary row per store, not the products. For the full product list with variants, SKUs and price or stock changes, use [Shopify Products Scraper & Price Monitor](https://apify.com/neverempty/shopify-products-price-monitor).

**Does it find stores for me?** No. You bring the URLs; it tells you which ones are Shopify stores and what they look like.

**Does it need a proxy?** No setting is needed. Most stores answer directly; the Actor switches to a residential IP address by itself only for a store that refuses the first request.

**Is the app list complete?** No - see above. It is what can be seen on the home page.

# Actor input Schema

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

Stores to analyze, one per line: a domain such as allbirds.com or any URL of the store such as https://www.allbirds.com/collections/mens (only the domain is used). Up to 200 stores per run; each store comes back as one row. The Actor reads the store's robots.txt first and then only /meta.json, /products.json, the home page and, when needed, /collections.json. A site that is not on Shopify, cannot be read or disallows these paths in robots.txt comes back as a free row that says why. If empty, one example store (allbirds.com) is analyzed.

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

How many products of each store are read for the price, vendor and freshness statistics (1-5000, read 250 at a time). If empty, 1000. A store with more products gets statistics for the first products of its list, and the row says so; the product count itself comes from the store profile and is not limited by this.

## Actor input object example

```json
{
  "stores": [
    "allbirds.com",
    "kyliecosmetics.com"
  ],
  "maxProductsPerStore": 1000
}
```

# Actor output Schema

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

One row per store: whether it is a Shopify store, store name, country, city, currency, myshopify domain, description, published product and collection counts, lowest, median and highest price, number of vendors, top vendors and product types, products in stock and on sale, newest product date, products published in the last 30 days, last product update, theme name and version, theme app extensions and script hints found on the home page, and social links. A site that is not on Shopify, could not be read, disallows the paths in robots.txt, an unusable input or a run that hit its maximum charge comes back as a free row that says why.

# 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 = {
    "stores": [
        "allbirds.com",
        "kyliecosmetics.com"
    ],
    "maxProductsPerStore": 1000
};

// Run the Actor and wait for it to finish
const run = await client.actor("neverempty/shopify-store-inspector").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 = {
    "stores": [
        "allbirds.com",
        "kyliecosmetics.com",
    ],
    "maxProductsPerStore": 1000,
}

# Run the Actor and wait for it to finish
run = client.actor("neverempty/shopify-store-inspector").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 '{
  "stores": [
    "allbirds.com",
    "kyliecosmetics.com"
  ],
  "maxProductsPerStore": 1000
}' |
apify call neverempty/shopify-store-inspector --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,neverempty/shopify-store-inspector"
        }
    }
}
```

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/qa5Wd98lNJcCFtlnN/builds/JfO4dQOSrJEluNRSu/openapi.json
