Compass Analytics: Technical Reference
This page covers the technical side of Compass analytics: how clicks are attributed, how to read the Advanced view when diagnosing your integration, and the endpoints behind the numbers.
For what the Overview dashboard shows and what each headline metric means, see Compass Analytics Overview on the Arc Learning Center. For the editorial actions in the same app, see Compass Admin UI: Editorial Controls.
How clicks are attributed
An impression is a recommendation exposure: a reader saw the story in a recommendation slot, qualified by the viewport. It is not a count of recommendation API requests or of lists rendered.
Clicks fall into three classes:
| Click class | What it is | How to use it |
|---|---|---|
| Confirmed clicks | A click that carried valid attribution context and matched an exposure of that same story inside the attribution window. | The CTR numerator. This is the customer-facing click number. |
| Context-only attributed clicks | A click that carried valid attribution context but never matched an exposure. | Real evidence of recommendation-driven engagement. It does not raise CTR, and it must never be turned into a second CTR. |
| Unattributed clicks | A click with no usable attribution context. | Evidence that interaction happened — nothing more. Never derive a rate from it (see the caution below). |
Why confirmed CTR is a lower bound
Matching a click to its exposure is one-shot. Event files arrive out of order — that is normal with batched delivery — and if a click is processed before the exposure that produced it, the click is permanently classified as context-only. It is never promoted to confirmed when the exposure lands later.
So confirmed CTR slightly undercounts, and the size of the undercount moves with your delivery patterns. If you need to see how much is being missed, the context-only series in Clicks by type is that gap.
The advanced view
The View all metrics button allows you to dive deeper into performance of the recommendations API*. This view is where you diagnose the quality of the data feeding recommendations, rather than the performance of the recommendations themselves.
Clicks by type
The three click classes from above, charted:
- Confirmed — clicks matched to a specific recommended story.
- Context only — clicks with attribution context that couldn’t be matched to a served story.
- Attributed (total) — every click carrying attribution context: confirmed plus context-only.
A large context-only share relative to confirmed is the signature of exposure events arriving late or not at all, rather than of readers behaving differently.
Event-stream readiness
Strength of the behavioral data feeding the recommendations API. A score from 0 to 100 with a state badge, the number of events in the window, the attribution rate, and the window itself (Last 24 hours).
The two score descriptions you’ll see are “Strong enough to personalize. Recommendations are running on real behavioral signal.” at the healthy end, and “Signal quality is low. Personalization may be unreliable.” at the weak end.
Readiness describes your organization’s whole recommender pipeline, not one experience. It has no per-experience filter — Catch Up traffic is excluded from the attribution-completeness dimension but still counts toward total events and user reach.
Readiness dimensions
Seven dimensions, each with a value and a status. The remediation text below is the guidance the UI itself shows:
| Dimension | What it measures | Unit | If it’s below target |
|---|---|---|---|
| Volume | Total events received in the rolling window | events | Increase event volume from your integration, or widen the time window. |
| Attribution completeness | Share of recommendation events carrying usable attribution context | of events | Include attribution context on recommendation events so clicks can be matched. |
| Diversity | Number of distinct event types seen | event types | Emit a wider range of event types, such as exposures, clicks, and conversions. |
| Distinct users | Estimated distinct users seen | users | Drive more unique users to recommended content, or widen the window. |
| Engagement depth | Average events per distinct user | events / user | Encourage repeat interactions per user across a session. |
| Item concentration | Share of activity captured by the single most active story | in top item | Spread recommendations across more items so activity is less concentrated. |
| Recency | How recently the latest event arrived | since last event | Check that events are flowing in near real time without delivery lag. |
Each dimension — and the overall score — carries one of five states:
| State | Meaning |
|---|---|
| Healthy | Meeting the target. |
| Warn | Below target, still usable. |
| Weak | Well below target. |
| Insufficient data | Not enough events yet to assess. |
| Not applicable | Not measurable for this window. |
Attribution completeness is the dimension to fix first if it’s low: it is what determines whether clicks can be matched to exposures, and therefore whether your CTR is meaningful at all. See Recommendation Attribution for the tagging that populates it.
Two readiness states are easy to mistake for a broken integration:
| What you see | What it means | What to do |
|---|---|---|
| A readiness score of 0 with Insufficient data states | Not empty. Events exist, but the rolling count is under the floor needed to assess quality. | Nothing is broken. Get more traffic through recommended content, or widen the window. |
| No readiness reading at all | Nothing has been projected yet for this organization. | Expected before the first events land. If events are flowing, treat it as an integration problem. |
Readiness over time
The same score as a trend, which is the more useful read: a readiness score sliding down over several days points at an integration that is degrading, and is worth investigating even while the absolute number still looks acceptable.
Item performance
Top recommended items ranked by exposure volume. A table of your stories covering the story, its title, impressions, confirmed clicks, CTR, and average served position.
Two things to know about this table:
- Titles are best-effort. The title is looked up at read time and shows as (no title) for a story that has since been deleted or is otherwise missing from the catalog. The metrics for that row are still valid.
- It is a truncated ranking, not a paginated list. There is no next page. If the view reports that results were truncated, the ranked list was longer than the row limit — narrow the time window or the surface filter to see further down.
A Show raw data affordance exposes the underlying response for the view.
Where Catch Up numbers come from
Catch Up has no dedicated analytics endpoint. Its numbers come from the same recommendation analytics endpoints, filtered to the Catch Up experience — which is why the Overview labels match. Catch Up impressions are counted per material segment within a card, not per card, and only storyline-driven cards emit telemetry; see Compass Analytics Overview for how that changes the numbers.
Per-story Catch Up impressions and confirmed clicks reach back only about 25 hours. If you need that history, capture the per-story figures on a daily schedule and retain them yourself.
The Catch Up section’s live indicator is derived from whether a projection exists and whether any cards were served in the window, not reported directly. “No activity in window” and “nothing projected yet” are different states with different causes.
The endpoints behind the numbers
Everything in the Admin UI is served by four read-only endpoints, which you can also query directly:
| Endpoint | Powers |
|---|---|
GET /analytics/v1/ctr | Impressions, clicks, CTR, average served position, and the clicks-by-type chart |
GET /analytics/v1/engagement | Card-level Catch Up counters |
GET /analytics/v1/items | Item performance and the pinned story’s own metrics |
GET /analytics/v1/readiness | The readiness score, dimensions, and trend |
The three time-series endpoints share a query shape: a required window_start
(inclusive) and window_end (exclusive) in UTC, an optional granularity of
minute, hour, or day (hour by default), and optional site_id and
surface_id filters. /items takes a limit instead of a granularity.
/readiness takes only an optional window and defaults to the last 24 hours.
Two limits to design around: a response is capped at 1,500 time buckets and a query window at 92 days, and exceeding either is an error rather than a truncated result. Requested windows are snapped to bucket boundaries, and the response echoes the window it actually used — read that back rather than assuming your requested window was honored exactly.
An empty window is a successful response with zero counts and a null CTR; a failed request is an error. Don’t record an error as a period with no activity. No freshness information means no underlying data, not fresh data.