Skip to content

Compass Web SDK: Catch Up Card

Last updatedView as Markdown

The Catch Up card — <arc-compass-catchup-card>, one of the SDK-rendered Experiences shipped in @arcxp/compass-sdk — is a “while you were away” deck for returning readers. It recaps what has changed across the storylines a reader follows since their last visit, as a collapsed card that expands into a full-screen, Stories-style takeover.

Like every SDK-rendered Experience, it is a custom element you drop into your markup. The SDK fetches its content, renders it inside a shadow root, and gates the whole thing on reader consent — you place one tag and style it with CSS custom properties. There is no data to fetch and no card component to build.

What the card is

The card has two surfaces, both built from a single catch-up fetch:

  • The collapsed card — a compact deck with a featured story that autoplays through the reader’s moved storylines, a list of everything in this catch-up, and a “Catch me up” control. This is the entry point.
  • The takeover — a full-screen reader opened from “Catch me up.” It pages through the stories one at a time; the reader advances until they reach an “I’m caught up” confirmation and close back to your page.

The one exception to “single fetch” is the “You might also be interested in” list on the final caught-up view. It is served by a separate recommendations request, issued only if the reader reaches the end of the takeover, and you configure it with the same attributes as the recommendations Experiences — see Attributes.

The card is personalized per reader and decides its own catch-up content: which storylines moved, in what order, and what to feature. You do not pass it a query or a section — it reads the consenting reader’s identity (established by the SDK) and requests their catch-up on mount.

Content in V1

The card presents real editorial content — the real headline, the real promo image, and story text extracted from the underlying content — for each item it shows. It is a recap of what your newsroom published, laid out for a returning reader.

Minimal render

With the SDK initialized and consent resolved (see the Integration Guide), the card is a single tag:

<arc-compass-catchup-card></arc-compass-catchup-card>

That is the entire integration. On mount, the element requests the current reader’s catch-up and renders the collapsed card. If the reader has nothing to catch up on — or has not consented — it renders nothing and collapses to zero height (see Lifecycle and reserving space).

Place it where a returning reader will meet it: the top of the homepage, a section front, or a personalized landing surface.

Attributes

Every attribute is optional and is read once, when the element first mounts — changing it afterward has no effect. None of them changes the catch-up content itself, which the card decides per reader.

The card

AttributeValuesEffect
open-storyany stringOpens the takeover directly on a specific story — a storyline key or the content item’s ID. Use it to restore a reader’s place: the takeover’s open state is not part of the URL, so a reader who follows a story out and returns lands on a freshly collapsed card unless you re-open it. A value that matches no story in the current catch-up is ignored, leaving the collapsed card.
autoplayoffStops the collapsed card’s featured story from advancing by itself: it stays on the first story until the reader picks another. Only off (in any letter case) turns it off; any other value, or none, keeps autoplay, which starts paused for readers who prefer reduced motion.

The “You might also be interested in” list

The list on the caught-up view is a separate recommendations request, and you configure it with the same attributes and values as the recommendations Experiences. The request is issued whether or not you set any of them, and the list renders only when it returns items.

AttributeEffect on the list
surface-idForwarded with the list’s recommendations request, so Confirmed-CTR reporting can tell this surface apart. The older name recs-surface-id still works; if you set both, a non-empty surface-id wins.
countHow many items to request and show, capped to 50. Omit it to request and show four.
headingReplaces the list’s heading. Omit it or leave it empty to keep “You might also be interested in,” translated into the reader’s language.
datesrelative (default) shows each item’s relative publish date; off hides it.
authorson (default) shows each item’s author; off hides it.
premium-labelA word shown beside the lock on a premium item, for example Subscriber. Omit it and the badge is the lock alone.
<arc-compass-catchup-card
surface-id="catchup-suggestions"
count="3"
></arc-compass-catchup-card>

Theming

The card renders inside a shadow root and is themed through the --arc-compass-* CSS custom properties shared by every SDK-rendered Experience. The token table, a copy-paste brand block, and the light and dark recipe live once, in the Compass Web SDK: Theming Reference.

The Catch Up Card is the only Experience that paints a surface of its own — the full-screen takeover — so it is the one that reads the surface/on-surface pair. Set that pair and the accent/on-accent pair and you are done: every neutral in the card derives from them, so it stays coherent on a light or dark page.

