Embedding

Embed a capsule on your site

Any published capsule can live on your own pages: a blog post, a newsroom, a product launch. It's a standard iframe, so it works in any CMS that accepts HTML. No script, no account and no key.

Quick start

In the editor, choose Published at the top, then Copy embed code. Or write it yourself from the capsule's link:

HTML
<iframe
  src="https://app.capsules.ink/your-space/your-capsule"
  title="The night shift, a capsule"
  width="100%"
  height="640"
  style="border: 0"
  allow="autoplay; fullscreen; clipboard-write"
  allowfullscreen
  loading="lazy"
></iframe>
  • title names the frame for screen readers. Use the capsule's title.
  • allow lets sound play after the reader taps, the reader go full screen, and links and quotes be copied.
  • loading="lazy" waits to load the capsule until the reader scrolls near it.

In WordPress, Ghost, Webflow, Squarespace and most other platforms, paste it into an HTML or embed block.

Here it is at work. Scroll inside the frame, and watch the progress it reports to this page:

Capsules Manifesto, embedded with the snippet above.capsules:progress waiting

Sizing

A capsule scrolls inside its own frame and lays itself out for the frame, not the browser window. Any size works. Two common choices:

Inline

Full width and 640 pixels tall, as in the quick start. It sits in the flow of an article like a video, and the reader scrolls through the story inside it.

Full screen

Make the frame as tall as the screen, so the capsule fills the view while it's being read. Pair it with the scroll hand-off so readers can carry on down your page afterwards.

HTML
<iframe
  id="capsule"
  src="https://app.capsules.ink/your-space/your-capsule"
  title="The night shift, a capsule"
  style="display: block; width: 100%; height: 100vh; height: 100svh; border: 0"
  allow="autoplay; fullscreen; clipboard-write"
  allowfullscreen
  loading="lazy"
></iframe>

100svh keeps the frame clear of the browser's toolbars on phones; 100vh is the fallback for older browsers.

Phones

Frames 768 pixels wide or narrower get the mobile layout, wherever they appear. A narrow column on a desktop page shows the mobile layout too. Give the frame the full width of the screen on phones.

Scroll hand-off

While the pointer is over the frame, scrolling moves the capsule, not your page. Browsers don't let a page read scroll position inside a frame from another site, so the capsule reports it instead with postMessage. This listener lets your page take over once the reader reaches the end:

HTML
<script>
  const CAPSULE_ORIGIN = "https://app.capsules.ink"
  const frame = document.getElementById("capsule")

  window.addEventListener("message", (event) => {
    // Only trust messages from the capsule you embedded.
    if (event.origin !== CAPSULE_ORIGIN || event.source !== frame.contentWindow) return
    const message = event.data
    if (!message || message.type !== "capsules:progress") return

    // At the end, let the wheel and touch fall through to the page.
    if (message.atEnd) frame.style.pointerEvents = "none"
  })

  // Hand control back to the capsule once it has left the screen,
  // so a reader scrolling back up can read it again.
  new IntersectionObserver(([entry]) => {
    if (!entry.isIntersecting) frame.style.pointerEvents = "auto"
  }).observe(frame)
</script>

Always check event.origin. A capsule posts its messages to whichever page embeds it, so any frame could send a message that looks like one.

Drive the capsule from your page

To tie the capsule to your own scrolling, for example a pinned section that plays the story as the page scrolls past, send it a position:

JavaScript
frame.contentWindow.postMessage(
  { type: "capsules:scrollTo", percent: 0.5 },
  "https://app.capsules.ink",
)

Messages

Every message is an object with a type. These are the ones meant for your page. Ignore any other type you see: they belong to the Capsules editor and can change.

From the capsule

typeFieldsMeaning
capsules:readyNoneThe capsule has loaded and is listening for messages.
capsules:first-frameNoneThe first frame is on screen.
capsules:progresspercent, atEndThe reader scrolled. percent runs from 0 to 1; atEnd is true at the bottom. Sent at most once per frame, and once on load.
capsules:editionedition, label, sourceThe edition changed, by the reader (source: "reader") or by you ("host").

