How are you handling supplier lead times and reorder triggers post-Stocky?

Hey everyone,

Like a lot of you, I’ve been looking closely at how to handle purchase orders and reorder points now that Stocky is out of the picture.

Native Shopify handles basic PO creation, but it completely leaves out the calculation side—specifically mapping out 30-day sales velocity against actual supplier lead times to figure out when a SKU is actually going to stock out. Without that, you’re back to doing manual math or default buffers that end up triggering way too early or too late.

For those of you migrating or building custom scripts/tools for this: how are you structuring your reorder trigger logic? Are you calculating days of cover dynamically via the API, or sticking to a flat threshold per variant? Curious what’s working best for your workflows right now.

I’d lean toward dynamic days of cover rather than a flat threshold. A fixed reorder point works when demand is fairly predictable, but it can get messy when sales velocity changes or different suppliers have very different lead times.

I’d probably calculate something like average daily units sold over the last 30 days, then compare that against supplier lead time plus a safety buffer. So if a SKU is selling 10 units a day and the supplier takes 14 days, you know you need roughly 140 units just to cover the lead time before even accounting for the buffer.

The part I’d be careful with is using a simple 30 day average for everything. Seasonal products or SKUs with a recent sales spike can make that number misleading. I’d probably combine recent velocity with historical demand and adjust the safety stock based on how reliable the supplier is.

I’ve been using SiteGuru to keep the technical side of the store in check, and inventory feels similar in that the useful part is having the system surface the exceptions rather than manually checking every SKU. Ideally the workflow tells you which products are actually at risk of stocking out and why, instead of just saying they’re below some arbitrary threshold.

One thing quietly breaks the days of cover math before you even get to seasonality, and it’s the denominator.

If velocity is units sold divided by 30, then every day the SKU sat at zero counts as a day of zero demand. So the SKU that stocked out on day 12 looks slow, earns a low reorder point, and stocks out again. The products the formula punishes hardest are your best sellers. What you want is units divided by days the variant was actually available, which for a SKU that was out 12 of 30 days is close to double the number you’d otherwise carry into the calculation.

The catch is Shopify won’t hand you that after the fact. InventoryLevel is current state only, available, on hand, incoming and committed, with no history series to query. So whatever you build, start writing a daily snapshot of available per variant per location on day one, before the reorder logic even exists. Six months from now that table is the one thing you can’t recreate.

Two other bits worth knowing.

Subtract incoming, not just committed. It’s already a quantity state on InventoryLevel, so a SKU with an open PO landing next week shouldn’t be tripping a trigger at all. Skipping it is how you end up double ordering.

And the trigger probably shouldn’t fire per SKU. Evaluate per SKU, but decide at supplier level. Otherwise one SKU crosses on Tuesday and another from the same supplier crosses on Friday, and you pay freight twice or miss the MOQ on both. What worked better was computing days of cover per variant, then when any variant from a supplier crosses, pulling in everything from that supplier that would cross before the next realistic order date and ordering the lot. It turns lead time into a scheduling problem rather than a threshold problem.

On lead times, stop asking suppliers and measure them instead. Every PO you receive gives you an ordered date and a received date, so after a dozen you have a real distribution per supplier. Size the buffer off how wide that spread is rather than a flat percentage. Someone who quotes 14 days and delivers in 14 to 16 barely needs a buffer. Someone who quotes 14 and delivers anywhere from 14 to 30 needs buffer covering 30, and at that point it’s a sourcing conversation rather than an inventory one.

How many SKUs and suppliers are you dealing with? Under a couple hundred SKUs across three suppliers, the supplier level batching tends to matter more than which velocity formula you pick.

lumine’s point about zero-stock days is the one most people miss

if a SKU sat at 0 for 10 of the last 30 days, dividing total sold by 30 hides real demand, so you under-reorder your fastest sellers

the logic that’s worked for me:

daily velocity = units sold over the window

days of stock left = stock / daily velocity

trigger the reorder when days of stock left drops below supplier lead time + a safety buffer

size the PO off velocity too, not a flat number: cover (lead time + buffer) days of sales, minus what you already have and what’s already on the way

and yeah, pull lead time from your own PO history (sent date to received date), not what the supplier tells you. the real number is always longer

batch the triggers by supplier so you hit MOQ and don’t pay freight twice

full disclosure, i build EZStock, an inventory + PO app, and this is exactly what it does: velocity vs lead time triggers and PO sizing, with velocity measured over how long the SKU has actually been selling so dead zero-stock days don’t drag the number down

