Your Shopify store publishes its entire catalogue at /products.json

No API key. No login. No app. Every Shopify storefront serves its whole product catalogue as JSON to anyone who asks, and most merchants have no idea.

Written after using it to scan 877 real Australian stores.

Try it on your own store

Open this in a browser tab, replacing the domain with yours:

https://yourstore.com/products.json?limit=250

You will get every published product: titles, variants, prices, inventory availability, images, tags, and the created and updated timestamps. Page through it with &page=2, &page=3 and so on.

There is a second endpoint that is less well known. For any single product:

https://yourstore.com/products/<handle>.js

That one includes selling_plan_groups, which is how you can tell whether a store sells subscriptions and on what cadence.

Is this a security problem?

No, and it is worth being clear about that. This is the same data your storefront already renders on your collection pages. Shopify exposes it deliberately so themes, apps and integrations can read it. Nothing here is a leak, a bypass or an exploit.

What it does mean is that your catalogue hygiene is public. Your competitors can see every product you have sold out, every price change, and how often you actually publish. Most never look.

If you want to turn it off

You can block it at the theme or edge layer, but think twice. Some apps and integrations depend on it, and Google reads your product pages anyway. Fixing the underlying mess is usually the better move than hiding it.

What we found reading 877 of them

The single most common finding, across every category we looked at, is products that are still live on the site and completely out of stock. Those pages stay indexed, keep taking clicks, including paid ones, and cannot convert.

Products with fewer than 2 images
93%
Product images with no alt text
90%
Products live but completely sold out
85%
Products with descriptions under 200 characters
85%
Variants with no SKU
77%
Products sharing a title with another product
40%
Products whose 'was' price is BELOW the current price
31%
Sampled pages with no Product structured data
11%
Sampled pages with no meta description
9%
See what your own /products.json says about your store We read it and hand you the list. Five seconds, no app install.

Reading it politely, if you are building something

One request per second, a real user agent with a contact address, and honour Retry-After when you get a 429. Around one store in ten disables the endpoint, and that is a legitimate answer rather than a bug to work around.