# Shopify MCP Server & API - Products, Prices, Stock (`akhil_rajesh/shopify-mcp-server`) Actor

Shopify products for AI agents: an MCP server and live API that reads any Shopify store, collection or product link in seconds. Prices per country, sale prices, variants, stock, SKUs, images, descriptions and collections. No login, no proxy.

- **URL**: https://apify.com/akhil_rajesh/shopify-mcp-server.md
- **Developed by:** [Akhil rajesh](https://apify.com/akhil_rajesh) (community)
- **Categories:** MCP servers, E-commerce, AI
- **Features:** Limited permissions, Single-tenant, Server interface
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 result rows

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

Give your AI agent **Shopify product data on demand**. This Actor is an **MCP server** and a **live HTTP API** that reads any Shopify store: the whole catalogue, one collection, or single products by link. An agent asks for "Gymshark's newest leggings under $60 that are in stock, priced for the UK" and gets the products back in seconds: title, brand, product type, **price and sale price** with the discount, **every variant** with its price, size and colour, SKU and whether it's **in stock**, images, dates and the product link.

It runs the same code as [Shopify Scraper & Price Tracker](https://apify.com/akhil_rajesh/shopify-scraper), with Apify Standby switched on, so it answers each request at once instead of starting a run. For whole catalogues, daily price-drop and restock tracking, or Slack, Discord and Teams alerts, use that Actor.

### Connect your agent

Authenticate with your **Apify API token** (Apify Console → Settings → API & Integrations).

**MCP server** (Streamable HTTP): `https://akhil-rajesh--shopify-mcp-server.apify.actor/mcp`

```json
{"mcpServers": {"shopify": {"type": "http", "url": "https://akhil-rajesh--shopify-mcp-server.apify.actor/mcp",
  "headers": {"Authorization": "Bearer <YOUR_APIFY_TOKEN>"}}}}
```

In Claude Code:

```bash
claude mcp add --transport http shopify https://akhil-rajesh--shopify-mcp-server.apify.actor/mcp --header "Authorization: Bearer <YOUR_APIFY_TOKEN>"
```

A client that can't send headers can use `https://akhil-rajesh--shopify-mcp-server.apify.actor/mcp?token=<YOUR_APIFY_TOKEN>`. Keep that URL private, as it carries your token.

Through **Apify's MCP server** (`https://mcp.apify.com`, for Claude, ChatGPT, Cursor and other clients), add the tools with `https://mcp.apify.com?tools=akhil_rajesh/shopify-mcp-server`. They appear as `akhil_rajesh--shopify-mcp-server--get_products` and so on. Add them that way rather than through Apify's generic `call-actor` tool, which returns the rows only as text.

Then ask in plain words:

- *"What are Allbirds' 20 best-selling shoes right now, and which are on sale?"*
- *"Compare Kith's prices for the UK and the US on its newest products."*
- *"Is this product in stock in size 10?"* (with the link)
- *"List Gymshark's collections, then show me the leggings under $50."*

### Tools

| Tool | What it returns |
|---|---|
| `get_products` | Products of up to 5 stores, collections or product links, in the store's order (best selling, newest, price, title), priced for any country. Filters: keywords, excluded words, vendors, product types, tags, a price range, in stock only, on sale only, published within N days. One row per product, or per variant. Product details and Shopify's own recommendations when asked for |
| `get_product` | Products by link, with every detail: variants, every image and video, the full description, SEO texts, subscription plans and collections. Links the store doesn't have are named in `notFound` and not charged |
| `list_collections` | A store's collections (categories) with title, link, description and image, to pass to `get_products` |
| `run_actor` | The whole input of [Shopify Scraper & Price Tracker](https://apify.com/akhil_rajesh/shopify-scraper) in one call, for reads the other tools can't express |

The first request starts a Standby run, which took about 5 seconds in testing; after that, 20 best sellers came back in 0.6 to 1.6 seconds and a single product in about 1.3 seconds.

### HTTP API

The same reads as plain HTTP requests, with the same token (header `Authorization: Bearer <token>`):

```bash
curl "https://akhil-rajesh--shopify-mcp-server.apify.actor/products?store=allbirds.com&max=20&country=GB&onSale=true" \
  -H "Authorization: Bearer <YOUR_APIFY_TOKEN>"
```

| Endpoint | Parameters (defaults in brackets) |
|---|---|
| `GET /products` | `store`, `max` (50), `sort` (bestSelling), `country`, `keywords`, `exclude`, `vendors`, `types`, `tags`, `minPrice`, `maxPrice`, `inStock`, `onSale`, `days`, `variants`, `details` (false), `recs` (0) |
| `GET /collections` | `store`, `max` (250) |
| `POST /run` | The Shopify Scraper & Price Tracker input as the JSON body |

Separate several stores, links, keywords or tags with `|`. The Actor's **Endpoints** tab in Apify Console lists every parameter and lets you try them.

### What each product holds

| Group | Fields |
|---|---|
| **Product** | `title`, `vendor`, `productType`, `tags`, `handle`, `productId`, `url`, `imageUrl`, `options` |
| **Price** | `price` (the lowest variant's), `maxPrice`, `compareAtPrice`, `discountPercent`, `onSale`, `currency`, `country` |
| **Stock** | `available`, `variantsCount`, `variantsInStock`, `backorder` |
| **Variants** | `variants`: each with `variantId`, `title`, `sku`, `barcode`, `price`, `compareAtPrice`, `available`, options, weight and image |
| **Details** (`product_details`) | `images`, `videos`, `description`, `descriptionHtml`, `seoTitle`, `seoDescription`, `sellingPlans`, `requiresSellingPlan`, `collections` |
| **More** | `recommendations` (Shopify's own related products), `createdAt`, `publishedAt`, `updatedAt`, `rank`, `store`, `storeName`, `scrapedAt` |

With **one row per variant**, each row is one size or colour with its own price, SKU and stock. Shopify doesn't share stock counts without the store's own token, so rows say whether each variant can be bought, not how many are left. Fields without a value are left out of a row.

A product, shortened:

```json
{
  "type": "product",
  "store": "www.allbirds.com",
  "storeName": "Allbirds",
  "rank": 1,
  "title": "Men's Wool Runner - Natural Grey (Light Grey Sole)",
  "vendor": "Allbirds",
  "productType": "Shoes",
  "price": 110,
  "onSale": false,
  "currency": "USD",
  "available": true,
  "variantsCount": 7,
  "variantsInStock": 3,
  "options": [{"name": "Size", "values": ["8", "9", "10", "11", "12", "13", "14"]}],
  "url": "https://www.allbirds.com/products/mens-wool-runners"
}
```

### Reading stores well

- **Any Shopify store's address works**, with or without `www.`, and so does its `.myshopify.com` address. A collection's link (`.../collections/mens`) reads only that collection, a product's link only that product.
- **Prices for another country**: set `country` (`GB`, `CA`, `DE`, or a name) and prices come in that country's currency, as the store sells there. A store that doesn't sell to a country answers with its own market's prices, and the rows' `country` says which.
- **A store's own order**: `bestSelling` is the store's best sellers, `newest` its newest products, `storeOrder` a collection's own arrangement.
- **Headless stores**, whose front end is built apart from Shopify's and doesn't pass its API through, are named in `notLoaded`. The Actor identifies itself and never disguises itself as a browser.

### Answers and limits

Every answer carries the `rows`, `notFound` (inputs that aren't a Shopify store, collection or product, each with the reason: free), `notLoaded` (stores that didn't answer), `notRead` (what a limit left out: not charged) and `notes`.

A request that reads nothing gets an `error`, and nothing is charged:

- HTTP 400 for an argument it can't read (a tool error over MCP).
- 503 when no store answered or the run was busy (send it again).
- 402 when your spending limit for the run is reached (it lifts when the run ends, after 2 minutes without requests).

A 503 can also carry rows, when the platform stopped the run while a request was being read: those were stored and charged, and `notRead` names the rest.

| | Stores or links | Rows | Answer size | Time |
|---|---|---|---|---|
| **MCP tool call** | 5 | 100 | about 350 kB | 50 seconds |
| **HTTP request** | 10 | 1,000 | about 6 MB | 170 seconds |

The MCP limits keep answers inside what MCP clients wait for (60 seconds) and what Apify's MCP server passes on (about 1 MB). Product details add a few kB a product, so fewer products fit an answer with them. **A request that has started runs to its end even if you stop waiting**: Apify's Standby proxy keeps it open, so its rows are read and charged. Ask for what you need.

### How much does it cost?

Pay-per-event, the same prices per row as Shopify Scraper & Price Tracker:

| Your plan | Per 1,000 rows |
|---|---|
| Free | $1.00 |
| Starter | $0.90 |
| Scale | $0.80 |
| Business and above | $0.70 |

A row is a product, a variant (with one row per variant) or a collection. Plus the start fee when a Standby run starts, and the run's **platform usage** while it serves you and until it has been idle for 2 minutes, at Apify's usual rates. That's why the Store page's pricing box mentions platform usage. Inputs that aren't stores, and products a filter leaves out, cost nothing.

### Agents that pay per call

Apify's MCP server doesn't offer Actors with a live endpoint to agents that pay per call with **x402** or **Skyfire**. Those agents can use [Shopify Scraper & Price Tracker](https://apify.com/akhil_rajesh/shopify-scraper) through `https://mcp.apify.com` instead: it takes the same input and returns the same rows, as a normal run that starts for each call instead of a live answer. An agent with an Apify account or API token can use either.

### FAQ

#### Why did I get fewer products than I asked for?

The store or collection ran out of products, a filter left the rest out, or a limit was reached (`notRead` says which). For whole catalogues of thousands of products, run [Shopify Scraper & Price Tracker](https://apify.com/akhil_rajesh/shopify-scraper), which has no per-request limits.

#### Can it tell me what changed since yesterday, or post price drops to Slack?

Not over the live endpoint, which answers each request on its own and ignores those fields. A normal run of this Actor does both, with the same input as Shopify Scraper & Price Tracker: schedule it, or schedule the scraper. Each Actor keeps its own price history (this one's is `shopify-mcp-history` by default), because Apify lets an Actor open only the history stores it created itself.

#### Why does a store come back as not loaded?

Either the store didn't answer (try again shortly), or its front end is built apart from Shopify's and doesn't pass Shopify's API through (a "headless" store, such as some large brands). The reason is in `notLoaded`.

#### Is the data the same as on the store's website?

It comes from the store's own Storefront API, which powers its pages and apps: the same products, prices and availability a shopper sees, for the country asked for.

### Other Actors by this developer

- [Shopify Scraper & Price Tracker](https://apify.com/akhil_rajesh/shopify-scraper): the same Shopify data as scheduled runs: whole catalogues, price drops, restocks, new and removed products, and Slack, Discord or Teams alerts
- [Amazon.ca Product & Trending Tracker](https://apify.com/akhil_rajesh/amazon-ca-product-trending-tracker): Amazon Best Sellers, prices, search positions and reviews on 23 marketplaces, with change tracking
- [AliExpress Price Tracker & Scraper](https://apify.com/akhil_rajesh/aliexpress-price-tracker): AliExpress search results with store prices, units sold and price history
- [Google Trends Scraper & API - Trending Now, Pinterest Trends](https://apify.com/akhil_rajesh/google-trends-scraper): Trending Now in 125 countries, interest over time and rising searches, with an MCP server for AI agents
- [Yahoo Finance Scraper, API & MCP](https://apify.com/akhil_rajesh/yahoo-finance-scraper): quotes, price history, financials and options chains, with an MCP server for AI agents

### Data source

All data comes from each store's **Shopify Storefront API**, which Shopify opens to everyone without a token. The Actor identifies itself as a bot, asks each store about once a second, and reads public product data only; it never signs in or checks out.

> **Disclaimer:** This is an independent tool. It is **not affiliated with, endorsed by, or sponsored by** Shopify Inc. or any store it reads. All product and company names are the property of their respective owners.

### Limitations

- **Shopify stores only**, and not headless stores whose front end doesn't pass Shopify's API through
- **No stock counts**: Shopify shares them only with the store's own token, so rows say whether each variant can be bought
- **Per-request limits** (see above); whole catalogues belong to a normal run
- **No change tracking or alerts over the live endpoint**: those are a scheduled run's
- Prices and stock change constantly, and a product can sell out between requests

# Changelog

This Actor's version history is a separate document: https://apify.com/akhil_rajesh/shopify-mcp-server/changelog.md

# Actor input Schema

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

Shopify stores (allbirds.com), collection links (allbirds.com/collections/mens) or product links (allbirds.com/products/mens-wool-runners). A store's /collections link (allbirds.com/collections) lists its collections, one row each. A store's own address or its .myshopify.com address both work. A link's language or country part (/en-ca/) is ignored: use Prices for country below. Up to 50.

## `maxResults` (type: `integer`):

Most rows a run returns, shared evenly between the stores and links. With Only changes: most changes a run returns (price drops first; the rest come with the next run).

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

Most products read from each store or collection. With Only changes, each store is read whole up to this number, so no change is missed. Leave empty for 10,000.

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

The order products are read in, and so which ones a run returns first. Best selling is the store's own best-seller order.

## `country` (type: `string`):

Two-letter country code or name (CA, GB, Germany): prices and availability in that country's currency, as the store sells there. A store that doesn't sell in that country answers with its main market's prices, and the run says so. Leave empty for the store's main market.

## `oneRowPerVariant` (type: `boolean`):

A row for each variant (size, colour) with its own SKU, barcode, price and stock, instead of one row per product with its variants inside. Each variant row is a result.

## `productDetails` (type: `boolean`):

Every image (up to 10, with alt text and size), videos, the full description as HTML, the SEO title and description, subscription plans and the collections each product is in. Pages then hold 60 products instead of 250, so a big store takes a little longer. Switch off for lean rows.

## `recommendationsPerProduct` (type: `integer`):

The products the store itself recommends with each product (its "You may also like"), up to 10, inside the row. One extra request per product, so a run takes about a second longer per product; not charged extra. Not read with Only changes. Leave empty for none.

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

Only products whose title, vendor, type or tags hold one of these words or phrases. Leave empty for all.

## `excludeWords` (type: `array`):

Leave out products whose title, vendor, type or tags hold any of these (gift card, sample).

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

Only products by these vendors or brands, as the store names them. Leave empty for all.

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

Only products of these types, as the store names them (Shoes, Socks). Leave empty for all.

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

Only products with at least one of these tags. Leave empty for all.

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

In the store's currency (the one for Prices for country). Leave empty or 0 for no minimum.

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

In the store's currency. Leave empty or 0 for no maximum.

## `inStockOnly` (type: `boolean`):

Only products (or variants) that can be bought now.

## `onSaleOnly` (type: `boolean`):

Only products (or variants) with a compare-at price above the price.

## `publishedWithinDays` (type: `integer`):

Only products the store published within this many days. Leave empty or 0 for any.

## `onlyChanges` (type: `boolean`):

Track your stores: each run returns only what changed since the last run with the same stores and filters (new products, price drops and increases, back in stock, sold out, newly on sale, removed). The first run saves the products there now as the baseline and returns them as firstRun.

## `changeTypes` (type: `array`):

Which changes Only changes returns. Leave empty for all.

## `minChangePercent` (type: `number`):

Smaller price moves aren't reported, and the last reported price stays the baseline, so a slow slide still shows once it adds up. Leave empty for 1%.

## `alertWebhookUrl` (type: `string`):

Post each run's changes to Slack, Discord or Microsoft Teams (their incoming-webhook URL), or to any HTTPS endpoint that takes JSON (Zapier, Make, n8n). Switches on Only changes. The first run posts a short 'alerts are set up' message.

## `alertChangeTypes` (type: `array`):

Which changes are posted. Leave empty for new products, price drops and back in stock.

## `historyName` (type: `string`):

Keep a separate history for this tracker (a-z, 0-9 and hyphens). Leave empty to share the default one: histories are kept per store and filters anyway.

## Actor input object example

```json
{
  "stores": [
    "https://www.allbirds.com"
  ],
  "maxResults": 100,
  "sortBy": "bestSelling",
  "productDetails": true
}
```

# Actor output Schema

## `products` (type: `string`):

No description

## `changes` (type: `string`):

No description

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

No description

## `catalog` (type: `string`):

No description

## `details` (type: `string`):

No description

## `collectionList` (type: `string`):

No description

## `notFound` (type: `string`):

No description

## `allData` (type: `string`):

No description

## `runSummary` (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 = {
    "stores": [
        "https://www.allbirds.com"
    ],
    "maxResults": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("akhil_rajesh/shopify-mcp-server").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": ["https://www.allbirds.com"],
    "maxResults": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("akhil_rajesh/shopify-mcp-server").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": [
    "https://www.allbirds.com"
  ],
  "maxResults": 100
}' |
apify call akhil_rajesh/shopify-mcp-server --silent --output-dataset

```

## MCP server setup

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

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/GhpWrSwP064yxKycE/builds/w7HwSYrikBY7aipJD/openapi.json
