Skip to content

Content Recommendations API Developer Guide

Introduction

This guide covers Arc XP’s Content Recommendations API, which delivers personalized content recommendations for your audience by learning from user behavior and your content catalog.

It is built to work with any Customer Data Platform (CDP) and any Content Management System (CMS), and deliver content recommendations on any content surface.

The Content Recommendations API is a personalization backend that connects your content catalog and audience behavior to a machine learning engine.

It provides two APIs:

APIPurposeBase Path
Collector APISend user behavior events and content updates/collector/v1
Recommendations APIRetrieve personalized content recommendations/recommend/v1

The Collector API accepts behavioral signals (page views, clicks, engagement) and content lifecycle events (publish, delete) from your applications (via your CDP) and CMS.

The Recommendations API is a read-only API that returns a ranked, personalized list for a given user. Each item carries a display-ready card, so a single call returns everything needed to render — no separate content lookup required.

Each tenant (organization) operates with a fully isolated recommendation model. Your content, your audience data, and your trained model are never shared with other tenants.

Base URL

Both APIs are served from:

https://{org}-config-prod.api.arc-cdn.net/

Replace {org} with your organization identifier; the config and prod segments are fixed. The path prefix selects the backend — /collector/v1 for the Collector API and /recommend/v1 for the Recommendations API — appended to this host.

How it works

Content Recommendations API flow

  1. You send content data in — Your CMS sends content updates via webhooks. For Arc XP customers, this is accomplished via IFX.
  2. Your apps send user behavior events (page views, clicks, engagement) — either with the first-party Compass Web SDK for web traffic, or by forwarding them from a CDP or server-side source. See the Overview to choose.
  3. The Content Recommendations API learns — The ML engine trains a personalization model on your content catalog and your audience’s behavior.
  4. You fetch recommendations out — Your applications call the Recommendations API to get ranked content for a specific user.

Authentication

Both the Collector API and Recommendations API require a Headless API token passed in the X-API-Key header. See Content Recommendations Authentication and Tokens for provisioning, key-collection separation, and token limits.

Critical requirements

These rules are non-negotiable. Violating them will either corrupt your recommendation model, leak sensitive data, or silently produce bad results.

  • Never send PII as the user identifier. user_id must be an anonymized, stable token — hash or pseudonymize before sending, because Arc XP does not sanitize user IDs on ingestion. See the User ID Guidance for the full rules.

  • Keep the content catalog in sync. Only send published content via the Content endpoint, and send an action: "delete" payload the moment an item is unpublished or deleted in your CMS. Stale content in the model leads to recommendations pointing at dead pages.

  • Use the same identifier for content and events. The item_id on every content item and the item_id on every interaction event must refer to the same, stable identifier — if they don’t match, the event cannot contribute to recommendations. See the Item ID Guidance for the full rules on stability, formatting, republish, and takedowns.

  • Do not send synthetic or test traffic against real site_id values. Load tests, QA scripts, and bot traffic poison the training signal and degrade recommendation quality for real users. Scope any test activity to a dedicated, non-production site_id.

  • Exclude internal employee traffic. Events from your own staff — editors QA-ing articles, newsroom staff browsing stories, engineers exercising the site — skew the behavioral signal away from real reader interests and degrade recommendation quality. Filter employee sessions out before sending to the Events endpoint.

  • Exclude bot and crawler traffic. Search crawlers, scrapers, and other automated agents do not represent real reader interest, and their access patterns (exhaustive crawls, repeated hits, no engagement depth) distort the training signal. Filter known bots out before sending to the Events endpoint.

  • There is no separate Sandbox or Production instance for the Content Recommendations API — you get a single instance. Anything you send is training the one model that serves your live traffic. Plan your testing, seeding, and rollout accordingly, and use a dedicated test site_id to keep experimental data out of your production catalog.

  • Handle Headless API tokens carefully. Never commit them to source control, and keep each API’s token in its own key collection — see Content Recommendations Authentication and Tokens for the handling rules.

Quick Start (5 minutes)

