Shopify inventory velocity windows: stop promo spikes from triggering bad transfers
How to use 7-, 30-, and 90-day Shopify inventory velocity windows so multi-location transfers follow real demand — not flash-sale noise, one-off wholesale orders, or store-wide averages.
Jeshua Leger
Founder, Leger Studio ·
Days of cover only works if the velocity under it is honest. A Black Friday weekend that sells 40 units at one door can make a 7-day rate look like a permanent new normal — and a naive transfer rule will happily empty the hub to “fix” a demand spike that already ended. The opposite failure is just as expensive: a 90-day average that still includes a dead quarter can leave a retail door under-covered while surplus sits two buildings away.
This guide is for multi-location Shopify merchants who already track on hand, incoming, and cover, and now need a durable policy for *which* sales window drives transfer math. It sits next to the operating model in Shopify multi-location inventory transfers, the scorecard in Shopify inventory health score: use days of cover to prevent stockouts, and the rails in Shopify transfer approval thresholds.
What a velocity window actually measures
A velocity window is the sales lookback you trust for ops decisions — not a marketing dashboard vanity chart. For each variant *at each Shopify location*:
- Count units sold in the window (7, 30, or 90 days) at that location only — never a store-wide blend.
- Convert to daily velocity: window units ÷ days in the window.
- Feed that daily rate into cover: (available + incoming) ÷ daily velocity when velocity > 0.
- Treat zero-velocity SKUs as a separate class — infinite cover on paper, useless as a transfer signal.
The window chooses *which past* you believe. Seven days reacts fast and overfits promos. Ninety days is stable and blind to recent acceleration. Thirty days is the usual baseline. Healthy ops teams do not pick one forever — they assign each window a job.
Why store-wide velocity breaks multi-location transfers
Shopify locations do not share demand. A DTC hub, a flagship retail floor, and a 3PL node can sell the same SKU at wildly different rates. Blending them into one company velocity does three bad things:
- Understates risk at the hot door — cover looks fine company-wide while that location is three days from a stockout.
- Overstates need at quiet doors — surplus looks like a “problem” that invents freight.
- Mis-sizes transfer quantity — destination need calculated from the wrong daily rate either underfills or drains the source.
Location-level windows are non-negotiable once you have two or more fulfillment sites. The rest of this post assumes that constraint.
Assign each window a job (do not average them blindly)
7-day: urgency and spike detection
Use the short window to answer: “Is something on fire *right now*?” Compare 7-day daily velocity to the 30-day baseline. A large ratio (for example 7-day ≥ 2× 30-day) is a spike signal — promo, influencer hit, local event, or a one-off B2B order that should not rewrite your replenishment policy overnight.
- Flag for human review when 7-day ≫ 30-day and destination cover is already thin.
- Do not auto-size transfers solely from 7-day during known campaign weeks.
- Still act on true sustained lifts — if 7-day stays elevated for two consecutive weekly reviews, promote the new rate into baseline judgment.
30-day: default transfer quantity
Thirty days is usually the least-wrong single number for destination need and source floor math. It smooths a noisy weekend without waiting a full quarter to notice a trend. Most teams should size transfers from 30-day daily velocity unless a documented exception applies (new door, new SKU, or a campaign with a written override).
90-day: seasonality, aging, and “is this still a real SKU?”
Ninety days answers slower questions: Is this SKU dying? Is winter demand still in the average? Is surplus actually dead stock rather than buffer? Use 90-day to gate aging and overstock scores — not as the sole input to an urgent retail replenishment.
Promo spikes: the failure mode that empties warehouses
Flash sales compress demand into a few days. Cover calculated from that spike says the destination needs a mountain of stock *tomorrow*. If automation trusts the spike as baseline, the source loses safety stock for ordinary post-promo demand — and you pay freight twice (in and back, or in and then emergency PO).
A practical anti-spike policy:
- Maintain a promo calendar that ops can see (channel, dates, SKUs, expected uplift). No calendar = every spike looks organic.
- During active promo windows, force review on transfers sized primarily from 7-day velocity — or cap auto-approve quantity at the 30-day need.
- Exclude known wholesale / sample / internal orders from velocity if they are tagged and should not drive retail cover.
- After the promo ends, require two quiet review cycles before any rule treats the elevated 7-day rate as the new normal.
- Pair with daily caps and source floors so even a mistaken recommendation cannot drain a hub in one night — see transfer approval thresholds.
Worked shape: Destination sells 3/day on a 30-day basis (need ≈ 14 days → ~42 units target). Promo weekend sells 24 units in two days → 7-day rate jumps to ~5.1/day and “need” balloons. Policy: size the transfer from 30-day (plus a small discretionary buffer for the remaining promo days if stock is already committed to the campaign), and flag the 7-day divergence for a human — do not auto-ship another 40 units the Monday after the sale ends.
New doors, new SKUs, and cold-start velocity
Windows assume history. A new retail location or a just-launched variant has none. Do not invent fake precision:
- Seed with a peer rate (similar door, similar SKU class) and mark the recommendation as provisional.
- Prefer manual transfers for the first 2–4 weeks until a real 7- and 30-day sample exists.
- Keep auto-approve off for cold-start SKUs even if unit quantity is small — early mis-sizes compound.
- When cloning a door’s assortment, copy *roles and floors* first; copy velocity assumptions last.
How velocity windows feed transfer quantity
Keep the math boring and auditable. Using the baseline (usually 30-day) daily velocity *v*:
- Destination need ≈ max(0, target_days × v − available − incoming).
- Source available ≈ max(0, available − source_floor − committed), where floor may itself be expressed as days × source *v*.
- Transfer qty = min(destination need, source available), rounded to case packs if required.
- Skip if expected cover improvement at destination is trivial (for example under ~2–3 days) — labor cost exceeds benefit.
Then overlay window checks before you create the Shopify transfer:
- If 7-day ≥ 2× 30-day → require review (or cap qty at 30-day need).
- If 7-day ≤ 0.5× 30-day and destination still looks short → verify counts / commits before shipping; demand may already be gone.
- If 90-day velocity collapsed while on-hand is high → prefer aging/liquidation paths over replenishing more doors.
- If destination *v* = 0 → do not invent cover from company averages; investigate or exclude.
Location roles still gate which velocities matter
A perfect window policy cannot fix a forbidden path. Tag each Shopify location with whether it can be a source, destination, or both — and which channels it serves — before automation reads velocity:
- Ecommerce / regional hub: usually source and destination for DTC; velocity here often drives kit and pack fulfillment cover.
- Retail: often destination-only from hub; local velocity should size inbound replenishment, not invent 3PL → store paths your contracts forbid.
- 3PL: source for contracted channels only — never treat retail sell-through as a reason to pull from a 3PL that will not ship store transfers.
- Quarantine / returns: exclude until sellable; do not let zero velocity there create phantom surplus.
Roles define the graph; velocity windows score edges on that graph. Thresholds and floors (covered in the approval thresholds guide) decide how much can move without a human.
Bundles and kits: attribute pack demand to components
If you sell packs, storefront velocity on the pack product is not the whole story for warehouse moves. Components absorb demand from solo SKUs *and* every kit that includes them. Transfer reviews should use component-level velocity at the location that actually picks the pack — otherwise you protect the wrong shelf.
Merchants on Better Bundles already expand kits into real component SKUs at checkout, which makes location-level component velocity measurable. Fold that into the same window policy: size component transfers from 30-day component demand, spike-check with 7-day during kit promos, and keep pack availability honest via kit inventory sync and Inventory sync & stock management.
A weekly ritual that keeps windows honest
- Refresh location × variant 7/30/90 velocities for A-movers (start with the SKUs that drive most units or revenue).
- Sort by cover using the baseline window (usually 30-day); note any SKU where 7-day diverges ≥ 2×.
- Cross-check the promo calendar and wholesale tags before you trust a spike.
- Propose specific transfers: variant, source, destination, qty, window used, and disagreement notes.
- Create native Shopify transfers so transit and receiving stay in the system of record.
- Friday exception review: which spikes were real, which transfers sat unused, which windows need retuning.
What “good” looks like
- Transfer quantities cite a named baseline window; spike weeks show review notes, not silent qty inflation.
- Post-promo Mondays do not systematically empty hubs.
- New doors and new SKUs stay manual until real samples exist.
- Zero-velocity and collapsed-90-day SKUs are routed to aging decisions, not endless replenishment.
- Pack/kit component demand is visible in the same review as solo SKUs.
- Approvals, floors, and daily caps still apply — windows improve signal quality; they do not replace safety rails.
Where FlowOps fits (in development)
FlowOps is Leger Studio’s multi-location inventory app currently in development. Product direction includes rolling 7-, 30-, and 90-day velocity per variant per location, days-of-cover recommendations with explainable reasoning, rules and approval modes, safety stock floors, daily caps, and native Shopify transfers — so promo noise and baseline demand can be treated as different inputs instead of one muddy average.
It is not available on the Shopify App Store yet, and this post is not an install link. Until launch, run the window jobs and weekly ritual with Shopify admin exports or native transfers, keep reading the blog, and watch the FlowOps app page for updates. For product news when FlowOps or other Leger Studio apps ship, subscribe from the site footer or use the contact page.