Case studies / JWC

How a reseller replaced gut feel with 86% forecast accuracy

86%

Forecast accuracy on held-out products

12M

Amazon products behind every forecast

5 mo

From raw data to a live system

Ever bought Nike or Adidas gear on Amazon? Chances are it came from one of the platform’s top 100 resellers for those brands.

Every reseller at that scale loses money in the same two places. Stockouts on the products that were selling, and write-offs on the products that were not. Both trace back to a single decision made monthly, by hand, on historical sales and category feel.

We rebuilt that decision around a forecast. Buyers now size purchase orders against a projected demand range with a stated confidence level, and the products with no sales history at all, where the guessing used to be worst, get forecast too.

Here is how the system works, and what forecasting demand across 12 million products taught us.

The challenge

Purchasing ran on experience, category feel, and Excel formulas. Someone with a strong read on the category reviewed inventory each month and decided what to buy and how much. That carried the business for years, and it broke down in four specific places.

No forward-looking signal
Reviews looked backwards at historical sales and nothing else. There was no systematic way to answer one question up front: is this specific product going to sell, and roughly how much, over the next few months. Without that answer every buy is a judgment call, and judgment calls do not scale.

Capital trapped in products that never sold
Money goes into stock that does not move, which is cash tied up in inventory plus storage plus whatever the team could have bought instead. Eventually it is a write-off.

Winners caught late, or missed entirely
The failure most teams underweight. Products that sold out early because nobody spotted them in time, or because nobody had the confidence to put real money behind them. Margin left on the table is harder to see than stock sitting in a warehouse.

New products worst of all
Two years of sales history at least gives you something to extrapolate from. A product with none is pure instinct, and those are the buys where the stakes run highest, because nobody has learned anything about them yet.

What we built

The system sits between the reseller’s sales history and its purchase orders. Two data sources feed an ETL pipeline on Google Cloud, which lands everything in one clean feature layer. Products are grouped by how they behave in the market, each group gets its own forecasting model, and a confidence layer turns the raw prediction into a range a buyer can act on. A forecast API serves it to the buying team, and a drift monitor retrains the models before accuracy quietly decays. The order itself stays with the buyer.

The sequence those layers run in is the whole trick.

Two sources feed it. The first is the client’s own sales, units, and pricing, pulled directly from Amazon’s Selling Partner API. The second is large scale external Amazon market data from Keepa, which is what lets the system say something useful about a product the client has never sold.

Both APIs throttle hard, with tight rate limits and quotas the pipeline is constantly bumping into at this scale. A naive ingestion job either falls over or silently drops data, and incomplete data quietly poisons every forecast downstream. So a real chunk of the work went into ingestion that respects those limits, backs off, retries, checkpoints, and resumes without double counting. That reliability layer is invisible when it works and catastrophic when it does not.

Solution 1

Grouping products by how they sell

Category and brand tell you almost nothing about demand. A steady staple and a promo-driven spike can sit side by side in the same category and behave nothing alike. So the first layer groups products by market behaviour: demand rhythm, how they ramp and taper, seasonality, and price sensitivity.

K-means over roughly 12 million Keepa ASINs produces five behaviour clusters. Long-tail-steady, steady-staple, seasonal-peak, spiky-promo, and fast-ramp. Separation is clean at a silhouette of 0.52 and mean coherence of 0.74. Brand new products have no behaviour history to cluster on, so they route to a cold start path and join a cluster once they have built enough.

This layer is where accuracy had been leaking. One global model averaging across products with nothing in common produces a number that fits none of them.
Solution 2

A model per behaviour, and a path for cold start

Five behaviour models plus one cold start model, all built on a fine-tuned Chronos-2. Chronos-2 is a time-series foundation model, chosen because it can take a very short history and project it forward into a real three-month forecast rather than noise. A product with history flows through its cluster’s model. A brand new product routes to cold start.

