Guide

Shopify products.json: the complete guide

9 min read

Almost every public Shopify store quietly publishes its entire product catalog as JSON - at /products.json. It's the same data the storefront uses to render pages, it needs no API key or login, and anyone can read it in a browser. This guide covers everything: what the endpoint returns field by field, exactly how pagination and the 250-per-page limit work, ready-to-copy code in curl, Python and JavaScript, what you can't get from it, what to do when a store blocks it, whether it's legal, and how to watch it for changes.

What is /products.json?

Shopify exposes a public, read-only JSON feed of a store's published products at the /products.json path of the store's own domain. It is a storefront endpoint - the same data Shopify uses to build product pages - so it is meant to be publicly accessible and requires no authentication.

To see any store's catalog, just add /products.json to its domain and open it in a browser:

https://examplestore.com/products.json
This works on the store's public domain (e.g. gymshark.com) and on its underlying myshopify.com domain (e.g. gymshark.myshopify.com). It is completely separate from Shopify's Admin API, which requires an API key and only the store owner can use.

Public products.json vs the Admin API

These two get confused constantly. They are completely different things:

Public /products.jsonAdmin API
Who can use itAnyoneOnly the store owner / their app
Needs an API keyNoYes (authenticated)
What it showsPublished products, variants, prices, availabilityEverything incl. drafts, inventory counts, orders, costs
Rate limitsSoft - just be politeFormal API call limits
Use case hereReading a competitor's public catalogManaging your own store

What data does products.json return?

The response is a JSON object with a single products array. Each item is a product, and each product contains a list of its variants. At the product level you get:

  • id - the product's numeric Shopify ID
  • title and handle (the URL slug used at /products/{handle})
  • vendor and product_type
  • tags - the store's own tags for the product
  • published_at, created_at, updated_at - timestamps you can use to spot new and recently-changed products
  • images - the product's image URLs
  • options - the option names (e.g. Size, Color)
  • variants - the array below

The variant fields (where the useful data is)

Each variant is a specific buyable version of the product (a size, a color, a bundle). For competitor research this is the part that matters:

  • price - the current selling price
  • compare_at_price - the 'was' price shown struck-through during a sale (null when not on sale)
  • sku - the store's stock-keeping unit
  • title + option1/option2/option3 - e.g. 'Large / Black'
  • available - true/false, whether the variant can currently be bought
  • requires_shipping, taxable, grams (weight)
  • created_at, updated_at - when the variant was added or last changed
Comparing a variant's price to its compare_at_price tells you whether it's on sale and by how much - the single most useful signal for competitor pricing.

A trimmed sample response

Here's roughly what the JSON looks like, shortened to one product with one variant:

{
  "products": [
    {
      "id": 1234567890,
      "title": "Wool Runner",
      "handle": "wool-runner",
      "vendor": "Example",
      "product_type": "Shoes",
      "created_at": "2026-01-10T08:00:00-05:00",
      "updated_at": "2026-10-01T12:30:00-04:00",
      "tags": ["bestseller"],
      "variants": [
        {
          "id": 9876543210,
          "title": "Grey / 10",
          "sku": "WR-GRY-10",
          "price": "98.00",
          "compare_at_price": "135.00",
          "available": true
        }
      ],
      "images": [ { "src": "https://cdn.shopify.com/..." } ]
    }
  ]
}
Note compare_at_price ($135) sitting above price ($98) - this product is on sale. That's exactly the kind of signal you're reading.

Pagination and the 250 limit

By default /products.json returns only the first 30 products. You raise that with the limit parameter, up to a maximum of 250 per page, and walk through the rest with the page parameter. Keep requesting pages until one comes back with an empty products array - that's the end of the catalog.

https://examplestore.com/products.json?limit=250&page=1
https://examplestore.com/products.json?limit=250&page=2
https://examplestore.com/products.json?limit=250&page=3
...stop when "products": [] is returned
250 is a hard cap - asking for limit=1000 still returns at most 250. So a 2,000-product store needs 8 page requests. Don't assume the first page is the whole catalog; always paginate until you hit an empty array.

Pull it with code

Reading it in a browser is fine for a quick look. To actually collect the data, here are three copy-paste starting points. Each fetches the first page; wrap them in a loop over the page number to get everything.

# curl
curl -s 'https://examplestore.com/products.json?limit=250&page=1'

# Python
import requests
r = requests.get('https://examplestore.com/products.json',
                 params={'limit': 250, 'page': 1},
                 headers={'User-Agent': 'Mozilla/5.0'})
products = r.json()['products']

