
A buyer's journey is not a single action. It is a series of events in order:
Search → View Product → Add to Cart → Favorite → Purchase
Think of it like reading a sentence:
| Random words | Ordered sentence |
|---|---|
| "pizza hungry I am" | "I am hungry for pizza" |
| Hard to understand | Clear meaning |
The same events in different orders carry different meaning.
A good recommendation system must read the full sequence, not just a summary like "this user likes shoes."
Instead of asking:
"What does this user generally like?"
Ask:
"Given everything that happened so far, what comes next?"
This is called next-token prediction — the same idea behind how ChatGPT works, but applied to products instead of words.
[Search: boots] → [View: brown boots] → [View: black boots] → PREDICT: ???
The model learns to predict the next product in the sequence.
An autoregressive model predicts the next item using only past items (not future ones). It uses a causal mask to enforce this:
Event 1 ✓ can see: nothing before it
Event 2 ✓ can see: Event 1
Event 3 ✓ can see: Events 1, 2
Event 4 ✓ can see: Events 1, 2, 3
This mirrors how real shopping actually unfolds — one step at a time.
Recommendation becomes a prediction problem over sequences, which is exactly where generative AI models excel.
HSTU stands for Hierarchical Sequential Transduction Units — a generative recommender architecture built specifically for sequential recommendation.
It has a critical property: favorable scaling behavior
More model capacity → Lower validation loss → Better recommendations
This is like saying: the bigger the model, the smarter it gets — and that relationship holds consistently.
| Dimension | What Changed |
|---|---|
| Data | Combined more sources (Shop app + storefronts) |
| Model | Added time encoding + better negative sampling |
| Compute | Optimized CUDA kernels for speed |
HSTU gave Shopify a foundation that improves predictably as you invest more resources into it.
Imagine a buyer who searched for t-shirts in June and bought one.
| Scenario | Naive Recommendation | Smart Recommendation |
|---|---|---|
| It's still June | More t-shirts ✓ | More t-shirts ✓ |
| It's now December | More t-shirts ✗ | Winter coats ✓ |
The same history should produce different recommendations depending on when you're asking.
They encoded time directly into the model's attention mechanism using two techniques:
RoPE = Rotary Position Encoding
Think of it like giving each event a clock stamp that the model can read:
[View boots: Oct 1] [Add to cart: Oct 1] [Purchase: Oct 2] → Current date: Dec 15
The model understands absolute time — it knows December is different from October.
This lets the model understand time gaps between events:
Event A ──── 2 hours ──── Event B ──── 3 weeks ──── Event C
A 2-hour gap means something different than a 3-week gap.
Absolute time (RoPE) + Relative gaps (attention bias) = Full temporal understanding
The model can also take the current session's timestamp at inference time, so it adapts to seasonality automatically — no manual rules needed.
Time is not just metadata. It is meaning. Encoding it properly transforms a generic sequence predictor into a commerce-aware model.
Training a model to predict the next product from millions of options is computationally impossible if you consider every product at every step.
Sampled Softmax is the solution: instead of comparing against all products, compare against a sample of products the buyer did not choose (called negatives).
True next product: Black boots ✓
Negatives (random sample): Red dress, Garden hose, Laptop stand...
The model learns: "Black boots fits here, these others don't."
| Negative Quality | What the Model Learns |
|---|---|
| Too easy (totally unrelated) | Weak, obvious boundaries |
| Informative (similar but wrong) | Sharp, precise boundaries |
Easy negatives = like asking someone to distinguish a cat from a car Hard negatives = like asking someone to distinguish two very similar cat breeds
Hard negatives make the model much smarter.
Instead of picking separate negatives for each training example, share negatives across the entire batch:
Batch of 100 examples → Share one pool of negatives
Result: Effectively larger negative pool, same memory cost
A dangerous mistake in negative sampling:
User bought: Black boots
Sampled "negative": Very similar black boots the user never saw
This is a false negative — the model is penalized for recommending something the user would probably like, just because they never saw it.
Positive-aware sampling avoids this by being careful about what counts as a true negative.
Negative sampling is not a minor training detail. It is a core scaling lever — better negatives directly improve model quality, but require careful systems engineering to manage memory.
A real recommendation system is not one model. It is a pipeline:
Retrieval Models (multiple) → Ranker → Aggregation → Final Recommendations
↑
Your new model lives here
A new model might score very well in isolation but add no real value to the system if it just finds the same products other models already find.
Model A finds: Products 1, 2, 3, 4, 5
Model B finds: Products 1, 2, 3, 4, 5 ← No new value!
Model C finds: Products 1, 2, 6, 7, 8 ← Adds value!
Incremental recall = finding true positives that other models miss.
Shopify used a technique inspired by boosting (a classic ML ensemble method):
Other models predict: Product X
Training signal: "Don't just repeat Product X — find what they missed"
The goal is not to build the best standalone model. The goal is to build a model that makes the entire system stronger.
Faster training = more experiments = better final model
Slow training (1 week per run):
→ Test 4 ideas per month
→ Find 1 good idea
Fast training (1 day per run):
→ Test 28 ideas per month
→ Find 7 good ideas
Iteration velocity is a competitive advantage.
They wrote optimized CUDA kernels — low-level GPU code that makes specific operations much faster.
Result: 7.3x speedup over baseline implementation.
With 7.3x faster training, they could explore:
| Parameter | Why It Matters |
|---|---|
| Model capacity | Bigger models = smarter recommendations |
| Batch size | More data per step = better learning |
| Context length | Longer history = richer understanding |
Systems efficiency is part of the modeling problem, not separate from it. A slow model that can't be iterated on is a dead end.
A model can look great in offline testing but fail in production. Shopify tracked both:
"Of the products the user actually engaged with, how many did the model retrieve in its top K recommendations?"
This is measured in the lab, before deployment.
| Metric | Result | What It Means |
|---|---|---|
| Shop Orders | +0.94% | More purchases completed |
| High-Quality CTR | +5.0% | Clicks that led to real buying intent |
| Conversion Rate | +0.71% | More browsers became buyers |
| Final Served Recall@2 | +4.8% | Better products actually shown to users |
Not all clicks are equal:
Low-quality click: User clicks, immediately leaves
High-quality click: User clicks → favorites / adds to cart / purchases
Shopify specifically tracked clicks that led to actions closer to buying.
Offline metrics are a proxy. Online metrics are the truth. The goal is to close the gap between them.
Right now, each product has a unique product ID (like a number). The model learns an embedding (a vector of numbers) for each product ID.
Product #4,521,847 → [0.2, 0.8, 0.1, 0.5, ...] (embedding vector)
With millions of products, this creates a massive embedding table — expensive to store and serve.
Instead of one ID per product, represent each product as a short sequence of tokens from a small shared vocabulary:
Traditional: Product #4,521,847 → one unique ID
Semantic ID: Product #4,521,847 → [token_42, token_7, token_156]
Think of it like how words are made from letters:
Vocabulary of 26 letters → Can express unlimited words
Small token vocabulary → Can express millions of products
| Benefit | Explanation |
|---|---|
| Smaller tables | Shared vocabulary instead of unique IDs |
| Text integration | Text tokens and product tokens in same space |
| Prompt-driven adaptation | Model can respond to natural language instructions |
Text query: "I need a gift for my mom who loves gardening"
↓
Model works in unified token space
↓
Retrieves semantically relevant products
Semantic IDs are a path toward unifying product understanding and language understanding in a single model.
┌─────────────────────────────────────────────────────────┐
│ THE GENERATIVE RECOMMENDER SYSTEM │
├─────────────────────────────────────────────────────────┤
│ │
│ INPUT: Buyer Journey Sequence │
│ [Search] → [View] → [Cart] → [Purchase] → ??? │
│ │
│ ARCHITECTURE: HSTU (scales with capacity) │
│ │
│ KEY INNOVATIONS: │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 1. Time Encoding → Seasonality awareness │ │
│ │ 2. Negative Sampling → Sharp product boundaries │ │
│ │ 3. Incremental Recall → Ensemble value │ │
│ │ 4. CUDA Optimization → Fast iteration │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ OUTPUT: Next product predictions │
│ │
│ RESULTS: +0.94% orders, +5% quality CTR │
│ │
│ FUTURE: Semantic IDs → unified text + product space │
└─────────────────────────────────────────────────────────┘
Commerce is context — and every design decision in this system is about extracting maximum meaning from that context.