arc-compass-catchup-card {
--arc-compass-font-family: Georgia, serif;
--arc-compass-font-family-secondary: "Helvetica Neue", Arial, sans-serif;
--arc-compass-accent: #b00020;
}

Styling internals with ::part()

When a token cannot express the change you need, restyle a named element with ::part(). The card exposes these parts, covering the collapsed card and the takeover it opens:

PartElement
cardThe card’s outer <section> — collapsed, and again after the reader is caught up
deckThe <header> holding the badge and the intro line
heroThe featured story: its image, the carousel dots, and the caption
headlineThe featured story’s title, or “Read the full story” when it has none
ctaThe “Catch me up” button, when there is something to open
footerThe card’s <footer>: the story count and the cta
viewerThe takeover — the full-screen dialog “Catch me up” opens
progressThe row of progress dashes at the top of the takeover
viewer-footerThe takeover’s bottom bar: “Previous,” “Up Next,” and “I’m caught up” on the last story
arc-compass-catchup-card::part(card) {
border-radius: 0; /* square corners to match a flat page */
}
arc-compass-catchup-card::part(cta) {
border-radius: 999px; /* pill-shaped "Catch me up" */
}

headline is on two elements: the caption under the hero on wide containers, and the title that replaces it at 640px and narrower. Only one shows at a time, so one ::part(headline) rule styles whichever is on screen. Do not set display on it — that would show both titles at once or hide the only one. The narrow title is also dimmed with opacity, so add opacity: 1 to the same rule if a color you set reads lighter there.

viewer, progress, and viewer-footer belong to a full-screen dialog whose layout the card owns. Change their color, background, borders, radius, padding, and type freely, but leave display, position, inset, z-index, and overflow alone: overriding those can leave the takeover under your site header, or cut off inside its own frame, while the page behind it still cannot scroll.

Part names are versioned public surface; everything else inside the shadow root is internal. The general ::part() rules and the Tailwind recipe are in the Theming Reference.

The card is gated on the same single consent decision as the rest of the SDK. Until the reader has consented, nothing renders and no events are sent — the card is silent, not an error. See Compass Web SDK: Consent & Identity.

Events

After the reader consents, the card emits three analytics events through the SDK’s normal event pipeline:

EventWhen it fires
catch_up_shownThe card is shown to the reader (a qualified impression, or when they open the takeover).
catch_up_clickThe reader clicks through to one of the stories in the catch-up.
catch_up_dismissThe reader reaches the “I’m caught up” end state and finishes the takeover. An early close (the ✕, Escape, or navigating away) does not fire it — despite the name, there is no event for an early dismissal.

Each event carries an attributionContext — the card’s exposureId, plus the moved segment’s attributionId on catch_up_shown and catch_up_click — tagged source: "fy-catchup". That pairing lets a catch_up_click be confirmed against its catch_up_shown (a Catch-Up CTR loop), and one catch_up_shown fires per material segment rather than one per card. The SDK emits all of this itself: you do not tag anything, populate attributionContext, or call track() for the card.

Lifecycle and reserving space

The card never shows a spinner, a skeleton, or an error message. It renders its content or it renders nothing, collapsing to zero height. That means there is no visual signal for your code to read — the SDK’s lifecycle events are that signal. They bubble, so you can listen on a container and read event.target:

EventMeaning
arc-compass:renderedThe card is in the DOM.
arc-compass:emptyNothing to catch up on for this reader — a successful answer, not a failure.
arc-compass:errorSomething went wrong; the element is collapsed.
arc-compass:catchup-doneThe reader finished the takeover (“I’m caught up”). May fire later, or never.

Exactly one of rendered / empty / error fires per mount after the reader has consented — the card renders behind the consent gate, so until consent resolves to granted (and never, if it is denied) it stays silent and dispatches none of the three. catchup-done is separate: it describes a reader finishing, fires later than the terminal event, and may not fire at all (a reader who never opens the takeover never completes it). Like the others, these events carry no detail.

If the card sits above the fold, reserve its space yourself and release it on the terminal event so an empty or failed response leaves no gap:

<div class="catchup-slot">
<arc-compass-catchup-card surface-id="catchup-suggestions"></arc-compass-catchup-card>
</div>
.catchup-slot {
min-height: 360px;
}
.catchup-slot.settled {
min-height: 0;
}
document.addEventListener("arc-compass:empty", release);
document.addEventListener("arc-compass:error", release);
function release(event) {
event.target.closest(".catchup-slot")?.classList.add("settled");
}

