Recommendations
allegro.recommendations fetches ranked article recommendations for the current
reader and reports clicks on them, so you can build a "Read Next" or "More Like
This" module on your site.
How ranking works
Recommendations come from a ladder of strategies, tried in order until enough articles are found:
- Taste — articles matched to the reader's own reading history.
- Similar — articles similar to the one they're currently on.
- Trending — articles currently getting the most engagement site-wide.
Articles the reader has already read are excluded at every rung. Each returned
item's strategy field tells you which rung produced it.
Basic usage
window.allegro.push(async function (allegro) {
const { items } = await allegro.recommendations.get({ limit: 6 });
const list = document.querySelector('#recommendations');
items.forEach(function (item) {
const link = document.createElement('a');
link.href = item.pagePath;
link.textContent = item.title;
link.addEventListener('click', function () {
allegro.recommendations.trackClick(item).catch(function (error) {
console.error(error);
});
});
list.appendChild(link);
});
});
Call allegro.recommendations.get() to fetch a set, render the items, and call
allegro.recommendations.trackClick(item) when the reader clicks one — pass the
same item object get() gave you, not a copy. See
Click attribution for why that matters.
trackClick() returns a promise that rejects if the click report fails — a rate
limit or a network error mid-navigation are both plausible — so always attach a
.catch(). An unhandled rejection surfaces as an SDK error in your own site's
monitoring, not ours.
Options
get() takes an options object; every field is optional:
| Option | Type | Default | Description |
|---|---|---|---|
limit | number | 6 upstream | How many articles to ask for. 24 is the maximum. |
path | string | window.location.pathname | Article to anchor the "similar" strategy on. |
maxAgeDays | number | 0 (no cap) | Excludes articles published more than this many days ago. |
device | string | the SDK's own device cookie | Reader's device id. |
Override path when you're rendering recommendations for an article other than
the one currently loaded — a widget on an article's own page, for example, that
recommends off a different anchor article. Override device only if you're
managing device identity yourself outside the SDK's cookie; otherwise leave it
to the default so click attribution and taste ranking stay tied to the same
reader.
Sorting and comparing scores
Each item carries a score, but it's only comparable within a strategy, not
across strategies. Taste and similar scores are a similarity value times a
recency decay; trending scores are engaged hours. Sorting a mixed list of items
by score produces a meaningless order — mixing a similarity fraction against a
count of hours. If you want a single ordering, keep the order get() returned,
which is already ranked by the ladder above.
Click attribution
trackClick(item) needs to know which request served item so the click can be
attributed to the right recommendation set. Passing the exact item object
get() returned always works — the SDK tracks it by identity.
If you pass a copy instead — the result of a JSON round-trip, or an item that
went through a state library that serializes it — the SDK falls back to matching
by pagePath across the 10 most recent get() calls on the page. That works as
long as the path is unique among those calls, but throws if it isn't: two
recommendation widgets on the same page could otherwise recommend the same
article and cross-attribute a click between them, silently corrupting your
click-through data.
Pass the item you rendered. Don't reconstruct it from a path or id, and don't
let it pass through JSON.stringify/JSON.parse or a store that serializes
props before it reaches trackClick().
No recommendations available
When no engine is configured for your tenant, or the engine is unreachable,
get() doesn't throw — it resolves with an empty items array and a null
requestId:
const { requestId, items } = await allegro.recommendations.get();
if (requestId === null) {
return;
}
Check for this and render nothing rather than an empty container, so a missing recommendation set doesn't leave a visible hole in your layout.
Server-to-server
Everything above runs from the browser through the SDK. If you need
recommendations from your own backend — a build step, a newsletter generator, a
batch job — there's a token-authenticated equivalent under /api/v1:
| Endpoint | Scope | Equivalent to |
|---|---|---|
GET /api/v1/recommendations | recommendations:read | allegro.recommendations.get() |
POST /api/v1/recommendations/click | recommendations:write | allegro.recommendations.trackClick() |
POST /api/v1/recommendations/preview | recommendations:read | No SDK equivalent — see below. |
See API Authentication for how to create a key with these scopes, and the generated REST API reference for full request and response schemas.
The browser SDK answers an empty items array when the engine is unreachable —
a reader can't act on the difference, and a dead widget is worse than an empty
one. The token API takes the opposite position: GET /recommendations and
POST /recommendations/click answer 502 Bad Gateway instead, because a
server-to-server caller can retry or alert on that, and silently swallowing the
failure would just hide an outage from you.
Preview
POST /api/v1/recommendations/preview has no SDK equivalent. It ranks
recommendations against a hypothetical reading history you supply, rather than a
real visitor's session — useful for testing how the ranking engine responds to a
given history, or for building tooling around it. Send up to 50 reads, oldest
first:
curl https://acme.allegrocdp.com/api/v1/recommendations/preview \
-H "Authorization: Bearer <your-key>" \
-H "Content-Type: application/json" \
-d '{
"reads": [
{ "path": "/news/first-article", "seconds": 45 },
{ "path": "/news/second-article", "seconds": 120 }
],
"limit": 6
}'
An empty reads array previews what a just-arrived visitor with no history
would see. The response echoes back each read's contribution to the taste
vector (weight, share, and whether the path was found in the catalog)
alongside the items that history would produce.
Preview depends on the tenant's configured recommendation engine supporting it.
A tenant with no engine configured gets 501 Not Implemented rather than a
crash or an empty response — check for that status before assuming the request
failed for another reason.
Related
RecommendationsNamespace— Full SDK method reference.RecommendationItem— Shape of one recommended article.- REST API reference — Full server-to-server endpoint documentation.