Skip to main content

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:

  1. Taste — articles matched to the reader's own reading history.
  2. Similar — articles similar to the one they're currently on.
  3. 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:

OptionTypeDefaultDescription
limitnumber6 upstreamHow many articles to ask for. 24 is the maximum.
pathstringwindow.location.pathnameArticle to anchor the "similar" strategy on.
maxAgeDaysnumber0 (no cap)Excludes articles published more than this many days ago.
devicestringthe SDK's own device cookieReader'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.

Guidance

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:

EndpointScopeEquivalent to
GET /api/v1/recommendationsrecommendations:readallegro.recommendations.get()
POST /api/v1/recommendations/clickrecommendations:writeallegro.recommendations.trackClick()
POST /api/v1/recommendations/previewrecommendations:readNo 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.

This API reports failures instead of degrading

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.