Cold start was the harder of the two problems on this build. Most teams wave their hands at forecasting a product with no history, because it is genuinely hard. No single clever model solved it. It took three things working together: the first month of sales as an early signal, the behavioural comparables the clustering provides, and a confidence layer honest enough that a buyer trusts a wide range instead of dismissing it. Calibrating that confidence is the part most people skip.

Every forecast goes down to size and colour, across 13 weeks at monthly resolution, and it comes back as a range rather than a single number. A demand band with a stated confidence level, corrected for the model’s tendency to run systematically high or low, alongside the cluster the product was matched to and the comparables it was matched against. That is the rationale a buyer needs to defend the order, and for someone committing real money to inventory, an honest range is worth far more than a false-precise figure.
On a held-out set of 4,030 ASINs the forecaster lands at an R² of 0.83, which is 85.8% accuracy on a weighted error basis. Accuracy tapers honestly with horizon, from 88.4% in month one to 79.1% in month three, and the 80% confidence band holds 86% of the time. Seasonal peaks land where they should, Prime Day and December included.
Solution 3

One call per product, one run per month

The forecaster runs as an API on Google Cloud Run, currently v4. A buyer passes a product’s ASIN and gets two things back: which behaviour cluster it sits in along with its nearest comparables, and a 13-week forecast with p10, p50, and p90 bands plus a total for the period. Model metrics come back with every response, so the number never arrives without its own error bars. That is the entire integration surface. No dashboard to learn, no export to reconcile.

The same forecast runs in batch once a month against the incoming supplier list. Each candidate gets checked on two axes, projected demand and margin at supplier cost, and only comes forward when both hold. A popular product that barely breaks even does not get mistaken for a winner. That monthly pass turns a forecast into a replenishment shortlist the buying team can work straight through.
Two calls: which cluster is this product in, and what will it sell.
Solution 4

Watching its own accuracy and retraining

Data shifts quarter over quarter, and a model that was right last year quietly stops being right. Vertex AI watches two things: whether incoming Keepa and sales data has started to look different from what the model trained on, and whether rolling forecast error is creeping up against recent actuals. Either one crossing its threshold triggers a retrain, which validates against a frozen test set and promotes behind a canary, so a bad retrain never reaches production.

It currently reads a data drift PSI of 0.08 against a retrain threshold of 0.20, and model drift of 1.3 points against an alarm at 5. The last automatic retrain was 13 July 2026, validated and promoted without anyone touching it. This is the piece still rolling out, and it is how the accuracy number climbs from here instead of decaying.

Conclusion

The largest recurring capital decision in the business now runs on a number instead of an instinct. Buying went from "I think this will sell" to "the model projects this range over the next three months, at this confidence, and here is the basis for it." It works on both ends: less money trapped in products that do not move, and more of the genuine winners caught early. Scope has expanded since launch, which is usually the clearest signal something is earning its place.

Products do not all sell the same way, and the whole system is built around that. Detect the pattern a product follows, route it to the behavioural segment and model that fit, and everything downstream works. Get the pattern detection wrong and no amount of model tuning saves you.

Want a forecasting system built like this one? Get in touch.

86%

Forecast accuracy on held-out products

12M

Amazon products behind every forecast

5 mo

From raw data to a live system

Data sources: Amazon Selling Partner API  |  External market data: Keepa
Pipeline: Automated ETL on Google Cloud (ingest, de-duplicate, FX-normalise, aggregate)
Models: Fine-tuned Chronos-2, five behaviour-cluster models plus one cold-start  |  Clustering: K-means, K=5
Serving: Forecast API v4 on Google Cloud Run  |  Horizon: 13 weeks at monthly resolution
Monitoring: Vertex AI drift detection, automated retraining, frozen-set validation, canary promotion

About JWC
A privately held e-commerce business built on product reselling, and one of the top 100 resellers on Amazon. What to stock and how much is the largest recurring capital decision it makes.
Tags
Product & engineering
Tech stack
Chronos-2 (Amazon)
Keepa
Vertex AI
Want similar results?
We build AI agents and software for teams ready to move faster.
Get in touch
contact image