Skip to content

Popular and Trending Recommendations

This guide is for client developers integrating the Popular and Trending recommendation endpoints, and for producers sending the events that feed them.

Popular and Trending are two site-wide recommendation endpoints. They rank a site’s content by how readers engage with it, with no personalization and no user identity. Popular ranks by volume: how much a story was read over a recent window. Trending ranks by velocity: how fast a story is climbing against its own recent baseline. Both take a site, not a user, and return the same ranked list to every reader of that site, so both are anonymous and carry no PII.

They share one request shape and one response envelope with the rest of the Recommendations API, so a client that already renders personalized recommendations renders these with the same code.

Endpoints

SurfaceEndpointRanks by
PopularGET /recommend/v1/popularEngagement volume over a recent window
TrendingGET /recommend/v1/trendingEngagement velocity (recent window vs a prior baseline window)

Both endpoints are part of the Recommendations API and are served from the same base URL and token as the rest of that API. Every request must carry your Recommendations API Headless API token in the X-API-Key header. See the Content Recommendations API Developer Guide for the base URL and token provisioning.

Request parameters

Popular and Trending take the same query parameters.

ParameterTypeRequiredDefaultDescription
site_idstringYesnoneScopes the ranking to one website or property. Must match the site_id used when ingesting content and sending events.
num_resultsintegerNo5Number of items to return. Range 1 to 50; values outside the range are rejected with a 422.
surface_idstringNononeAn opaque label for the surface where the set is rendered. The endpoint echoes it back in the response and does not interpret it.

These endpoints are anonymous, so they do not accept user_id or item_id; supplying either, or any other unrecognized parameter, returns a 422. Sending site_id alone is enough to get a ranked list.

A minimal request passes only the site scope and returns five items:

GET /recommend/v1/popular?site_id=acme&num_results=5

Response

Both endpoints return a RecommendationResponse, the same envelope the personalized /recommendations endpoint returns. It has two parts: a recommendations array ordered best-first, and a response-level attribution object.

Each item in recommendations carries its ranking score, a display-ready card (plus the same display fields flattened onto the item), its zero-based position, and a per-item attribution_id. As with personalized results, one call returns everything needed to render; there is no separate content lookup.

GET /recommend/v1/popular?site_id=acme&num_results=2
{
"recommendations": [
{
"item_id": "a_202",
"score": 1.0,
"title": "Breaking: Major Policy Change Announced",
"type": "article",
"timestamp": "2026-07-15T09:00:00Z",
"categories": ["Politics"],
"tags": ["policy", "congress"],
"author": "Jane Reporter",
"is_premium": false,
"url": "https://acme.example/politics/policy-change",
"thumbnail_url": "https://acme.example/img/policy.jpg",
"card": {
"title": "Breaking: Major Policy Change Announced",
"author": "Jane Reporter",
"url": "https://acme.example/politics/policy-change",
"thumbnail_url": "https://acme.example/img/policy.jpg"
},
"position": 0,
"attribution_id": "att-9f2c4e7a8b1d4c0e"
},
{
"item_id": "a_198",
"score": 0.62,
"title": "City Council Approves Budget",
"type": "article",
"card": { "title": "City Council Approves Budget", "url": "https://acme.example/local/budget" },
"position": 1,
"attribution_id": "att-3b7d1f90c2a64e55"
}
],
"attribution": {
"exposure_id": "exp-1a2b3c4d5e6f7089",
"issued_at": "2026-07-16T14:30:00Z",
"surface_id": null
}
}

Render each item’s card fields in the order returned, and skip any item whose card is null (a card is null only when no matching content document exists yet). For the field-by-field rendering flow, see Rendering Recommendations: From Content IDs to Story Cards. For the authoritative schema, see the Content Recommendations API Reference.

Score

score is normalized to (0.0, 1.0] for engagement-ranked items: the top item scores 1.0 and every ranked item scores strictly above 0.0. A score of exactly 0.0 is reserved for recency-backfilled items. See Graceful degradation. Use score to rank, not as an absolute popularity figure; the value is relative to the top item in the same response.

Attribution round-trip

Every response carries attribution so clicks can be tied back to the exact set and slot they came from. This is the same round-trip the personalized endpoint uses, and it is how these endpoints participate in Confirmed CTR.

The response-level attribution object holds:

  • exposure_id: one opaque identifier for the whole rendered set.
  • issued_at: when the set was issued (UTC).
  • surface_id: the value you sent on the request, echoed back; null when you did not send one.