Hello @Berend_Verstegen17, lumine’s breakdown above is spot on, especially the point about subtracting incoming POs so you don’t double-order. One thing worth adding: start writing a daily snapshot of available-per-variant-per-location to your own table now, since InventoryLevel only gives you current state with no history, and you can’t reconstruct that later once you need real velocity data. Thanks

Hey everyone—totally feel the pain on this. With native Shopify tools leaving a big gap in real-time synchronization and safety thresholds post-Stocky, a lot of merchants are struggling to piece together their workflows.

If anyone is looking for a lightweight, straightforward drop-in replacement ($79/mo) built specifically to keep checkouts and fulfillment channels locked in sync without heavy enterprise bloat, I actually built a tool called SyncPlus to solve exactly this. Happy to share a quick backend look if it helps anyone navigate the transition!

Disclosure: I build a reorder forecasting app, so I have a bias. lumine has already covered most of what I would have written, so this is only the part that sits just past it.

The denominator fix has a second half. Dividing by days available repairs the mean. It does not repair the variance, and the buffer is computed from the variance. A SKU that sat at zero for 12 of 30 days has a series full of forced zeros, so its standard deviation is largely an artefact of the stockout rather than of demand. Feed that into a safety stock formula and you get a fat buffer for a product whose real demand may be perfectly steady. I drop the unavailable days from the variability calculation as well as from the average, and if fewer than about three weeks of days survive, I publish no buffer at all and say so on the screen. Sigma from eleven days is noise with a decimal point, and a confident wrong number is worse than an admitted gap.

Cap whatever buffer you do compute. If it comes out larger than the lead-time demand itself, one unusual week is driving sigma. Capping at 100% of the base reorder point changed more in practice than the choice of service level did.

One caveat on incoming. Subtracting it from what you order is right. Letting it move the stockout date is not, because Shopify reports incoming with no delivery date attached. A PO raised four months ago that is never arriving looks identical in the API to one landing on Thursday. So I subtract incoming from the quantity to order and deliberately leave the runs-out date where it is - “incoming” and “arriving before we run out” are not the same claim, and only one of them is in the data.

Service level should not be a habit. 1.65 is just the z for 95%. Whether 95 is right falls out of the cost of holding one extra unit for a lead time against the margin lost when someone cannot buy it. Cheap to hold and high margin pushes it up; bulky, perishable or thin margin pulls it down. A 1.65 on a slow heavy item is a decision to tie up cash that nobody actually made.

And one that is not maths. A variant with no sales in the window should read “unknown”, not “healthy”. No data is not good news, and a dashboard that colours it green is the same failure as the zero-stock denominator, just further downstream.

Personally, I like to use a flat reorder point plus a small safety amount based on the slow end of the typical delivery history. This helps to prevent surprises if there’s a slowdown during peak demand.

The other piece I’d add is a review cadence, because the trigger might change on a SKU by SKU level. i.e., Fast movers can be checked daily, slow movers weekly, and seasonal maybe even less often. That keeps you from over-buying just because last month was busy.

If you’re building this in Shopify, I’d also store the last 10 to 20 PO receipt dates and delivery dates per supplier and use that to recalculate the trigger.

I’m the developer behind Replenly, so I’ll be upfront about that. It handles exactly this reorder points based on your real sales velocity and supplier lead times, then turns those into purchase orders you can send directly. It also imports your Stocky CSV exports so your supplier data and costs carry over.

$19/month on the Growth plan, free tier for stores under 100 SKUs. Happy to answer any specific questions about the lead time calculations if that helps.

I’ve been working on exactly this kind of workflow. Instead of manually checking stock and trying to remember supplier lead times, you can set up a system that watches inventory, factors in the lead time/reorder threshold, and automatically flags what needs attention. If you’re still looking for a practical way to handle this, I’d be happy to share how I’d structure it.

Missing from the formulas above: where the lead time number comes from.

Most people type in what the supplier told them, and suppliers quote their best case. Your own receiving history knows better, because it holds the real number of days between raising each order and the stock actually landing on your shelf, delivery after delivery, in your season, through your customs. Use the median. One late container drags an average into fantasy.

Three deliveries is my floor before I trust it.

The output isn’t a threshold either. “Reorder point 140” tells you nothing about your Tuesday. “Order this by 12 September or you run out before it lands” is the same maths with the answer already in it.

One caveat on velocity, since it feeds everything downstream. If a SKU sat out of stock for part of your window those days count as zero demand, which quietly punishes exactly the products you most want to reorder. Divide by the days it was actually available.

Disclosure, since I’m describing the thing I build: that median lead time, measured from your own receipts, is how Binly (Binly ‑ Stocktake & Reorder - Stocky replacement: phone stocktakes, POs & smart reorder | Shopify App Store) works out its order-by dates. The maths is yours to copy whatever you use.

