Bringing your own ranking
By default, core puts the products in order by the shopper's signals. You might already have a ranking you trust, such as a bought-together list, a model trained on your own orders or a row a merchandiser picked by hand. Pass rank: 'given', and the order you send is the order that renders.
Keeping your order
import {
createComponentGenerator,
parseTrackingInput,
type TrackingInputDraft,
} from '@rudra-js/core';
const generator = createComponentGenerator({
provider: null,
rank: 'given',
});
const fromYourRecommender: TrackingInputDraft['candidates'] = [
{
sku: 'SK-201',
title: 'Merino Hiking Socks',
category: 'Socks',
price: 22,
reason: 'Bought together with this shoe',
},
{ sku: 'GT-310', title: 'Trail Gaiters', category: 'Accessories', price: 35 },
{ sku: 'TR-104', title: 'Ridgeline Trail Shoe', category: 'Trail Running', price: 139 },
];
export async function boughtTogether(shopperId: string) {
const input = parseTrackingInput({
user: { id: shopperId },
context: { surface: 'pdp', currentSku: 'TR-102', currentCategory: 'Trail Running' },
candidates: fromYourRecommender,
});
const spec = await generator.generate(input);
return { spec, products: input.candidates };
}fromYourRecommenderstands for the list your ranking returns, best first.parseTrackingInputkeeps it in that order ascandidates. The socks show first, then the gaiters, then the trail shoe.- Core still leaves out any product this shopper can't be shown, such as one in their basket. It checks every signal you sent, so a shopper with a long order history is covered too.
rankworks in the default mode and in the block core builds without a model. In per-shopper mode the model picks the order instead.
Writing the line under each product
Each candidate can carry its own reason, the line shown under its card. Use it when your ranking knows something the signals don't. In the sample, the socks say “Bought together with this shoe”.
Core shows your reason as you wrote it, the same as the product title. It doesn't check it for claims. That holds in the default mode and in the block core builds without a model. In per-shopper mode the model writes every reason, and core checks each one.
With no reason of your own, core writes one from the shopper's signals, such as “More in Trail Running” or “Goes with what is in your cart”. Core doesn't check its own lines either.
What each line can claim
Each product in the block also carries a basis, a code for why it's there. As the block is served, core checks the basis against the shopper's signals. When the check fails, core drops the line and the badge under that product.
| Basis | Core keeps it when |
|---|---|
most_viewed | The product is among the ones the shopper viewed most. |
similar_to_current | The product is in the category being browsed. |
liked_category | The shopper bought, liked, carted or viewed something in its category. Browsing a category page doesn't count. |
complements_cart | The basket isn't empty. |
complements_purchase | The shopper has bought something before. |
popular | Always. It claims nothing. |
The two complements bases prove less than they read. Core can't know that one product goes with another. So “Goes with what is in your cart” only means the basket has something in it. If your ranking knows what goes together, say so in reason.