Release on empty and error only — on rendered the content is already filling the slot.

A realistic integration

Putting it together: a themed card, above-the-fold space reserved and released on the terminal events and on the two non-granted consent outcomes (so a reader who denies or ignores consent is not left with a permanent gap), a suggestions surface on the caught-up view, and a resume hook so a reader who follows a story out and comes back re-opens where they were.

<!-- The card is created in the script below so `open-story` is set *before* the
element is inserted — the attribute is read once when the card mounts and is
not observed afterward. If you don't need resume, drop the script and place
<arc-compass-catchup-card surface-id="catchup-suggestions"> here. -->
<div class="catchup-slot"></div>
<style>
.catchup-slot {
min-height: 360px;
}
.catchup-slot.settled {
min-height: 0;
}
arc-compass-catchup-card {
--arc-compass-font-family: "Publico", Georgia, serif;
--arc-compass-font-family-secondary: "Franklin", Arial, sans-serif;
--arc-compass-accent: #b00020;
--arc-compass-on-accent: #ffffff;
/* Set the surface pair so the full-screen takeover matches your page. */
--arc-compass-surface: #ffffff;
--arc-compass-on-surface: #1a1a1a;
}
</style>
<script>
document.addEventListener("arc-compass:empty", release);
document.addEventListener("arc-compass:error", release);
function release(event) {
event.target.closest(".catchup-slot")?.classList.add("settled");
}
// Those events never fire when consent is denied or never answered, so also
// collapse the reserved slot in both of those cases (see the consent caution
// above). The SDK has no consent-denied event — define a handler and wire it
// to your CMP's denial callback (the exact API differs per CMP).
function collapseReservedSlots() {
document.querySelectorAll(".catchup-slot").forEach((s) => s.classList.add("settled"));
}
// yourCmp.onDenied(collapseReservedSlots); // ← wire this up to your consent manager
// Never answered: after a grace period, collapse whatever is left — but only
// while consent is still *unresolved*. A granted decision (even one whose card
// is still loading) or a denial is already handled above, so bail if the reader
// has since answered; otherwise you risk yanking a slot a slow-but-granted
// render is about to fill.
setTimeout(() => {
if (yourCmp.consentAnswered) return; // ← your CMP's "reader has responded" flag
document
.querySelectorAll(".catchup-slot:not(.settled)")
.forEach((s) => s.classList.add("settled"));
}, 10000);
// Optional: restore the reader's place after they return from a story.
// `open-story` is read once, when the card mounts (its connectedCallback — the
// moment it is inserted into the DOM) and is not observed afterward, so setting
// it on an element already in the page has no effect. The only requirement is
// that it be present *before* the element is appended; it does not matter
// whether ArcCompass.init() has run yet. Creating the element, setting the
// attribute, then appending guarantees the value is there at mount.
//
// The read side needs a value to read, so persist it elsewhere in your app:
// when the reader opens a story from the catch-up (your own routing knows which
// one), stash its id under this key, and clear it once they are caught up —
// sessionStorage.setItem("catchup:open-story", storyId); // when a story opens
// sessionStorage.removeItem("catchup:open-story"); // when caught up
const resumeKey = sessionStorage.getItem("catchup:open-story");
const card = document.createElement("arc-compass-catchup-card");
card.setAttribute("surface-id", "catchup-suggestions");
if (resumeKey) card.setAttribute("open-story", resumeKey);
document.querySelector(".catchup-slot")?.append(card);
// Clear the resume key once the reader finishes the takeover, so the next visit
// opens a fresh collapsed card instead of re-opening the story they already
// caught up on. `arc-compass:catchup-done` fires on "I'm caught up" (see
// Lifecycle and reserving space); it bubbles, so listening on the card works.
card.addEventListener(
"arc-compass:catchup-done",
() => sessionStorage.removeItem("catchup:open-story"),
{ once: true },
);
</script>

MVP limitations

  • Single-site. The card serves one site’s catch-up per placement.
  • Enablement is provisioning-driven. Catch Up is turned on for your site by Arc XP during provisioning — there is no self-serve toggle. Contact your Arc XP representative to enable it. After Catch Up is enabled, the card begins returning content for qualifying readers; before then it renders nothing (an arc-compass:empty).

See also