# Shopify Best Sellers — Ranked Products from Any Store (`tidyfeed/shopify-best-sellers`) Actor

Read the bestseller collection a Shopify store publishes, in the store's own ranking order. Rank, price, discount and stock for every product. Finds the collection even when its address is not /best-sellers.

- **URL**: https://apify.com/tidyfeed/shopify-best-sellers.md
- **Developed by:** [tidyfeed](https://apify.com/tidyfeed) (community)
- **Categories:**
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $7.00 / 1,000 products

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?

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 Best Sellers — Ranked Products from Any Store

**Paste a store address. Get its bestseller list, in the order the store itself ranks it.**

Rank, product, price, discount and stock — one row each, ready for a spreadsheet. Add several brands and see what each of them is pushing to the top, side by side.

No API key. No login. No Shopify partner account. No proxies.

***

### The two things that make it work

#### 1. The address almost never matches the title

Read on 2 September 2026:

| Store | Collection it shows you | Address it actually lives at |
|---|---|---|
| gymshark.com | Best Sellers | `/collections/most-popular` |
| allbirds.com | Men's Bestsellers | `/collections/mens-bestsellers` |
| vuoriclothing.com | Men's Best Sellers | `/collections/best-sellers` |

A tool that guesses `/collections/best-sellers` misses Gymshark entirely and reports that the store has no bestsellers. This Actor reads the store's own published collection list first and matches on **both** the title and the address.

#### 2. Stores leave their own workshop lying around

The public collection list is full of things no shopper ever sees — staging copies, merchandising-tool records, last season's gift guide. Picking the wrong one looks like a broken tool.

Measured across twelve live stores on 9 September 2026, here is what a naive "highest match wins" approach returns versus what this Actor returns:

| Store | Naive pick | What you get here |
|---|---|---|
| glossier.com | "Bestsellers **TEST**" | **"Best-sellers"** (15 products) |
| rothys.com | "Trending **(Test)**" — 4 products | **"Best Sellers"** (25) |
| brooklinen.com | "**Collection Data** - Best Sellers **Prospect HP Refresh**" | **"Best Sellers"** |
| kotn.com | "**2025** Best-Sellers" | **"Men's Best Sellers"** |
| vuoriclothing.com | "Men's Best Seller **Gifts**" | **"Men's Best Sellers"** |
| gymshark.com | "Best Sellers" — **1 product** | **"Most Loved"** (25) |

Staging and internal collections are excluded outright. Gift guides, sale cuts and dated editions are kept but ranked behind the plain list. A collection holding almost nothing loses to a fuller one, because a one-row answer is not an answer.

If a store's *only* ranked collection is an internal one, you still get it — something beats nothing.

### What you get

One row per ranked product:

**Where it sits** — `rank`, `collectionTitle`, `collectionHandle`, `collectionUrl`

**What it is** — `productTitle`, `vendor`, `productType`, `tags`, `productUrl`, `imageUrl`, `skus`

**What it costs** — `minPrice`, `maxPrice`, `maxCompareAtPrice`, `discountPercent`, `onSale`

**Whether you can buy it** — `variantCount`, `availableVariantCount`, `anyAvailable`

Prices arrive as numbers, not strings, so a spreadsheet can add them up without cleaning.

***

### What `rank` means, exactly

`rank` is the position the store publishes the product at inside that collection. It is the merchant's own ordering.

It is **not** an estimate of units sold, and this actor does not pretend otherwise. Shopify does not publish sales figures to anyone, and any tool that shows you a sales number for a store it does not own is guessing.

What you are reading is the list the brand chose to put in front of every visitor under the heading "Best Sellers" — which, for competitive research, is usually the more useful thing anyway.

***

### Typical uses

- **Find what a category is actually selling.** Run it across 20 brands in one niche and read the top 10 of each.
- **Watch a rival's front page over time.** Schedule it weekly; when a product climbs or drops out, you see it.
- **Price a launch.** The bestseller list is where a brand's real price points sit, not the outliers.
- **Feed a shortlist into the full catalog.** Once a store looks interesting, `tidyfeed/shopify-product-scraper` pulls its entire catalog with every variant.

***

### Input

| Field | What it does |
|---|---|
| `storeUrls` | Store addresses. Normal website addresses are fine. |
| `collectionHandles` | Leave empty to auto-find. Fill in to read specific collections instead — `most-popular`, `new-arrivals`, anything. |
| `maxCollectionsPerStore` | Some stores rank several lists. Caps how many are read, strongest match first. Default 2. |
| `maxProductsPerCollection` | How far down the ranking to read. Default 100. |
| `onlyAvailable` | Drop sold-out products. |
| `includeDescription` | Add the description as plain text. |

Leaving `collectionHandles` empty is the interesting mode. Filling it in turns this into a plain "read this collection in order" tool, which is also useful.

***

### What it costs

Billed per ranked product delivered. A store with no bestseller collection returns nothing and costs nothing beyond the run start.

Platform usage is included — no separate compute bill. There are no proxy costs because none are needed.

***

### How it works

Shopify serves two public JSON feeds on every storefront: the collection list at `/collections.json` and each collection's products at `/collections/<handle>/products.json`. The second returns products in the order the merchant arranged them. This actor reads the first to find the right collection, then walks the second.

**Headless storefronts are followed to their real shop.** Brands running a custom front end answer `/collections.json` with a web page instead of a feed. This actor reads the shop address the site publishes in its own markup and continues from there.

No HTML parsing means a theme change cannot break it.

***

### Honest limits

- **Stores that sell one product per colour will repeat the same style.** Shopify has no notion of a parent product, so a brand like allbirds.com lists every colourway separately and its bestseller list reads "Tree Runner" five times in different shades. The storefront collapses those into one card with swatches; the feed does not, and neither do we — inventing a grouping would be guessing. Group by `productType` or by the common part of `productTitle` if you need one row per style.
- **A collection's order is the merchant's order.** If a store curates its bestseller page by hand, that hand-curated order is what you get. There is no way to tell from the outside which stores sort by real sales and which arrange it themselves — so treat `rank` as "what they show", not "what sold".
- **Some stores publish no ranked collection at all.** The run says so per store and bills nothing for it. Pass `collectionHandles` to point at something yourself.
- **Stock is what the feed publishes, from the United States.** Shopify exposes an in-stock flag per variant, never a quantity, and for stores running separate regional markets that flag reflects the market the request lands in. Runs here originate from US servers. Prices, discounts and ranking are unaffected.
- **Currency is not published in the feed**, so prices are plain numbers in the store's own currency.
- **Shopify's own `products_count` for a collection is unreliable** and is passed through under the name `collectionProductsCountReported` rather than being presented as a product count. Measured on 2 September 2026: allbirds.com reports 4,143 products in "All Products" and publishes 293. The rows this actor returns are counted, not reported.
- **Password-protected and pre-launch stores return nothing**, with a reason per store.

***

### Scheduling

Rankings move. Schedule it weekly against a list of competitors and each run leaves a dated snapshot — the shape of a category over a season is worth more than any single read.

***

### Legal

This actor reads only data a Shopify store publishes publicly, at addresses the store itself serves to anyone. It collects no personal data, requires no login, and bypasses no access control. You remain responsible for how you use the exported data.

***

Questions, or a store that behaves oddly? Open an issue on the actor — issues are read and answered.

# Actor input Schema

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

One or more Shopify store addresses. Paste the normal website address — https://deathwishcoffee.com. No API key, login or Shopify partner account is needed. Stores running a custom front end are resolved to their Shopify shop automatically.

## `collectionHandles` (type: `array`):

Leave empty and the Actor finds the store's own bestseller collection for you. Fill it in to read specific collections instead — use the last part of the collection address, for example 'most-popular' from /collections/most-popular. Applied to every store in the list.

## `maxCollectionsPerStore` (type: `integer`):

Some stores publish several ranked lists (men's, women's, overall). This caps how many are read per store, strongest match first. Ignored when you supply collection addresses yourself.

## `maxProductsPerCollection` (type: `integer`):

How far down the ranking to read. The top 20-50 is usually where the useful signal is.

## `onlyAvailable` (type: `boolean`):

Leave out products with no variant in stock. Note that stock is reported for the region the run happens from, which is the United States.

## `includeDescription` (type: `boolean`):

Add the product description as plain text. Off by default because it makes spreadsheets hard to read.

## Actor input object example

```json
{
  "storeUrls": [
    "https://deathwishcoffee.com",
    "https://allbirds.com"
  ],
  "collectionHandles": [
    "most-popular",
    "new-arrivals"
  ],
  "maxCollectionsPerStore": 2,
  "maxProductsPerCollection": 100,
  "onlyAvailable": false,
  "includeDescription": false
}
```

# Actor output Schema

## `bestSellers` (type: `string`):

No description

## `bestSellersCsv` (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 = {
    "storeUrls": [
        "https://deathwishcoffee.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tidyfeed/shopify-best-sellers").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://deathwishcoffee.com"] }

# Run the Actor and wait for it to finish
run = client.actor("tidyfeed/shopify-best-sellers").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://deathwishcoffee.com"
  ]
}' |
apify call tidyfeed/shopify-best-sellers --silent --output-dataset

```

## MCP server setup

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

```

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/9Pyhyez3qK89zvfwh/builds/igYD2G151WA4bRHIx/openapi.json
