Videos, podcasts, events and research for app developers
This page is for teams building their own Arcel Konnect screens on the Daily Dose API: the videos and podcasts of Discover (to embed in your own player), saving, liking, sharing and commenting, the reader's collection, events, research papers, publisher logos and in-app feedback. Every operation named here links to its entry in the reference, with its inputs, replies, errors and examples.
Listing and opening videos and podcasts
The API gives you the items and the fields to play them; your app draws the screens and embeds the player.
listExplorewithkindset tovideoorpodcastlists the items a page at a time (sortlatestorpopular, the filters of the reference, andcursorfor the next page).getExplorelists the kinds Discover offers.getExploreItemopens one item.listUpNextgives the suggestions to show after the item, with their reasons.
Each video or podcast from YouTube carries details.player:
| Field | Use |
|---|---|
videoId | The 11-character id, for YouTube's native player libraries on iOS and Android |
embedUrl | https://www.youtube-nocookie.com/embed/<id> (YouTube's privacy-enhanced domain); add playsinline=1 and your own player parameters |
watchUrl | https://www.youtube.com/watch?v=<id>: open it in the YouTube app or the browser; always offer it |
embeddable | true, false (the owner does not allow embedding: open watchUrl instead) or null (not checked yet: try the player, and fall back to watchUrl) |
The item's image is the video's thumbnail with its credit, and details.channel names the channel (name, handle, url).
// List the latest videos and choose how each one plays.
const res = await fetch(`${API}/v1/dailydose/explore/video?sort=latest`, {
headers: { Authorization: `Bearer ${sessionToken}` },
});
const { items } = await res.json();
for (const item of items) {
const player = item.details.player;
const play = player?.embeddable === false ? player.watchUrl : player?.embedUrl;
console.log(item.title, play);
}
YouTube's rules
Follow YouTube's API Services Terms and its required minimum functionality, with the IFrame Player API or YouTube's native player libraries:
- Show YouTube's player whole and unobstructed, at least 200 × 200 px; never cover its controls or branding.
- Never play the audio alone: a YouTube podcast plays in the video player too.
- Never download or cache the video; use
embedUrlorwatchUrlexactly as the API gives them. - When
embeddableisfalse, openwatchUrlinstead of the player.
Curated items: fields that may be empty
ARCEL's staff add many videos and podcasts by pasting their links, and the API reads their title, channel and thumbnail from YouTube's public oEmbed. Until the YouTube Data API is connected, such an item has:
publishedAt:null(unknown, never guessed). Showdetails.curated.atinstead, for example "Added 6 Oct 2026".details.durationSeconds:null. Hide the duration.details.channel.idanddetails.channel.avatar:null. Show the channel's name, and its initial in place of the picture.
Up next and playback events
Report playback with captureEvents, with the item's exploreItemId: Explore Play when it starts, Explore Progress at 25, 50, 75 and 95 %, Explore Complete at the end, and Up Next Open when a reader opens a suggestion (with its position and reason). The counts on the cards and the Popular order are computed from them.
Actions on an item
Every item lists the buttons to draw in actions; draw only those. The API refuses an action the kind does not offer with 422 ACTION_NOT_AVAILABLE.
| Kind | actions | Counts to show |
|---|---|---|
event | save, share | none |
podcast, video | save, share, comment, like | counts.likes, counts.comments |
research | read, save, share | counts.reads |
- Save:
saveExploreItemandunsaveExploreItem;savedsays whether the reader saved the item. Guests may save; their saves move to their account when they sign in. - Like:
likeExploreItemandunlikeExploreItem, for videos and podcasts only: a like on an event or a research paper answers 422ACTION_NOT_AVAILABLE. - Share:
getExploreItemShareLinkgives the link to share; reportSharewithcaptureEvents. - Read: call
recordExploreReadwhen a research paper's detail opens (only for research: a read counts once per reader).
Show your app's change at once and keep the reply's state and counts; on an error, put the button back as it was.
Comments on videos and podcasts
Comments on a video or a podcast work as comments on a story, with their own operations: listExploreItemComments, createExploreItemComment (a reply names its parentId), listExploreCommentReplies, updateExploreComment, deleteExploreComment and restoreExploreComment within the undo time, likeExploreComment, unlikeExploreComment and reportExploreComment. A guest is asked to sign in first (403 SIGN_IN_REQUIRED); a comment the community rules hold says it waits for a review (state: held).
The reader's collection
What a reader saved, liked and wrote, across stories and Discover, is private to them. getCollectionSummary gives the counts of each section by kind, and listCollection lists one section (saved, liked or comments) and kind, newest first, a page at a time. Each entry holds a story or an item; an entry whose story or item is no longer available (or an event that has ended) has available: false and keeps its title in unavailable.
Events
List events with listExplore and kind=event (upcoming, in date order) and open one with getExploreItem. The detail's sections follow the event detail design: the summary, "Event Details", "What you'll experience", "Pillars covered", "Technologies covered", "What you'll take away" and "Who should attend".
| Field | Show it as | When it is empty |
|---|---|---|
summary | The description under the title | The organiser's own description; when the organiser gives none, an AI-assisted one from the organiser's page (aiSections.fields names summary); null when neither exists |
details.startsAt, details.endsAt, details.timeZone | Date and time in the event's own zone | timeZone (IANA, for example America/New_York) is the organiser's, else the event city's when the start's offset agrees with it; absent when unknown: show startsAt with its own offset |
details.venue, details.address | The venue and its full address | Absent for online events or when the organiser gives none |
details.city (code, label), location.cities | The place; filter with city | city.code is an IATA city code, null when the city has none (the name stays in label); location.cities is then [] |
details.organiser | "by …" | Absent only when neither the page nor ARCEL's source review names one |
image, details.images | The hero and the carousel | details.images holds the extra images only (empty when the organiser gives one) |
details.highlights | "What you'll experience" | The organiser's list, else AI-assisted; absent when the page supports none |
details.pillarHighlights (pillar, name, description) | "Pillars covered": name as the heading | Only the event's own pillars; absent when none is supported by the page |
details.technologies | "Technologies covered" chips | Absent when the page names none |
details.takeaways | "What you'll take away" | Absent when the page supports none |
details.audience | "Who should attend" | Absent when the page says nothing about it |
details.attendeeCount | Attendees | Only a count the source publishes as attendees or registrations (never capacity, saves or views); no current source publishes one, so it is absent |
details.expectedAttendeeCount | Expected attendance | Only when the organiser's page states the attendance it expects for this edition |
aiSections (label, generatedAt, fields) | Show label with the AI-assisted fields | Absent when nothing on the card is AI-assisted |
publishedAt | Not needed: date an event by details.startsAt | Usually null (organisers rarely declare when they published the page; never guessed) |
The AI-assisted fields are written from the organiser's own event page and checked against it as story summaries are; a field the page does not support is left out rather than filled.
Publisher logos
Story cards in getBriefing and getStory carry publishers[].logo ({ url, credit }): a short-lived address of the logo ARCEL stored from the publisher's own site (a square icon where the publisher declares one). It is null for a publisher whose site declares no usable raster logo or whose logo host refuses crawlers; show the publisher's first letter then. Do not cache the address beyond its expiry; ask again.
Research papers
Research items come from reviewed publishers and research indexes; the API stores their metadata and, where the licence allows, their abstract, never the full text. List them with listExplore and kind=research (sort latest or popular, and the paperType, pillars, country and publishedSince filters), and open one with getExploreItem.
| Field | Show it as | When it is empty |
|---|---|---|
shortTitle | The card's title (at most 70 characters, only words of the paper's own title, AI-assisted) | Absent until one is made: show title |
title, publisher, topics | The detail's head (the full title) | Always given |
image | The card and detail picture, with image.credit | kind: illustration is ARCEL's shared AI illustration for the paper's pillar and type (not a picture of the paper), kind: generated an AI image made for this paper; null only before the illustration set exists (show your own) |
details.paperTypeName | The paper's type (Research Paper, Market Report…), the display name of details.paperType. This is the readable label you asked for as details.paperTypeLabel: paperTypeLabel stays the publisher's own wording ("journal-article"), not for display | Absent when the paper has no controlled type |
details.authors, publishedAt | The author block, "Published on …" | Authors absent when the metadata names none; publishedAt null when the source declares no date (never guessed) |
details.doi | The DOI | Absent when the paper has none (reports, most library pages) |
summary | The one-line "See how…" | Null for metadata-only papers (most of them): their licence allows no text from the paper |
aiSummary.paperSummary with aiSummary.label | "Paper summary", with the label beside it | Null when there is no licensed source text to summarise, or before the summary is made: show details.abstract (when given), else nothing |
aiSummary.whyItMatters | "Why it matters?" | Hide the section when aiSummary is null |
details.abstract | The abstract | Given only when the work's licence (or a recorded permission) allows it |
details.fullPaperUrl | "View full paper": open it outside your app (the publisher's page or the open-access copy), and report Research Paper Opened with captureEvents | Always given |
counts.reads | "631 reads" on the card | 0 |
A paper has readable text in at least one of aiSummary.paperSummary, details.abstract and summary whenever its licence lets ARCEL keep any of the paper's own text; a metadata-only paper has none of them, and nothing is generated from its title alone.
When the detail opens, call recordExploreRead.
In-app feedback
Readers and guests can send feedback from any screen:
getFeedbackOptionsgives the topics ("Feedback about", in their order), the types (Problem, Suggestion, Other), the longest text and the image limits (how many, how large, which types). Start on the topic of the screen the sheet was opened from.- For each image:
createFeedbackUploadwith its type and size, then aPUTof the file touploadUrlwith the sameContent-Type. Convert HEIC photos to JPEG first. The server removes the images' metadata (location, camera, dates) before staff see them. submitFeedbackwith the topic, the type, the text, the uploads' keys and the app's context (appVersion,platform, and when you know themosVersion,device,screen,locale,timeZone), with anIdempotency-Keyheader (a new UUID per feedback, reused on a retry). Then thank the reader: there is no reply channel.
Keep the reader's topic, type and text on the device until the feedback is sent, so closing the sheet keeps the draft; never keep the images.
Your data
A signed-in reader can download everything ARCEL holds about them with exportAccountData, a JSON file, from your privacy settings.