# Shopify Trend Tracker (`xtracto/shopify-trend-tracker`) Actor

Track what's trending on any Shopify store: best sellers (the store's own ranking), new arrivals, and price drops. No account or API key needed.

- **URL**: https://apify.com/xtracto/shopify-trend-tracker.md
- **Developed by:** [Farhan Febrian Nauval](https://apify.com/xtracto) (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 $10.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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 Trend Tracker

See what's actually trending on any Shopify store — best sellers, brand-new products, and items currently on sale — pulled straight from the store's own public catalog.

### Why use this actor

- **No account, no login, no key** — just give it a store address.
- **Works with any Shopify store** — one actor, no per-store setup.
- **Real signals, not guesses.** Best sellers use the store's own "Best selling" sort order — the same ranking shoppers see on the site. New arrivals use the date the store itself published each product. Price drops use the store's own "was / now" pricing.
- **Three focused modes** in one actor — pick the one you need, or run all three.
- **Ready-to-use JSON** — a clean summary per product, plus every size/color variant, image and price detail.
- **Runs on a schedule** with automatic retries; export to JSON, CSV or Excel.

### How it works

1. You enter one or more Shopify store addresses and pick a mode.
2. **Best sellers** — the actor reads the store's own "sorted by best selling" shopping page and reports the products in the exact order the store put them in, numbered 1, 2, 3…
3. **New arrivals** — the actor reads the store's full product catalog and returns the most recently added products first, with how many days old each one is.
4. **Price drops** — the actor reads the full catalog and returns every product where the store is showing a "was" price above the current price, with the discount worked out for you.
5. Results stream into your dataset as they're found — download any time.

You don't manage any scrapers or browsers — just enter a store, pick a mode, and press Run.

### A note on "best sellers" — please read

Some stores don't show their full product list on the "Best selling" page itself (a minority of storefronts load their product grid in a way this actor can't read). On those stores, best-seller mode can't find a genuine ranking, so instead of guessing it returns a clear note that the ranking isn't available for that store — new arrivals and price drops are unaffected and work on every public Shopify store we've tested. Also note: the best-seller order reflects **the store's own ranking**, not independently verified sales figures — Shopify stores decide this order themselves (usually based on their own sales data), and this actor simply reads and reports it.

### Input

#### Mode: Best sellers

```json
{
    "storeUrls": ["https://deathwishcoffee.com"],
    "mode": "bestsellers",
    "maxItems": 10,
    "maxItemsPerStore": 0,
    "limit": 250
}
```

#### Mode: New arrivals

```json
{
    "storeUrls": ["https://deathwishcoffee.com"],
    "mode": "new-arrivals",
    "maxItems": 10,
    "maxItemsPerStore": 0,
    "limit": 250
}
```

#### Mode: Price drops

```json
{
    "storeUrls": ["https://deathwishcoffee.com"],
    "mode": "price-drops",
    "maxItems": 10,
    "maxItemsPerStore": 0,
    "limit": 250
}
```

| Field | Type | Description |
| --- | --- | --- |
| `storeUrls` | array | Store addresses or bare domains, e.g. `https://www.allbirds.com` or `allbirds.com`. |
| `mode` | string | `bestsellers` — the store's own best-selling order. `new-arrivals` (default) — newest products first. `price-drops` — products currently on sale. |
| `maxItems` | integer | Total result cap across everything. `0` = no cap. |
| `maxItemsPerStore` | integer | Cap per store. `0` = no cap. Handy to sample many stores evenly. |
| `limit` | integer | Products fetched per page request while reading the catalog (max 250). Leave at 250 for speed. |
| `proxyConfiguration` | object | Optional. The catalog is public, so usually not needed; turn on Residential for stores that block datacenter traffic. |

### Output

#### Best sellers — real output from `deathwishcoffee.com`

```json
{
    "_input": "https://deathwishcoffee.com",
    "_source": "S1-bestsellers",
    "_scrapedAt": "2026-08-06T09:32:11Z",
    "id": 4488392933431,
    "title": "Organic Cold Brew Coffee, Unsweetened",
    "handle": "organic-cold-brew-coffee-unsweetened",
    "vendor": "Death Wish Coffee",
    "productType": "Ready to Drink",
    "createdAt": "2022-05-18T09:41:19-04:00",
    "publishedAt": "2022-05-18T09:41:33-04:00",
    "url": "https://deathwishcoffee.com/products/organic-cold-brew-coffee-unsweetened",
    "minPrice": 39.99,
    "maxPrice": 39.99,
    "variantsCount": 1,
    "imagesCount": 4,
    "storeHost": "deathwishcoffee.com",
    "bestsellerRank": 1,
    "variants": [ { "id": 32819415105655, "sku": "COLDBREW12CT", "price": "39.99", "available": true } ],
    "images": [ { "src": "https://cdn.shopify.com/s/files/1/0271/7209/files/DW_ColdBrew_Bottle_01.jpg" } ],
    "options": [ { "name": "Title", "position": 1, "values": ["Default Title"] } ]
}
```