# JavaScript (Node or browser)
const res = await fetch('https://examplestore.com/products.json?limit=250&page=1');
const { products } = await res.json();

Useful endpoints and variations

products.json isn't the only public JSON a Shopify store exposes. These are the most useful relatives:

  • /products/{handle}.json - one product by its handle (great for watching a single item)
  • /collections/{handle}/products.json - just the products in one collection
  • /collections/all/products.json - the automatic 'all products' collection, a handy fallback
  • /collections/all?sort_by=best-selling - orders the catalog by best-selling, a rough demand signal
  • /collections/all?sort_by=created-descending - newest products first, to spot latest drops
  • /sitemap.xml - links to sitemap_products_*.xml files listing every product URL

What you CAN'T get from products.json

It's important to be honest about the limits, because a lot of guides oversell it. The public endpoint only exposes published storefront data. You cannot see:

  • Exact inventory numbers - you get the available boolean (in/out of stock per variant), never the actual quantity on hand
  • Draft or unpublished products - only products that are live on the storefront appear
  • Sales figures or revenue - no order, traffic, or conversion data is ever exposed
  • Cost, margin, or supplier info - that lives in the Admin API, which only the owner can access
Anyone claiming to show a competitor's exact stock counts or revenue from products.json is guessing. What you CAN do reliably is track availability, prices, and catalog changes over time.

When products.json doesn't work

A few stores won't return data. The usual reasons and fixes:

  • Password-protected store - the storefront is gated, so you get the password page instead of JSON. There's no public data to read until it opens.
  • Endpoint disabled - rare, but some stores block /products.json. Try /collections/all/products.json as a fallback; it's a different route and often still works.
  • 404 or a redirect - you may be on a non-Shopify domain, or a marketing redirect. Confirm the store is Shopify first (see below).
  • 429 Too Many Requests - you're being rate-limited. Slow down and space out requests.

How to confirm a store is actually Shopify

These endpoints only exist on Shopify. The fastest check is simply whether /products.json returns JSON. You can also view the page source and look for a reference to cdn.shopify.com or Shopify.theme, or check for an X-ShopId response header - nearly every Shopify storefront has them.

Not sure if a site is on Shopify? See our guide: How to check if a website is built on Shopify.

Etiquette, rate limits, and legality

The data is public, but good manners still apply: send a normal User-Agent, space your requests out, cache responses, and don't hammer a store with hundreds of rapid hits.

On legality: comparing competitors' public prices is a long-established, legitimate practice, and courts have generally held that accessing publicly available data isn't 'unauthorized access.' Where you need care is HOW you collect it (gently, public data only, no bypassing logins) and what you do with it (use the facts, don't republish a competitor's copyrighted images or copy). It's not legal advice, and there's real nuance.

We cover the full picture in: Is it legal to monitor or scrape competitor Shopify prices?

From a one-off peek to continuous monitoring

Reading products.json once tells you what a store sells today. The real value is in the changes over time: a price drop, a sell-out, a new launch, a removal, a sale starting. Catching those by hand means fetching every page of every competitor, storing each snapshot, and diffing it against yesterday's - forever.

That's exactly what Shop Sentry automates. You paste a competitor's Shopify domain, it discovers the full catalog from products.json automatically, and it alerts you by email or Telegram the moment a price, stock level, or product changes - with the before/after value. No scripts, no spreadsheets, no cron jobs.

Frequently asked questions

How many products does products.json return?

Up to 250 per page with ?limit=250 (the default is 30). For stores with more than 250 products, paginate with ?page=2, ?page=3 and so on until a page returns an empty products array.

Do I need an API key or app to use it?

No. products.json is a public storefront endpoint - no API key, no app, no login. That's different from Shopify's Admin API, which requires authentication and is only for the store owner.

Can I see a competitor's exact inventory or sales?

No. You get a per-variant 'available' true/false, but never the exact quantity on hand, and never any sales, revenue, or traffic data. Those require the Admin API that only the owner can access.

Why does a store's products.json return a 404 or the password page?

Either the store is password-protected, the endpoint is disabled (try /collections/all/products.json instead), or it isn't a Shopify store. Confirm the platform first.

How often does products.json update?

It reflects the live storefront, so it updates as soon as the store changes a price, adds a product, or a variant sells out. To catch those changes you have to re-fetch and compare over time - which is what Shop Sentry does for you.

Monitor any Shopify store's products.json automatically

Paste a domain and Shop Sentry watches its catalog for you - price changes, restocks, new launches and removals - with instant email and Telegram alerts. Free on your first store, no card required.

Keep reading