ProductHow it worksDocsBlogPricingGet Framer Plugin
← Blog

Shopify Inventory Sync on Framer: Stop Overselling in 2026

Shopify inventory sync on a Framer site works one of two ways: read stock from Shopify at request time through the Storefront API, or let an inventory webhook update the page the moment stock changes. What does not work is copying stock counts into Framer CMS. A copied number is a snapshot, and snapshots go stale between the moment you write them and the moment a customer clicks buy.

That gap is where oversells live. Inventory distortion — the combined cost of out-of-stocks and overstocks — ran to $1.73 trillion globally, or 6.5% of retail sales, according to IHL Group's 2025 research. A design-led storefront with a stale stock field is a small, self-inflicted contribution to that number.

What Shopify inventory sync means on a decoupled frontend

Shopify inventory sync is the practice of keeping the stock number a shopper sees identical to the stock number Shopify will honour at checkout. On a Liquid theme that is free, because the theme renders from Shopify's own data. On Framer it is a design decision, because Framer renders from Framer CMS and Shopify is somewhere else.

So the question is not whether you sync. It is how many seconds of staleness you are willing to ship, and who pays when the number is wrong — you, in refunds and support replies, or the customer, in a cancelled order.

Shopify inventory sync methods compared

Method Staleness window Oversell risk Setup effort Ongoing cost
Manual CSV into Framer CMS Hours to days High Low (an afternoon) Your time, every week
Scheduled CMS sync (hourly/daily job) 1–24 hours Medium Medium (a script plus a cron) $0–$29/mo tooling
Live Storefront API fetch on page load Seconds Low Medium (one query, one component) API calls only
Inventory webhook push to cache/CMS Seconds, when delivered Low–Medium High (endpoint, HMAC, retries) Hosting for the endpoint

Two columns deserve a note. "Staleness window" is the honest number, not the marketing one: a scheduled sync advertised as hourly is on average 30 minutes stale and at worst 60. And webhook risk is not zero, because delivery is not a promise.

"Webhook delivery isn't always guaranteed." — Shopify, webhook development docs

Shopify's own guidance is to run a periodic reconciliation job that refetches data using updated_at filters. Treat webhooks as a speed-up, never as the only path.

How do you use Shopify inventory sync apps with a custom storefront?

Mostly, you do not — and this is where most search results mislead. Search "shopify inventory sync" and you get app listings for supplier feeds, CSV mapping and multi store sync. Those tools solve a real problem: moving stock between Shopify and something outside it, like a warehouse feed or a second store.

Your Framer storefront is not outside Shopify. It is a view of it. Installing a sync app to keep a frontend honest adds a second source of truth and a second thing to debug. If you already run one of those apps for supplier reasons, keep it — just do not ask it to feed your product pages.

Does multi store sync change anything here?

Only upstream. Multi store sync keeps two Shopify stores' inventory aligned with each other; your frontend still reads from whichever store it is pointed at. The rule holds: fix sync once, at the Shopify layer, then read live.

One genuine wrinkle is markets. Since Storefront API version 2024-04, the @inContext directive returns per-market fulfillable inventory, so availableForSale and quantityAvailable can differ by country. If you sell into several markets, a single global stock number in CMS is wrong in more places than one.

Reading live stock without hammering the API

The live-fetch objection is always performance, and it is weaker than it sounds. Shopify applies no fixed requests-per-minute limit to buyer traffic on the Storefront API; bots and crawlers are what get throttled, and tokenless access is capped at 1,000 query complexity. A variant availability query costs a fraction of that.

Three rules keep it cheap and fast:

  1. Render the page from CMS, fetch stock separately. Copy, images and pricing can be static. Availability is the only field that must be live, so fetch it client-side after paint.
  2. Ask for the booleans first. availableForSale and currentlyNotInStock answer "can I sell this" with the standard product listings scope. Numeric quantityAvailable needs unauthenticated_read_product_inventory — request it only if you actually display counts.
  3. Cache for seconds, not hours. A 30-second edge cache on an availability query absorbs a traffic spike while keeping the page defensibly current.

If you are weighing this against pushing a full catalogue into CMS, the structural limits are worth reading first — we covered them in Framer CMS for product catalogs, and the field-level changes in Storefront API 2026-07.

When the page and Shopify still disagree

Build for the mismatch instead of pretending it cannot happen. Let Shopify's checkout be the referee: it will refuse an unavailable line item, and a clear "this just sold out" message beats a silent failure.

Practically, that means three things. Show availability state rather than exact counts unless scarcity is part of your pitch. Re-check availability when the shopper adds to cart, not only on page view. And log every refusal, because a cluster of them tells you which variant your sync is lying about.

This is the whole reason FramerLink reads product state from Shopify on request instead of mirroring it into CMS — a stale field is a bug you cannot see in the designer. Whether you build that yourself or not, pick the method whose staleness window you could defend to a customer, and price the tooling honestly against one weekend of manual CSV uploads.

Frequently asked questions

How do you sync Shopify inventory with a Framer site?

Read stock from Shopify at request time through the Storefront API rather than copying it into Framer CMS. Query availableForSale and quantityAvailable on each variant, and add an inventory webhook if you cache pages. Shopify stays the single source of truth, so the page cannot drift.

Can Framer CMS show real-time Shopify stock?

Not on its own. Framer CMS stores whatever value was last written to it, so a stock number pushed in at build time is a snapshot, not a live reading. Real-time stock needs a client-side or server-side fetch to Shopify on page load.

Does the Shopify Storefront API return inventory quantities?

Yes. ProductVariant exposes availableForSale, quantityAvailable and currentlyNotInStock. The boolean works with the standard product listings scope, but numeric quantities require the unauthenticated_read_product_inventory access scope on your Storefront access token.

Why does my Framer product page say in stock when it is sold out?

Because the page is serving a cached copy of an older inventory value. Either the CMS field was written hours ago, the static page has not been rebuilt, or a webhook that should have invalidated the cache was never delivered or never handled.

Do you need an inventory sync app for a headless Shopify store?

Only for supplier feeds and multi-store setups. Inventory sync apps move stock between Shopify and outside systems. Keeping a custom storefront truthful is a different job, solved by reading Shopify live or invalidating caches on inventory change.

Sources