The shortest path from zero to your first recommendation:

  1. Provision Headless API tokens — one for the Collector API and one for the Recommendations API, following Content Recommendations Authentication and Tokens. Pass the appropriate token in the X-API-Key header on each request below.

  2. Send contentPOST /collector/v1/content with an action: "publish" payload for each item in your catalog. This seeds the model with what’s available to recommend.

    POST /collector/v1/content
    { "action": "publish", "item_id": "ARTICLE-001", "site_id": "my-site", "type": "article", "timestamp": "...", "title": "..." }
  3. Send eventsPOST /collector/v1/events as users interact with that content. At least a few events per user are needed before personalization kicks in.

    POST /collector/v1/events
    { "user_id": "user-1", "item_id": "ARTICLE-001", "event_type": "page_view", "timestamp": "..." }

    On a website, the Compass Web SDK captures and posts these events for you — you paste a snippet instead of hand-rolling this request. The raw POST shown here is what a server-side or CDP forwarder sends; it’s also the contract the SDK implements under the hood.

  4. Fetch recommendationsGET /recommend/v1/recommendations?site_id=my-site&user_id=user-1 returns a ranked list of recommendations, each with a display-ready card ready to render.

Once this loop is in place, the remaining sections of this guide cover the full field reference and supported event types.

Collector API

Base path: /collector/v1

The Collector API accepts two types of data: user behavior events and content lifecycle events. Both are processed asynchronously — the API responds immediately with 202 Accepted and processes data in the background.

It exposes two endpoints: the Events endpoint for user interactions and the Content endpoint for content lifecycle updates.

Every request must include your Collector API Headless API token in the X-API-Key header.

Events endpoint

Send user interaction events to train the recommendation model. The more behavioral data you send, the better the recommendations become.

Endpoint: POST /collector/v1/events

Response: 202 Accepted (no body)

{
"user_id": "abc-123",
"item_id": "ZSGXFR2KNFCMPN3VHPWQR3BGCE",
"event_type": "page_view",
"timestamp": "2026-03-27T14:30:00+00:00",
"session_id": null
}

Fields

FieldTypeRequiredDescription
user_idstringYesAnonymized identifier of the user who triggered the event. Can be an authenticated user ID or an ephemeral session ID for anonymous users, but it must be anonymized before sending to Arc XP.
item_idstringYesThe content item the user interacted with. Must match an item_id previously sent via the content endpoint.
event_typestringYesThe type of interaction. See Supported Event Types.
timestampstring (ISO 8601)YesWhen the interaction occurred. Must include timezone information (e.g., +00:00 or Z).
session_idstringNoSession identifier for grouping interactions within a single user visit.
event_valuenumberNoNumeric magnitude for the interaction, conventionally a 0.01.0 ratio (e.g. deepest_scroll depth).
event_idstringNoDe-duplication key. If omitted, the Collector derives it deterministically from the event’s natural identity (user_id, item_id, event_type, timestamp, session_id). Omit it unless your source emits its own stable per-event ID.
schema_versionintegerNoLeave unset. Any value other than 1 is rejected by design.

Supported Event Types

Event TypeDescription
page_viewUser viewed a content detail page, such as article page.
clickUser clicked on a content link, including from recommendations modules.
shareUser shared content, such as clicked on share on Facebook.
article_saveUser saved the article to read later, such as via bookmarking.
searchUser performed an on-site search. Requires topic or keyword extraction to be relevant.
deepest_scrollThe maximum depth that the user consumed a given piece of content, expressed as a number (0.0–1.0). Do not send multiple observations for the same piece of content within the same user session.
engaged_readAn organization-defined metric that represents a reader consuming, being highly engaged with a piece of content, such as leaving a comment, spending a robust amount of time on page, etc.

Example: Page View

{
"user_id": "u_314",
"item_id": "a_202",
"event_type": "page_view",
"timestamp": "2026-04-08T10:15:00Z"
}

Batch ingestion

For high-volume or backfill scenarios, send multiple events in a single request via POST /collector/v1/events/batch. The request body is a JSON array of the same event envelope shown above, and the response is the same 202 Accepted. See POST /collector/v1/events/batch in the API reference for the full schema.

Content endpoint

Keep your content catalog in sync with the Content Recommendations API. Content is sent as webhook payloads from your CMS whenever an item is published, updated, or deleted.

Endpoint: POST /collector/v1/content

Response: 202 Accepted (no body)

The request body uses a discriminated union on the action field — either "publish" (create or update) or "delete".

Publishing or Updating Content

Send this payload when a content item is first published or when it is updated.