Each item in recommendations also carries its own attribution_id and position.

When a reader is shown the set or clicks an item, send the corresponding event back to the Collector’s Events endpoint carrying the exposure_id, that item’s attribution_id, and its position, verbatim. These identifiers are opaque: they carry no campaign, model, or internal-system structure, so round-trip them as-is rather than parsing them.

Caching

Both endpoints set no-store cache directives, so treat every response as uncacheable: request a fresh one per render, and do not store it in a shared cache or reuse it across readers. Each response mints its own exposure_id and per-item attribution_id, so serving one reader’s response to another would collapse their clicks onto the same attribution and skew your click metrics.

Graceful degradation

For an active tenant and a valid site_id, these endpoints do not return an empty list while the catalog has active content. When engagement ranking produces fewer items than num_results (a new site, a quiet window, or items removed by an EXCLUDE signal), the endpoint backfills the remaining slots with the most recently published active items.

Backfilled items are scored exactly 0.0, which distinguishes them from engagement-ranked items (always above 0.0). A response whose items are all scored 0.0 means the ranking had no engagement data to work with and the whole list is recency backfill.

The endpoint returns a 403, rather than an empty list, only when it cannot serve the request at all:

  • The tenant is not eligible for these endpoints (its status is neither active nor onboarding).
  • The tenant is still onboarding and has no ingested content yet, so there is nothing to rank or preview.

Editorial signals and eligibility

These endpoints reflect what a site’s readers actually read, so editorial steering signals do not reorder them. Only the EXCLUDE signal applies: an excluded item is dropped from the ranking (and from recency backfill), which keeps EXCLUDE working as the takedown and brand-safety control it is on every surface. PIN, BOOST, and BURY are ignored here; use the personalized endpoint if you need those. See Editorial Signals for how signals are defined.

A tenant that is still onboarding (content ingested but the model not yet trained) is served the most recent active catalog items as a recency preview (all scored 0.0), the same preview state described for the personalized endpoint.

Producer-side site_id contract

Popular and Trending rank per site, so the events they rank must carry the right site_id. That value is set on the producer side, when you send events, not on the recommendation request.

Declaring site_id

Set site_id in whichever way matches how you send events:

  • Web SDK: add <meta name="arc-compass:site-id" content="your-site-id"> to the page. Automatic page_view capture re-reads this tag on every view, including on each SPA route change, so a multi-site SPA that updates the tag per route attributes each view to the right site with no extra code. Manually tracked events (including video_start) instead use the value read once at initialization; on a multi-site SPA, pass siteId to that track() call so the event is attributed to the current site rather than the one loaded first.
  • CDP or server-side adapter: populate the site_id field on the event envelope with the same site_id you use when ingesting that site’s content. See Connect Your CDP to the Recommender API.

Use the same site_id string across content ingestion, events, and the recommendation request. A mismatch partitions engagement onto a site the request never asks for.

When site_id is omitted

Unlike item_id, site_id is optional on the event envelope: a single-site tenant can leave it off. An event that arrives without a site_id is still accepted; it is not dropped and it is not guessed from item_id.

But without a site_id there is no site to attribute it to, so the event is counted-but-skipped: it is tallied as a missing-site_id event and left out of every site’s ranking, rather than misattributed to a site it may not belong to. If a producer that should be sending site_id stops, the events keep flowing but stop feeding the ranking. Confirm your producers stamp site_id before relying on Popular or Trending for a multi-site tenant.

Which events feed the ranking

In v1, only page-view and video-start events feed the popularity and trending rankings, counted equally. Recommendation exposures, impressions, and clicks are deliberately excluded so the recommender cannot inflate its own ranking, and other event types (video progress, shares, search, and the rest) do not count toward these endpoints.

Trending takes the same request parameters as Popular and returns the same RecommendationResponse. It differs only in how it orders items. Instead of ranking by raw volume, it ranks by velocity: it compares each item’s volume in a recent window against what a prior baseline window predicted, so a story climbing fast ranks above a story that is merely large and steady.

A minimum-volume floor keeps a small absolute rise from topping the list: an item must clear a recent-volume threshold before its velocity is considered, so a story going from a handful of views to a few more does not out-rank a genuine breakout however large its ratio. An item with no baseline is treated as a breakout and ranked by its recent volume.

Recency backfill, the 0.0 backfill marker, attribution, EXCLUDE-only signals, tenant gating, and caching all behave the same as on Popular.

See also