#### New arrivals — real output from `deathwishcoffee.com`

```json
{
    "_input": "https://deathwishcoffee.com",
    "_source": "S1-new-arrivals",
    "_scrapedAt": "2026-08-06T09:28:57Z",
    "id": 7448261034039,
    "title": "Coffee Consultation Tumbler",
    "handle": "grey-plastic-tumbler-im-not-ignoring-you-meme",
    "vendor": "Planetary Design",
    "productType": "On-The-Go Drinkware",
    "tags": ["Accessories", "Merch", "OTG"],
    "createdAt": "2026-04-28T10:48:20-04:00",
    "updatedAt": "2026-08-06T04:51:28-04:00",
    "publishedAt": "2026-07-29T11:35:07-04:00",
    "url": "https://deathwishcoffee.com/products/grey-plastic-tumbler-im-not-ignoring-you-meme",
    "minPrice": 20.0,
    "maxPrice": 20.0,
    "variantsCount": 1,
    "imagesCount": 3,
    "firstImage": "https://cdn.shopify.com/s/files/1/0271/7209/files/DeathWishCoffee_July2026_Product_MemeTumbler_Front_Web.jpg?v=1784910460",
    "storeHost": "deathwishcoffee.com",
    "daysOld": 99,
    "variants": [ "... 1 variant" ],
    "images": [ "... 3 more" ],
    "options": [ { "name": "Title", "position": 1, "values": ["Default Title"] } ]
}
```

#### Price drops — real output from `deathwishcoffee.com`

```json
{
    "_input": "https://deathwishcoffee.com",
    "_source": "S1-price-drops",
    "_scrapedAt": "2026-08-06T09:28:57Z",
    "id": 7218414092343,
    "title": "Rebellious By Nature Trucker",
    "handle": "rebellious-by-nature-trucker",
    "vendor": "Sportiqe",
    "productType": "Accessories",
    "tags": ["Accessories", "Apparel", "Gifting", "Merch", "Website Exclusive Sale"],
    "createdAt": "2025-01-23T13:20:49-05:00",
    "updatedAt": "2026-08-06T04:51:28-04:00",
    "url": "https://deathwishcoffee.com/products/rebellious-by-nature-trucker",
    "minPrice": 17.5,
    "maxPrice": 17.5,
    "storeHost": "deathwishcoffee.com",
    "discountedPrice": 17.5,
    "compareAtPrice": 25.0,
    "discountPercent": 30.0,
    "variants": [ "... 1 variant" ],
    "images": [ "... 5 more" ],
    "options": [ { "name": "Title", "position": 1, "values": ["Default Title"] } ]
}
```

| Field | Type | Description |
| --- | --- | --- |
| `_input` | string | The store you entered (for traceability). |
| `_source` | string | Which mode produced the row, e.g. `S1-bestsellers`. |
| `_scrapedAt` | string | UTC timestamp of the fetch. |
| `id` / `title` / `handle` / `vendor` / `productType` / `tags` | — | Standard product info, straight from the store. |
| `createdAt` / `updatedAt` / `publishedAt` | string | The store's own dates for when the product was added / last changed / went live. |
| `url` | string | Direct link to the product page. |
| `minPrice` / `maxPrice` | number | Lowest / highest variant price. |
| `variantsCount` / `imagesCount` | number | How many size/color variants and images the product has. |
| `storeHost` | string | The store's domain. |
| `bestsellerRank` | number | *(bestsellers mode only)* Position in the store's own best-selling order — 1 is the top seller. |
| `daysOld` | number | *(new-arrivals mode only)* Days since the store added this product. |
| `discountedPrice` / `compareAtPrice` / `discountPercent` | number | *(price-drops mode only)* Current price, the store's listed "was" price, and the percentage off. |
| `variants` / `images` / `options` | array | Full raw detail exactly as the store provides it. |

If a store keeps its catalog private, or best-seller mode can't find a real ranking on a particular store, you'll get a clear note instead of guessed data:

```json
{
    "_input": "https://www.allbirds.com",
    "_source": "S1-bestsellers",
    "_error": "bestseller_rank_unavailable",
    "_errorDetail": "the 'best selling' and 'newest' sort options returned the exact same product order — this store's theme ignores sort order, so there's no real bestseller signal to report"
}
```