Hello @Berend_Verstegen17, @Denyslg’s point about using your own receiving history median instead of the supplier’s quoted best case is the key fix here. One thing worth layering on: weight that median toward your most recent 5-6 orders rather than all-time history, since ocean freight lead times swing hard around Chinese New Year and peak-season surcharges, so an all-time average can look fine on paper while quietly running stale for the season you’re actually ordering in.

If this helped, please mark it a solution

Agreed, and with a small sample I’d go further: a window beats a weight.

Take the last six receipts, median them, done. An all-time median with two Chinese New Year deliveries in it barely moves, but it never forgets them either, so you end up placing an October order with February’s number baked into it, and nobody notices because the average still looks reasonable on the report. Six receipts is roughly one season for most of the importers I’ve talked to. The window forgets on its own.

One more thing.

Keep the supplier’s quoted lead time next to the measured one, on the same screen. Ten days quoted, twenty-three measured. That gap is a phone call to the supplier, not a formula tweak, and it is the kind of thing you only see when the two numbers sit side by side instead of living in two different tabs.

Full disclosure, I build Binly. It currently medians every receipt for a supplier once there are three or more; a six-order window was on the list already, and this thread just moved it up.

@Denyslg on window over weight - agreed, and for the same reason you give. I shipped this in the last day so the numbers are fresh in my head: last twelve receipts rather than six, median, and nothing at all below three.

Twelve because a shop ordering monthly gets roughly a year, which is enough that one bad month does not decide the figure, and short enough that a supplier who genuinely got faster is believed within two or three orders instead of two years. Six is defensible too and I would not argue hard; the thing that matters is that it is a window and not an average of everything that ever happened.

Two things that bit me building it, neither of them in the formulas above.

Measure from sent, not from created. A purchase order drafted on the 1st and actually emailed on the 8th produces a fourteen-day delivery that looks like twenty-one. That week is yours, not the supplier’s, and folding it into their lead time means every reorder date carries your own admin delay as if it were freight. It also means the number gets worse the busier you are, which is exactly backwards. Same trap in the other direction: measure to the day stock was received, not to the day you got round to marking it received.

Decide what you show below the threshold, because that is most rows for most shops. If three receipts is the minimum, a shop with two has a supplier whose lead time is genuinely unknown, and there are only two options: fall back to the typed figure, or show nothing. I went with nothing. A date on the screen derived from what a supplier quoted looks exactly as measured as one derived from what they did, and the merchant cannot tell which they are looking at - which makes the fallback worse than the blank. The blank at least says something true, and it fills itself in after a few receipts.

Also worth separating the two numbers once you have the history: the quoted lead time is still worth keeping next to the measured one. A supplier who says fourteen and takes twenty-two is a fact about that supplier, and overwriting the quote with the measurement throws away the more interesting half.

Disclosure as in my earlier reply: I build a forecasting app, and the design above came out of an argument in another thread here rather than out of my own head.

Hi there @Berend_Verstegen17
A dynamic days of cover approach has served us better than a static threshold. I would then take that average daily units from the 30 day rolling window and compare it to supplier lead time + small safety buffer. Reorder point ≈ daily velocity × lead time + safety stock. I’d also remove anomalous spikes or stockouts days from the velocity otherwise the trigger can be very misleading. For Shopify workflows; having those inputs at the variant level allows you to make way more accurate reorder decisions.

Quick disclosure: I build replenishment software, so I’ve got a commercial interest in this topic. Nothing below needs it.

lumine’s point is the one I’d underline. The number a supplier gives you for lead time is a sales figure. Your own PO history isn’t.

Two things decide whether the measurement is worth anything, and I got both wrong on my first pass at the maths.

Count once per purchase order, not per line. A PO with six lines is one delivery. Count lines and a 40-line order swamps everything else, so a supplier who’s slow on small orders never shows up as a problem.

And keep the spread, not just the average. 14 days average could mean 14 every time, or 14 usually and 31 once in ten. Same number, completely different safety stock. It’s the bad tenth you plan around, not the middle.

On Berend’s velocity point, if you’re using 30-day sales to work out cover, take out the days you were actually out of stock before you divide. Otherwise anything that sold out reads as a slow mover and never gets reordered.

One thing I can’t answer, and it’s bugging me. Tsumugi said in another thread that the individual PO export has Received at on each line. irish.chen went through the API docs and found received_at was API-only. My guess is they’re both right about different reports and the summary export flattens it, but I’m guessing.

If anyone still has an export sitting around, I’d genuinely like to know which report you pulled and whether the dates are actually in there. Happy to run the lead time maths on it and send back what it says, if that’s useful to you.