{
"action": "publish",
"item_id": "a_202",
"site_id": "acme",
"type": "article",
"timestamp": "2026-04-08T09:00:00Z",
"title": "Breaking: Major Policy Change Announced",
"categories": ["Politics", "Government"],
"tags": ["policy", "congress", "legislation"],
"author": "Jane Reporter",
"is_premium": false,
"metadata": {}
}
Fields
FieldTypeRequiredDescription
actionstringYesDiscriminator indicating a create/update operation.
item_idstringYesUnique identifier for this content item, typically from your CMS.
site_idstringYesIdentifies which website or property this content belongs to. Used to partition recommendations by site.
typestringYesContent type: such as "article" or "podcast".
timestampstring (ISO 8601)YesPublication date. Must include timezone.
titlestringYesDisplay title of the content.
categorieslist of stringsNoHigh-level taxonomy labels (e.g., "Politics", "Sports"). Defaults to empty list.
tagslist of stringsNoDetailed keywords for the content. Defaults to empty list.
authorstringNoContent creator name.
is_premiumbooleanNoWhether this content is behind a paywall. Defaults to false. Used for subscription-tier filtering in recommendations.
metadataobjectNoFlexible key-value pairs for tenant-specific fields. Defaults to empty object.

Deleting Content

Send this payload when content should be removed from recommendations.

{
"action": "delete",
"item_id": "a_202",
"site_id": "acme"
}
Fields
FieldTypeRequiredDescription
action"delete"YesDiscriminator indicating a delete operation.
item_idstringYesThe item to remove.
site_idstringYesThe site the item belongs to.

Deletes are soft: the item is marked as deleted and excluded from future recommendations.

Recommendations API

Base path: /recommend/v1

The Recommendations API returns personalized, ranked content for a given user.

Every request must include your Recommendations API Headless API token in the X-API-Key header.

Fetching Recommendations

Endpoint: GET /recommend/v1/recommendations

Query Parameters

ParameterTypeRequiredDefaultDescription
site_idstringYesScopes recommendations to a specific website or property. Must match site_id values used in content ingestion.
user_idstringYesThe user to personalize for. See Identifying Users for anonymous user handling.

Response

The response contains a recommendations array — an ordered list of recommended items ranked by relevance. Each item carries an item_id, a relevance score, and a display-ready card object (title, author, URL, thumbnail, and other display fields) sourced from the underlying content document, so a single call returns everything you need to render — there is no separate hydration step. card is null when no matching content document is found (for example, an editor-pinned item that has not yet synced). For the field-by-field rendering flow with examples, see Rendering Recommendations: From Content IDs to Story Cards; for the authoritative response schema, see the Content Recommendations API reference.

Example: Basic Personalized Recommendations

GET /recommend/v1/recommendations?site_id=acme&user_id=u_314&num_results=10

Personalization and Filtering

The Content Recommendations API applies multiple layers of intelligence to produce relevant recommendations:

  • ML Personalization — The recommendation model learns from your audience’s behavior (page views, clicks, engagement) and your content metadata (categories, tags, authors, recency). Each user receives a uniquely ranked set of results based on their interaction history.
  • Site Partitioning — The site_id parameter ensures recommendations are scoped to a specific website. Content published to one site will not appear in another site’s recommendations.
  • Filters — Optional section and content_type query parameters scope a request to an editorial section, content type, or both. Filtering happens before ranking, so non-matching items are never scored and never compete for a slot — more efficient than excluding them in client code. See Content Recommendations API filters for the full reference.

Cold-Start Behavior

The Content Recommendations API handles two cold-start scenarios automatically:

New or anonymous users — When a user has no interaction history, the system returns popularity-based recommendations drawn from your content catalog. Results reflect what is trending among your broader audience, weighted by recency and content metadata. As the user accumulates interactions, recommendations progressively become more personalized.

New content — Freshly published content with no engagement data is still eligible for recommendations. The model uses content metadata (categories, tags, author, recency) to place new items in front of relevant audiences immediately.

No special handling is required on your part for either scenario. The API response shape is identical whether results are fully personalized or cold-started.

Recency preview before ingestion

Before your catalog has been ingested and the model has trained, GET /recommend/v1/recommendations still returns a usable response so you can build and validate your rendering ahead of go-live. In this state the API returns the five most recent active catalog items as a recency preview.