```json
{
    "_input": "www.gymshark.com",
    "_source": "S1-new-arrivals",
    "_error": "blocked_or_not_shopify",
    "_errorDetail": "fetched 0 before failure"
}
```

### Notes / limits

- **New arrivals and price drops work on every public Shopify store** we tested (verified: allbirds.com, deathwishcoffee.com, redbullshopus.com, kyliecosmetics.com, fashionnova.com).
- **Best sellers is best-effort per store.** It's verified working with real, distinct rankings on deathwishcoffee.com and kyliecosmetics.com. On stores whose theme doesn't list products on the sorted page itself (verified example: allbirds.com), it reports `bestseller_rank_unavailable` rather than making up a rank.
- **The best-seller order is the store's own ranking**, not independently verified sales data — this actor reads what the store itself already publishes.
- **Prices** are shown in the store's own currency and format.
- **A minority of stores keep their catalog private** and will return a `blocked_or_not_shopify` note instead of products.
- **Proxy** is optional. If a store blocks datacenter traffic, enable Residential in the proxy settings.

# Actor input Schema

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

One or more Shopify store URLs or bare domains (e.g. 'https://www.allbirds.com' or 'allbirds.com').

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

'Best sellers' reads the store's own best-selling order from its shopping page. 'New arrivals' sorts the catalog by newest first. 'Price drops' finds products currently on sale.

## `maxItems` (type: `integer`):

Total result cap across all stores. 0 means no cap.

## `maxItemsPerStore` (type: `integer`):

Per-store result cap. 0 means no cap. Handy to sample many stores evenly.

## `limit` (type: `integer`):

How many products to fetch per page request while reading the catalog. Maximum 250. Leave at 250 for fastest results.

## `proxyConfiguration` (type: `object`):

Optional. The product feed is public, so a proxy is usually not needed. Turn on Residential for stores that block datacenter traffic.

## Actor input object example

```json
{
  "storeUrls": [
    "https://deathwishcoffee.com"
  ],
  "mode": "new-arrivals",
  "maxItems": 50,
  "maxItemsPerStore": 0,
  "limit": 250,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `title` (type: `string`):

Title of the item.

## `vendor` (type: `string`):

Vendor as reported by the source.

## `minPrice` (type: `string`):

Min Price as reported by the source.

## `maxPrice` (type: `string`):

Max Price as reported by the source.

## `bestsellerRank` (type: `string`):

Bestseller Rank as reported by the source.

## `daysOld` (type: `string`):

Days Old as reported by the source.

## `discountPercent` (type: `string`):

Discount percentage; 0 when not on sale. Whole number.

## `url` (type: `string`):

Direct link to the scraped item.

## `_scrapedAt` (type: `string`):

UTC timestamp of the scrape, ISO 8601.

## `id` (type: `string`):

Unique identifier of the item at the source.

## `handle` (type: `string`):

Account handle.

## `productType` (type: `string`):

Product Type as reported by the source.

## `createdAt` (type: `string`):

Creation timestamp, ISO 8601.

## `publishedAt` (type: `string`):

Publication timestamp, ISO 8601.

## `variantsCount` (type: `string`):

Variants Count. Whole number.

## `imagesCount` (type: `string`):

Images Count. Whole number.

## `storeHost` (type: `string`):

Store Host as reported by the source.

## `variants` (type: `string`):

Variants.

## `images` (type: `string`):

Image URLs. List of values.

## `options` (type: `string`):

Options.

## `tags` (type: `string`):

Tags or keywords. List of values.

## `updatedAt` (type: `string`):

Last-updated timestamp, ISO 8601.

## `firstImage` (type: `string`):

First Image as reported by the source.

## `discountedPrice` (type: `string`):

Discounted Price as reported by the source.

## `compareAtPrice` (type: `string`):

Compare At Price as reported by the source.

## `_input` (type: `string`):

The input value this row was produced from.

## `_source` (type: `string`):

Which extraction strategy produced the row.

## `_error` (type: `string`):

Set only on diagnostic rows - why that target produced no data.

## `_errorDetail` (type: `string`):

Extra context for the error.

# 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"
    ],
    "mode": "new-arrivals",
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("xtracto/shopify-trend-tracker").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"],
    "mode": "new-arrivals",
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("xtracto/shopify-trend-tracker").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"
  ],
  "mode": "new-arrivals",
  "maxItems": 50
}' |
apify call xtracto/shopify-trend-tracker --silent --output-dataset

```

## MCP server setup

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

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/zuVREWWksQQVZRbCf/builds/eZQOrE0zleGCI0x0P/openapi.json
