# Shopify Trending Products Scraper (`badr_xba/shopify-trending-products-scraper`) Actor

Find trending products on any public Shopify store: best-seller collections, new arrivals, sold-out variants, discounts and cross-store duplicates in one explainable Trend Score. History between runs, HTML dashboard, 79 curated stores.

- **URL**: https://apify.com/badr_xba/shopify-trending-products-scraper.md
- **Developed by:** [Badr Bouargan](https://apify.com/badr_xba) (community)
- **Categories:** E-commerce, Marketing, Automation
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.99 / 1,000 trending product (lead)s

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 Trending Products Scraper – Best Sellers, New Arrivals & Trend Score

![Shopify Trending Products Scraper: visual report of a real run, key figures and charts](https://api.apify.com/v2/key-value-stores/R1P4OnWyoV0LnGBin/records/shopify-trending-products-scraper-overview.png)

**Paste any Shopify store (or pick a category of well-known stores) and get its products ranked by an explainable Trend Score: what the merchant lists as best-seller, what is new, what is selling out, what is discounted and what several stores sell at once.**

**The problem it solves.** Shopify stores do not publish sales numbers, and "best selling" sorting is blocked for crawlers by Shopify's own robots.txt. Product researchers end up clicking through stores by hand and guessing. This Actor reads the public product JSON every Shopify store exposes – only where the store's robots.txt allows it – and turns it into a clean table where each product carries the signals behind its score, so you can see *why* something looks like it is trending.

**Who it is for.** Dropshippers and e-commerce entrepreneurs looking for winning products; product researchers and market researchers watching competitors; agencies preparing product or pricing audits; Shopify developers and analysts who need store catalogs as data; AI agents that need Shopify product data through an API.

**What you get, per product:** `title`, `url`, `price`, `compareAtPrice`, `discountPercent`, `currency` (+ optional converted price), `vendor`, `productType`, derived `category`, `tags`, `available` / `availableVariants`, `createdAt` / `publishedAt`, store name, country and currency, the merchant `collections` it appears in (with its position), SKUs / barcodes / GTINs, **`trendScore` 0–100, `trendLevel`, `trendConfidence` and every `trendSignal` with its evidence**, cross-store matches, history between runs (`isNew`, price / stock / rank changes) and the exact `source` endpoint. Full example below.

### Start in 3 steps

1. Open **Shopify Trending Products Scraper** on Apify Store and click **Try for free**.
2. Paste one or more **Shopify stores** (e.g. `colourpop.com`) – or pick **Curated store categories** such as *Beauty* or *Pets* – and optionally a **Minimum Trend Score**.
3. Click **Start**. Open the **Visual report** (Output tab: product cards with photos, Trend Score and filters) or export the products as Excel, CSV or JSON.

No Shopify account, login, cookies or proxy needed. Empty input runs a small demo on 3 stores (50 products).

### Why choose this Actor

- **An explainable Trend Score, not a black box.** Every row lists its signals – e.g. *"position #3 in Best Sellers (+15, verified)"*, *"4 of 5 variants sold out (+9, inferred)"* – and a score is never built from a single data point.
- **Best-seller lists without breaking the rules.** It reads the merchant's own *Best sellers / Trending / Featured / New arrivals* collections in merchant order, instead of the `sort_by=best-selling` pages that Shopify's robots.txt forbids.
- **Gets better every day.** With history on (default) each run stores a compact snapshot; scheduled runs detect new products, variants selling out, price moves and rank changes in best-seller collections.
- **Cross-store detection.** The same product (GTIN, SKU, image file or near-identical title) found in several stores of your run is flagged – a classic viral / dropshipping signal.
- **79 curated, verified stores** across fashion, beauty, home, fitness, pets, gadgets, food & drink, jewelry, kids and outdoor, so you can start without a store list.
- **Polite and compliant by design.** robots.txt obeyed for every URL (including `Crawl-delay`), ≤ 2 parallel requests and ≥ 1 s between requests per store, honest user agent, no CAPTCHA / password / bot-protection bypass.
- **Filtered products are never charged.** Keywords, categories, price, discount, stock, dates, store country / currency and minimum Trend Score are applied before saving.

### How much it costs

Pay per product saved (pay-per-event). Platform usage is included.

| Event | Free plan | Bronze | Silver | Gold (also Platinum & Diamond) |
| --- | --- | --- | --- | --- |
| Trending product (lead) saved | $0.004792 | $0.004632 | $0.004232 | $0.003992 |
| **Per 1,000 products** | **$4.792** | **$4.632** | **$4.232** | **$3.992** |
| Actor start (once per run) | $0.00005 | $0.00005 | $0.00005 | $0.00005 |

Worked examples: a default run (100 products) ≈ **$0.48** on the Free plan · **1,000 products = $4.79** on Free, **$3.99** on Gold.

**Never charged:** products removed by your filters or below your minimum Trend Score, gift cards and shipping-protection add-ons, duplicates, invalid inputs, and stores that are blocked, password-protected, disallowed by robots.txt or not Shopify (all listed in `FAILED_INPUTS`). Set *Maximum cost per run* when you start the Actor and it stops cleanly at that amount.

### Use cases

- **Winning-product research:** run a category (e.g. *Beauty* + *Jewelry*), keep `minTrendScore` 60+, look for `crossStoreCount ≥ 2` and recent `publishedAt`.
- **Competitor launch monitoring:** schedule your competitors daily with *Sort by: Recently detected* – `newSinceLastRun` marks every product they added since the previous run.
- **Stock-out watch:** history shows `variants sold out since last run` – an early sign of demand (or of a limited drop).
- **Discount hunting:** `minDiscountPercent: 30` + `sortBy: discountDesc`, prices converted to your currency.
- **Catalog and price audits for agencies:** every product of a store with variants, SKUs, barcodes, collections and prices, as Excel.

### Trend Score – how it works

Points from eight independent signal groups are added up; each group has a maximum and the total is capped at 100.

| # | Signal group | Max | Kind | What earns points |
| --- | --- | --- | --- | --- |
| 1 | Merchant curation | 40 | verified | In a collection named best-sellers / top-sellers (25), trending / popular / viral (18), featured / staff picks (10), new arrivals (8); position in that collection: top 3 +15, top 10 +10, top 25 +6, top 50 +3. *This is the merchant's own list, not a sales count.* |
| 2 | Merchant tags | 15 | verified | Tag `bestseller` / `best-seller` (15), `trending` / `viral` / `hot` (12), `popular` (10), `new` (6). |
| 3 | Recency | 20 | verified | Published ≤ 7 days (20), ≤ 30 days (14), ≤ 90 days (7); re-published old products get at most 5. |
| 4 | Availability pressure | 12 | inferred | Share of variants sold out on a product still on sale (≥ 50 %: 9, ≥ 25 %: 6, else 3); +3 if published in the last 30 days. |
| 5 | Pricing | 12 | verified + inferred | Discount vs compare-at price (≥ 50 %: 8, ≥ 30 %: 6, ≥ 15 %: 4, ≥ 5 %: 2); cheapest quarter of its category in this run (+4) or cheaper half (+2), same currency, ≥ 10 products. |
| 6 | Cross-store occurrence | 20 | inferred | Same GTIN, SKU, image file or near-identical title in 2 stores (14) or 3+ stores (20) of the run. |
| 7 | Category demand | 8 | inferred | The product's category appears in best-seller / trending collections of 3+ stores (8) or 2 stores (5). |
| 8 | History / growth | 25 | historical | Needs a previous run: newly added (4), variants sold out since last run (3 each, max 10), entered a best-seller list (8), rank improved (2–8), stays in best-seller lists (2 per run, max 6), price increased (3) or decreased (2). |

**Rules:** one contributing group caps the score at 49 ("insufficient signals"); 70+ needs at least 2 groups and 90+ at least 3. `trendConfidence` is *low* (1 group), *medium* (2–3) or *high* (4+). Levels: **Strong trend signals** 90–100 · **High potential** 80–89 · **Promising** 70–79 · **Moderate** 50–69 · **Weak or insufficient signals** < 50. Seasonal products (Christmas, Black Friday, summer, Halloween, Valentine's, back-to-school…, from title, tags or collections) get a `seasonal` flag with 0 points.

**Popularity is not sales volume.** Shopify does not publish sales; this Actor never outputs or estimates sales numbers. The score combines what the merchant shows publicly.

### Input examples

**Quick start – your stores**

```json
{
  "storeUrls": ["colourpop.com", "www.deathwishcoffee.com", "wildone.com"],
  "maxProductsPerStore": 250,
  "maxItems": 200
}
```

**Category research on curated stores, strong products only**

```json
{
  "seedCategories": ["beauty", "jewelry", "outdoor"],
  "maxStores": 6,
  "minTrendScore": 55,
  "sortBy": "trendScore"
}
```

**New products of the last 30 days (schedule it daily)**

```json
{
  "seedCategories": ["fashion", "beauty"],
  "createdWithinDays": 30,
  "sortBy": "newest",
  "historyStoreName": "my-fashion-watch"
}
```

**Discounts across currencies, in USD**

```json
{
  "storeUrls": ["www.ohpolly.com", "snocks.com", "peppermayo.com", "kotn.com"],
  "minDiscountPercent": 30,
  "onlyAvailable": true,
  "convertCurrencyTo": "USD",
  "priceCurrency": "USD",
  "maxPrice": 60,
  "sortBy": "discountDesc"
}
```

**One collection or one product**

```json
{ "storeUrls": ["https://colourpop.com/collections/best-sellers", "https://colourpop.com/products/swerve-creme-gel-liner"] }
```

### Input parameters

| Field | Description |
| --- | --- |
| `storeUrls` | Store domains or URLs (myshopify domains, collection or product URLs accepted). |
| `seedCategories` | Add curated stores: `fashion`, `beauty`, `home`, `fitness`, `pets`, `electronics`, `food`, `jewelry`, `kids`, `outdoor`. |
| `maxStores` / `maxProductsPerStore` / `maxItems` | Limits (default 10 / 250 / 100; raise `maxItems` for bigger runs, `maxItems: 0` = no limit). |
| `minTrendScore`, `sortBy` | `trendScore`, `priceAsc`, `priceDesc`, `discountDesc`, `newest`, `recentlyDetected`, `growth`. |
| `includeCollections`, `maxCollectionsPerStore` | `curated` (default), `all` or `off`; collections read per store (default 8). |
| `useHistory`, `historyStoreName` | Snapshots between runs (default on, `shopify-trending-history`). |
| `keywords`, `excludeKeywords`, `categories`, `productTypes`, `vendors`, `tags` | Product filters. |
| `minPrice`, `maxPrice`, `priceCurrency`, `minDiscountPercent`, `onlyAvailable` | Price and stock filters. |
| `createdWithinDays`, `createdAfter`, `createdBefore`, `dateField` | Date filters on `publishedAt` (default), `createdAt` or `updatedAt`. |
| `currencies`, `countries` | Store filters from `/meta.json` (skipped stores cost one request). |
| `includeVariants`, `includeDescription`, `convertCurrencyTo`, `excludeNonProducts` | Output options. |
| `maxConcurrency`, `requestTimeoutSecs`, `maxRetries`, `proxyConfiguration` | Advanced (proxy off by default). |

Invalid values never crash the run: they are listed in `FAILED_INPUTS` with an explanation and the default is used.

### Output example

![Shopify Trending Products Scraper: result cards from a real run](https://api.apify.com/v2/key-value-stores/R1P4OnWyoV0LnGBin/records/shopify-trending-products-scraper-results.png)

*Screenshots from a real platform run.*

A real row (store `kotn.com`, `convertCurrencyTo: "USD"`), arrays shortened:

```json
{
  "title": "Women's Off Shoulder Tee in Sorbet",
  "url": "https://kotn.com/products/womens-off-shoulder-tee-in-sorbet",
  "productId": "15112469741936",
  "imageUrl": "https://cdn.shopify.com/s/files/1/0932/1356/files/WOMENS_OFF_SHOULDER_TEE_SORBET_02_1b2841d7-73e6-405a-b6a9-6a629f5c57a9.jpg?v=1783437308",
  "price": 39, "compareAtPrice": 48, "discountPercent": 19, "currency": "CAD",
  "priceConverted": { "amount": 27.73, "currency": "USD", "rate": 0.71092, "rateDate": "2026-11-06", "note": "Estimate for comparison only (ECB euro reference rate of that date); the store charges its own currency." },
  "vendor": "Kotn", "productType": null, "category": "Fashion", "categorySource": "tags",
  "tags": ["15-off-reg", "all-tops", "best-seller", "final-sale", "last-chance", "sale"],
  "variantsCount": 5, "availableVariants": 1, "available": true,
  "createdAt": "2026-05-13T14:12:03.000Z", "publishedAt": "2026-06-03T15:44:55.000Z",
  "storeName": "Kotn", "storeDomain": "kotn.com", "storeCountry": "CA", "storeCurrency": "CAD",
  "collections": [
    { "handle": "womens-best-sellers", "title": "Women's Best Sellers", "position": 7, "curation": "bestseller", "seasonal": false },
    { "handle": "womens-new-arrivals-ads-2026", "title": "Women's New Arrivals Ads 2026", "position": 5, "curation": "new", "seasonal": false }
  ],
  "identifiers": { "skus": ["1.26.2.2.1.878.806.3", "…"], "barcodes": [], "gtins": [] },
  "trendScore": 80, "trendLevel": "High potential", "trendConfidence": "high", "trendGroups": 5,
  "trendSignals": [
    { "group": "curation", "signal": "in best-seller collection", "points": 25, "kind": "verified", "value": "womens-best-sellers",
      "evidence": "Listed by the merchant in the collection \"Women's Best Sellers\" (/collections/womens-best-sellers). This is merchant curation, not a sales count." },
    { "group": "curation", "signal": "position #7 in best-seller collection", "points": 10, "kind": "verified", "value": 7, "evidence": "…" },
    { "group": "tags", "signal": "best-seller tag", "points": 15, "kind": "verified", "value": "best-seller", "evidence": "Merchant tag \"best-seller\"." },
    { "group": "availability", "signal": "variants sold out", "points": 9, "kind": "inferred", "value": 80,
      "evidence": "4 of 5 variants are sold out while the product is still on sale. Could mean demand – or limited stock." },
    { "group": "pricing", "signal": "discount", "points": 4, "kind": "verified", "value": 19, "evidence": "19% off: price 39 vs compare-at 48 CAD." },
    { "group": "categoryDemand", "signal": "category in best-seller lists of several stores", "points": 8, "kind": "inferred", "value": 4, "evidence": "…" }
  ],
  "seasonal": false, "crossStoreCount": 1, "crossStoreDomains": [],
  "history": null, "isNew": null, "newSinceLastRun": null,
  "source": { "endpoint": "https://kotn.com/collections/womens-best-sellers/products.json?limit=250&page=1", "fetchedAt": "2026-11-07T21:08:27.381Z" },
  "dataNotes": []
}
```

Each row also lists the product's **options** with their values (e.g. `[{"name": "Size", "values": ["S", "M", "L"]}]`, empty for single-variant products). With `includeVariants`, every variant additionally carries `weightGrams`, `requiresShipping` and its own photo `imageUrl` (null when the store gives none), all from the store's public product JSON.

Dataset views (with product thumbnails): **Overview**, **Trending** (score & signals), **Pricing**, **History & growth**, **Options, variants & identifiers**. The key-value store also holds **REPORT** (the visual report below), **RUN_SUMMARY** (the run numbers as JSON) and **FAILED_INPUTS**.

### Visual report

Every run also saves a **visual report**: one self-contained web page to browse the products you just collected, no spreadsheet needed. Open it from the run's **Output** tab → **Visual report** (or the key-value store record `REPORT`).

- **Product cards** with the product photos (click for a full-size gallery with arrows, keyboard and swipe), price, compare-at price and discount, the **Trend Score** badge, its level and confidence, the top signals as chips and an expandable **"Why this score"** panel listing every signal with its points, its kind (verified / inferred / historical) and its evidence.
- **Filters and sorting:** search, store, country, category, brand, trend level, a **minimum Trend Score slider**, on sale, new since last run, increasing signals, signal kind and confidence; sort by Trend Score, newest, biggest discount, price or growth. Cards or table view, pagination.
- **Compare** up to 4 products side by side (best values highlighted).
- **Key figures and charts** that follow your filters: products, median Trend Score, share with a score of 50+, median price, share on sale, stores; Trend Score and discount distributions, top categories.
- **Run details:** execution time, requests and success rate, retries, rate limits, peak memory and CPU, the fetched → filtered → saved funnel, every store with its status, and the distributions by category, country, trend level and confidence. Failed inputs are listed at the top.
- **Export** the filtered products as CSV or JSON from the page, or download the full dataset (JSON, CSV, Excel).
- **Live progress:** while the run is in progress the report shows the stores analysed so far (progress bar), the products saved so far and refreshes itself every 30 s (at most one update per minute).
- **Warnings & errors panel** at the top: failed stores grouped by error code (password protected, not Shopify, blocked...) with counts.
- **Data-quality panel:** how complete the key fields are (title, price, currency, stock status, category, brand, published date, store country) and the share of products with a photo.

Photos are loaded in your browser from each store's own Shopify CDN (nothing is copied or re-hosted) and may disappear if the store removes them; a product without a photo shows a neutral placeholder. The report holds up to 2,000 products (up to 3 photos each, main photo first); bigger runs show a notice and a link to the full dataset. Light and dark mode, works on phones.

### Ready-made tasks

| Task | What it does |
| --- | --- |
| Trending Products Discovery | Beauty, fashion and home stores ranked by Trend Score. |
| New Shopify Products | Products published in the last 30 days, newest first – schedule daily. |
| Discounted Products Finder | In-stock products ≥ 30 % off, in USD. |
| Products by Category | Pet products from curated pet stores. |
| High Trend Score Products | Only products scoring 55+ (always ≥ 2 signal groups). |
| Shopify Product Research | Two stores in depth: all collections, variants, SKUs and barcodes, keyword filter. |

### Use it from code, Make, Zapier, n8n or AI agents

**Python**

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("badr_xba/shopify-trending-products-scraper").call(run_input={
    "seedCategories": ["beauty"], "minTrendScore": 60, "maxItems": 100,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["trendScore"], item["title"], item["storeDomain"])
```

**JavaScript**

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('badr_xba/shopify-trending-products-scraper').call({ storeUrls: ['colourpop.com'], maxItems: 100 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

**No-code:** send results to Google Sheets, Make, Zapier, n8n, Slack or a webhook with Apify integrations; an Apify **Schedule** reruns the same stores daily so the history signals build up.

**AI agents (MCP):** add `https://mcp.apify.com/?tools=badr_xba/shopify-trending-products-scraper` to Claude, ChatGPT or Cursor and ask, for example, "which pet products are trending on these 5 Shopify stores?".

### Architecture (for developers)

Shopify storefronts expose their catalog as JSON (`/products.json?limit=250&page=N`, `/collections.json`, `/collections/<handle>/products.json`, `/meta.json`), so no browser and no crawler framework are needed: a small fetch-based client (per-host rate limiter, retries with exponential backoff and jitter, timeouts, Retry-After handling, manual redirects checked against robots.txt) is faster, cheaper and easier to keep polite than a headless crawler. TypeScript (strict) on Node.js 22, Apify SDK 3. Modules: `robots.ts` (RFC 9309 parser), `http.ts`, `shopify.ts` (detection, pagination with stop conditions, curated collections), `normalize.ts`, `trend.ts`, `history.ts`, `filters.ts`, `report.ts` (visual report config and card), `visualKit.ts` (shared visual report kit, a port of the owner's Python kit 1.0.0; `visualKitAssets.ts` is generated), `seeds.ts`, `run.ts`, `main.ts`. 113 offline tests (`npm test`) with mocked fetch and real Shopify fixtures.

### Limits

- Only **public storefront JSON**. Stores that disabled `/products.json`, protect it with bot challenges or disallow it in robots.txt are skipped and listed in `FAILED_INPUTS` (for example some large brands). Password-protected stores are never accessed.
- Shopify does not expose **sales, revenue or stock quantities**; `available` is per variant (in stock or not), and the Trend Score uses public signals only.
- **Collections:** the first 250 products of each collection are read (merchant order); `position` is the merchant's order, which is not necessarily a sales rank.
- **Currency:** `/products.json` returns prices in the store's default currency; conversions use ECB reference rates (≈ 30 currencies) and are estimates.
- **Speed:** ≤ 1 request per second per store on purpose, more if a store's robots.txt sets `Crawl-delay` (above 60 s the store is skipped). Stores run in parallel, so many stores are fast; one huge store is slower (up to 250 products per request, one request per second, plus one request per collection).
- `category` is derived from product type, tags, collections, title or description; `categorySource` says which.
- History needs at least two runs on the same stores with the same `historyStoreName`; only the last 5 snapshots per store are kept.

### Compliance

The Actor only requests public, unauthenticated Shopify storefront endpoints that the store's robots.txt allows for its user agent (`ShopifyTrendingProductsScraper`), re-checking robots.txt on every run and for every URL and redirect, and never uses `sort_by` URLs that Shopify disallows. It never bypasses CAPTCHAs, logins, passwords, bot protection or rate limits (on HTTP 429 it waits as told by `Retry-After` and slows down). It collects product data, not personal data. You are responsible for using the data in line with the stores' terms and the law that applies to you.

### FAQ

**Is the Trend Score a sales estimate?**
No. It combines public popularity signals (merchant best-seller lists, tags, recency, stock-outs, discounts, cross-store presence, changes over time). No sales numbers are output or estimated.

**Why is a store marked `robots_disallowed` or `blocked`?**
Its robots.txt does not allow the product JSON, or it shows a bot challenge. The Actor respects that and moves on – nothing is charged for that store.

**Why do scores rise after a few days?**
History signals (new products, variants selling out, rank changes) need at least two runs. Schedule the Actor daily on the same stores.

**Can I use my own list of 500 stores?**
Yes – paste them in `storeUrls` and raise `maxStores`. Stores are processed in parallel (`maxConcurrency`), each politely.

**Does it work for stores in other currencies or languages?**
Yes. Prices stay in the store currency (`currency`); add `convertCurrencyTo` for an ECB-rate estimate. Titles are in the store's default language.

**Do I need a proxy?**
No. The endpoints are public; the proxy option exists for special network setups and is off by default.

### Support

Something missing or wrong? Open an issue on the Actor's **Issues** tab with the run link. See [CHANGELOG.md](CHANGELOG.md) for changes.

### Feedback and reviews

If this Actor saved you time, a short review on its [Store page](https://apify.com/badr_xba/shopify-trending-products-scraper/reviews) helps other users find it. If something did not work as expected, please open an issue on the [Issues tab](https://apify.com/badr_xba/shopify-trending-products-scraper/issues) with your run ID: we read every issue.

# Changelog

This Actor's version history is a separate document: https://apify.com/badr_xba/shopify-trending-products-scraper/changelog.md

# Actor input Schema

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

Store domains or URLs, one per line, e.g. <code>colourpop.com</code>, <code>https://www.deathwishcoffee.com</code> or <code>brand.myshopify.com</code>. A collection URL (<code>/collections/best-sellers</code>) reads only that collection; a product URL reads only that product. Non-Shopify sites, password-protected stores and stores whose robots.txt disallows the product endpoints are reported in FAILED_INPUTS and never charged.

## `seedCategories` (type: `array`):

Optional. Add well-known public Shopify stores from these categories (79 stores, verified to allow product JSON in robots.txt). Combined with your own stores, up to <i>Maximum stores</i>.

## `maxStores` (type: `integer`):

Stop after this many stores (your own stores first, then curated ones).

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

Products read per store. Products from best-seller / trending / featured / new-arrival collections are read first, then the rest of the catalog (250 per request). Larger values give better price and cross-store comparisons but take longer: stores are read politely, 1 request per second.

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

Total products saved to the dataset (and charged), after filters and sorting. <code>0</code> = no limit.

## `minTrendScore` (type: `integer`):

Keep only products with at least this Trend Score (0–100). 50+ = moderate, 70+ = promising (needs at least 2 independent signal groups), 90+ = strong (3+ groups). Products below are not saved and not charged.

## `sortBy` (type: `string`):

Order of the saved products. <i>Strongest measured growth</i> uses changes between runs (needs history).

## `includeCollections` (type: `string`):

<b>Curated</b> (recommended): read the store's best-seller, trending, featured, new-arrival and seasonal collections, which power the merchant-curation signal and positions. <b>All</b>: also read other collections to list each product's collections (more requests). <b>Off</b>: catalog only (weaker Trend Score).

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

Collections read per store (one request each, first 250 products in merchant order).

## `useHistory` (type: `boolean`):

Save a compact snapshot of each store in a named key-value store so the next run can detect new products, variants selling out, price moves and rank changes in best-seller collections. Schedule the Actor daily to get growth signals.

## `historyStoreName` (type: `string`):

Name of the key-value store that keeps the snapshots (letters, digits, dashes). Use different names to keep separate histories.

## `keywords` (type: `array`):

Keep products whose title, tags, type, vendor or description contain at least one of these words.

## `excludeKeywords` (type: `array`):

Drop products containing any of these words.

## `categories` (type: `array`):

Keep products of these categories. The category is derived from product type, tags, collections or title (see <code>categorySource</code>).

## `productTypes` (type: `array`):

Keep products whose Shopify product type contains one of these texts, e.g. <code>Hoodie</code>.

## `vendors` (type: `array`):

Keep products of these vendors.

## `tags` (type: `array`):

Keep products having at least one of these merchant tags (exact tag, any case).

## `minPrice` (type: `number`):

In the store currency, or in <i>Price filter currency</i> when set.

## `maxPrice` (type: `number`):

In the store currency, or in <i>Price filter currency</i> when set.

## `priceCurrency` (type: `string`):

Optional. Compare prices of stores in different currencies by converting them to this currency with the ECB reference rates (estimate).

## `minDiscountPercent` (type: `integer`):

Keep products whose price is at least this % below the compare-at price.

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

Keep only products with at least one available variant.

## `createdWithinDays` (type: `integer`):

Keep products whose date (see <i>Date used</i>) is within this many days.

## `createdAfter` (type: `string`):

Keep products listed on or after this date.

## `createdBefore` (type: `string`):

Keep products listed on or before this date.

## `dateField` (type: `string`):

<b>Published</b> = when the product went on sale in the online store (falls back to created), <b>Created</b> = when it was created in Shopify admin, <b>Updated</b> = last change.

## `currencies` (type: `array`):

Analyse only stores selling in these currencies, e.g. <code>USD</code>, <code>GBP</code>. Other stores are skipped after one request.

## `countries` (type: `array`):

Analyse only stores based in these countries (2-letter codes from the store's public /meta.json, e.g. <code>US</code>, <code>GB</code>, <code>AU</code>).

## `excludeNonProducts` (type: `boolean`):

Skip gift cards, shipping protection add-ons, donations, gift wrap and free gifts. They are not saved and not charged.

## `includeVariants` (type: `boolean`):

Add every variant (id, title, SKU, barcode, price, compare-at price, availability, options, weight in grams, requires shipping, variant image) to each row.

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

Add the product description as plain text (HTML removed, max 1,500 characters).

## `convertCurrencyTo` (type: `string`):

Optional. Adds <code>priceConverted</code> in this currency, using the European Central Bank daily reference rate (estimate for comparison, with the rate date).

## `maxConcurrency` (type: `integer`):

How many stores are read at the same time. Each store still gets at most 2 parallel requests and at least 1 second between requests (more if its robots.txt sets a Crawl-delay).

## `requestTimeoutSecs` (type: `integer`):

Time limit for one request.

## `maxRetries` (type: `integer`):

Retries on timeouts, network errors, 5xx and 429 (honouring Retry-After), with exponential backoff and jitter. Bot challenges and password pages are never retried or bypassed.

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

Not needed for most stores (public JSON endpoints). Off by default.

## Actor input object example

```json
{
  "storeUrls": [
    "colourpop.com",
    "www.deathwishcoffee.com",
    "wildone.com"
  ],
  "seedCategories": [],
  "maxStores": 10,
  "maxProductsPerStore": 60,
  "maxItems": 100,
  "minTrendScore": 0,
  "sortBy": "trendScore",
  "includeCollections": "curated",
  "maxCollectionsPerStore": 8,
  "useHistory": true,
  "historyStoreName": "shopify-trending-history",
  "keywords": [],
  "excludeKeywords": [],
  "categories": [],
  "productTypes": [],
  "vendors": [],
  "tags": [],
  "onlyAvailable": false,
  "dateField": "publishedAt",
  "currencies": [],
  "countries": [],
  "excludeNonProducts": true,
  "includeVariants": false,
  "includeDescription": true,
  "maxConcurrency": 10,
  "requestTimeoutSecs": 30,
  "maxRetries": 3,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

Image, title, store, category, price, discount, Trend Score, level and link.

## `trending` (type: `string`):

Trend Score, level, confidence and every signal with its evidence.

## `pricing` (type: `string`):

Price, compare-at price, discount, converted price and stock.

## `history` (type: `string`):

New products and changes since previous runs.

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

Options offered (size, colour...), variants in stock, SKUs / barcodes / GTINs and, with includeVariants, every variant (weight, shipping flag, variant photo).

## `allFields` (type: `string`):

Every field as JSON, CSV or Excel.

## `report` (type: `string`):

Product cards with up to 3 photos each, Trend Score and "why this score", filters, min-score slider, sorts, compare, charts, data-quality panel, CSV/JSON export, plus run details (stores, requests, time, memory). Updated live while the run is in progress.

## `runSummary` (type: `string`):

Same numbers as the report's run details: stores by status, requests, success rate, filters, distributions, performance.

## `failedInputs` (type: `string`):

Invalid input values and stores that gave nothing (blocked, password-protected, robots-disallowed, not Shopify…), with the reason.

# 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": [
        "colourpop.com",
        "www.deathwishcoffee.com",
        "wildone.com"
    ],
    "maxProductsPerStore": 60,
    "maxItems": 100,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("badr_xba/shopify-trending-products-scraper").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": [
        "colourpop.com",
        "www.deathwishcoffee.com",
        "wildone.com",
    ],
    "maxProductsPerStore": 60,
    "maxItems": 100,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("badr_xba/shopify-trending-products-scraper").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": [
    "colourpop.com",
    "www.deathwishcoffee.com",
    "wildone.com"
  ],
  "maxProductsPerStore": 60,
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call badr_xba/shopify-trending-products-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,badr_xba/shopify-trending-products-scraper"
        }
    }
}
```

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/MZjgM9uWwPqfh56Gk/builds/scRr9Nl0a2aeGaler/openapi.json