Preview items are fully enriched and carry the same attribution as personalized results, so your card-rendering code exercises the real response shape. What they do not carry is a relevance score — every preview item is scored 0.0. A response whose items are all scored 0.0 is the signal clients use to distinguish a preview from personalized results: no reranker is run, and no editorial signals (boosts, buries, pins) are applied to a preview.

If the catalog has no content yet — nothing has been ingested at all — there is nothing to preview, and the request falls through to the existing 403 response.

Integration Guide

Identifying Users

The user_id parameter is required for both sending events and fetching recommendations, and it is your responsibility to provide a consistent, anonymized identifier for each user. See the User ID Guidance for anonymization, stability, and login-transition rules.

Content Sync from Your CMS

The Content Recommendations API stays in sync with your content catalog through webhooks. Configure your CMS to send POST /collector/v1/content requests whenever content is published, updated, or deleted. This provides near-real-time sync.

Arc XP CMS customers: Contact your Technical Account Manager for access to the IFX Recipe, which wires up the content webhook end-to-end without custom code. For the install steps and the bundle’s internals, see the end-to-end setup guide and the IFX Handlers Guide.

Other CMS customers: Build a direct integration from your CMS to the Content endpoint. At minimum, your CMS (or an intermediary service) must:

  • Listen for publish, update, and delete events in your CMS.
  • Transform each event into the appropriate action: "publish" or action: "delete" payload described under Content endpoint.
  • POST the payload to /collector/v1/content with your Headless API token in the X-API-Key header.
  • Handle retries on transport-level failures (connection errors, 5xx responses). Do not retry on 202 Accepted — that means the payload was accepted for async processing.

Whichever path you take, the goal is the same: every publish, update, and unpublish in your CMS must reach the Content endpoint, ideally within seconds.

Displaying Recommendations

Each recommendation carries a display-ready card object, so one call to GET /recommend/v1/recommendations returns everything needed to render — no separate lookup against your CMS. Render the cards in the order returned (the list is already ranked), skip any item whose card is null, and send a click event back to the Events endpoint when a user clicks a recommendation. For a full rendering walkthrough — TypeScript + React examples and empty/error-state handling — see Rendering Recommendations: From Content IDs to Story Cards.

Onboarding for good recommendations on day one

The Quick Start gets the plumbing working, but a freshly provisioned model knows nothing about your catalog or your audience — launch on it and readers see generic, popularity-based results. Front-load your content catalog and historical behavioral signal before any user-facing surface is switched on. The pre-launch steps are laid out phase by phase in the Content Recommendations Onboarding Checklist; for the mechanics of seeding your back catalog, see the Content Collector Bulk Load Guide, and for replaying historical events from a CDP or analytics source, see Connect Your CDP to Content Recommendations.

Troubleshooting

Use this section when recommendations aren’t behaving as expected. Most issues trace back to catalog sync, event volume, or cold-start behavior being misread as a bug.

No recommendations returned

If the response comes back with an empty recommendations array, the model has nothing to rank for that user and site.

  • Check content ingestion first. Query your CMS integration or webhook logs to confirm POST /collector/v1/content calls are succeeding. A model with no catalog cannot return anything.
  • Confirm site_id matches. The site_id on the recommendations request must exactly match the site_id used during content ingestion. A typo silently partitions your catalog into an empty sub-model.
  • Check for over-aggressive deletes. If your CMS sends action: "delete" for items that are still live, the model excludes them from results. Audit your unpublish / delete pipeline.

Recommendations look low-relevance or generic

If the API returns results but they feel random or generic, the model likely doesn’t have enough behavioral signal yet.

  • Check event volume. The model improves with more interactions. If you’re only sending page_view events — or only sending them for a small fraction of your traffic — personalization quality will be weak. Add richer event types (click, article_save, deepest_scroll, engaged_read) where appropriate.
  • Verify user_id consistency. If the same person shows up under different user_id values across sessions, the model can’t accumulate history on them. Confirm your anonymization scheme produces stable IDs per user.
  • Check content metadata quality. Missing categories, tags, or author values reduce what the model can reason about, especially for new content that has no engagement signal yet.

New user or new content looks “cold”

Cold-start is expected behavior, not a bug — see Cold-Start Behavior for how the API handles it.

  • New or anonymous users and newly published content are handled automatically, as described in that section.
  • If you’re evaluating the API with a brand-new tenant, expect the first wave of results to look generic. Seed the model with historical content and a representative volume of events before drawing conclusions about relevance.