To the capsule

typeFieldsMeaning
capsules:scrollTopercentScroll the capsule to a point from 0 to 1. Ignored while the title screen shows.
capsules:set-editioneditionSwitch to the edition with this slug.

Send messages to the capsule with its origin, https://app.capsules.ink, as the target. Wait for capsules:ready before sending, or the capsule may not hear you.

Host page requirements

Capsules can be framed by any site. You don't need to register your domain. If your page sends a Content Security Policy, allow the capsule's origin:

Header
Content-Security-Policy: frame-src https://app.capsules.ink; child-src https://app.capsules.ink

Avoid sandbox on the frame. If your platform requires it, these permissions keep the capsule working: scripts and its own storage to play, forms for the subscribe form, popups for sharing, and top navigation for the link to the next capsule.

Attribute
sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox allow-top-navigation-by-user-activation"

oEmbed

Capsules support oEmbed, so platforms that use it can embed a capsule from its link alone. Each capsule page advertises the endpoint, and you can call it yourself:

Request
curl "https://app.capsules.ink/api/oembed?url=https%3A%2F%2Fapp.capsules.ink%2Fyour-space%2Fyour-capsule&maxwidth=640"
Response
{
  "version": "1.0",
  "type": "video",
  "title": "The night shift",
  "provider_name": "Capsules",
  "width": 640,
  "height": 360,
  "html": "<iframe src=\"https://app.capsules.ink/your-space/your-capsule\" width=\"640\" height=\"360\" …></iframe>",
  "thumbnail_url": "https://…"
}
  • url is the capsule's published link. Only format=json is supported.
  • maxwidth and maxheight are optional. The default is 720 by 405.
  • type is video when the capsule has a short preview clip, and rich otherwise. Both embed the capsule itself.
  • White-label capsules don't advertise the endpoint and leave out Capsules as the provider.

Performance

  • The cover image is part of the capsule's page, so the frame shows a picture straight away.
  • The first scene's video loads first. Later scenes load as they're needed, at a quality that suits the reader's device and connection.
  • Most of a capsule's weight is video, so use loading="lazy" for any capsule below the fold, and avoid several full-screen capsules on one page.

Search and fallbacks

Search engines credit a capsule's words to its own link, not to your page. Give your page its own title, description and a few lines of introduction, and add a plain link to the capsule after the frame for readers whose browsers block frames:

HTML
<iframe src="https://app.capsules.ink/your-space/your-capsule" …></iframe>
<p><a href="https://app.capsules.ink/your-space/your-capsule">Read “The night shift” on Capsules</a></p>

Analytics

Reads of an embedded capsule count towards its views in Capsules, the same as reads on its own link. Capsules doesn't break views down by site. To measure reading on your page, forward progress to your own analytics:

JavaScript
const seen = new Set()

window.addEventListener("message", (event) => {
  if (event.origin !== "https://app.capsules.ink") return
  const message = event.data
  if (!message || message.type !== "capsules:progress") return

  for (const mark of [0.25, 0.5, 0.75, 1]) {
    if (message.percent >= mark && !seen.has(mark)) {
      seen.add(mark)
      // Replace with your analytics call.
      track("capsule_progress", { percent: mark * 100 })
    }
  }
})

Updates and caching

  • Republishing keeps the link, so every embed shows the new version within a minute or two. You don't change the embed code.
  • Renaming the link when you republish breaks embeds that use the old one. It isn't redirected.
  • Unpublishing makes every embed of the capsule show a not-found page within a minute or two.
  • Improvements to the Capsules reader reach a capsule the next time it's published, so republish older capsules to pick them up.

Inside the frame

  • Sound only starts after the reader taps or clicks in the capsule, as browsers require.
  • The link to the next capsule in a series opens in your page's tab. Share, subscribe and profile links open a new tab.
  • The subscribe form works inside the frame and adds readers to the capsule creator's list.
  • Every published capsule can be embedded. There are no supporter-only capsules yet.