Pepsi and Max post short videos, and the point of putting them on PawScapes is discovery: a reel on a beach page should lead back to the account. That means embedding Instagram, TikTok and YouTube inside venue guides, diary entries and landing pages.

The usual way to embed a post is to paste the provider's HTML snippet. It works, and it puts third-party markup and scripts in your database, where they stay after the provider changes the snippet or the post disappears.

Store what it is, not what it looks like

highseam's embed field (1.6.0) takes a pasted URL and, on save, resolves it to a provider and an id. YouTube and Vimeo are built in. Anything else has to be registered with a fixed set of hosts. There's deliberately no oEmbed discovery: fetching whatever URL an editor pastes, from the server, is a server-side request forgery risk, and a list of known hosts isn't.

PawScapes registers the two it needs:

pawscapes-cms/src/cms.config.ts
const embedProviders: EmbedProviderConfig[] = [
  {
    name: "instagram",
    hosts: ["instagram.com"],
    extractId: (u) => {
      const m = INSTAGRAM_PATH.exec(u.pathname);
      return m ? `${m[1] === "reels" ? "reel" : m[1]}/${m[2]}` : null;
    },
  },
  {
    name: "tiktok",
    hosts: ["tiktok.com"],
    extractId: (u) => /\/video\/(\d{8,25})/.exec(u.pathname)?.[1] ?? null,
    oembed: "https://www.tiktok.com/oembed",
  },
];

Instagram has no oEmbed endpoint that works without a token, so it gets an id parsed from the URL and nothing else. TikTok's oEmbed is public; PawScapes uses only the title from it, because the thumbnail URLs it returns expire. Where a provider gives no lasting image, the block has a poster field for an editor to pick a cover.

The site builds the iframe

What's stored is { url, provider, embedId }. On the public site, one module is the only source of third-party iframes. It trusts a stored provider and id only when they match strict patterns, re-derives them from the URL otherwise, and builds every src from a fixed host. Unknown URLs render as a plain link.

That's the same rule as highseam's own reference renderer, which serves YouTube through youtube-nocookie.com. When there's a poster frame it shows that first, and nothing loads from YouTube until the reader clicks.

Embeds inside blocks

Editors don't only paste videos as loose paragraphs. PawScapes has a "Video / social embed" block (URL, caption, poster, posted date) and a "Reels row" block holding several. Since September those blocks, along with image sections, FAQs and galleries, can sit inside rich-text bodies and landing sections. That nesting found three bugs in a row:

  • 1.7.1: a rich-text field inside a block row rendered as a plain textarea showing [object Object].
  • 1.7.2: inside rich text, a block's own rich-text, array and link sub-fields fell back to text inputs.
  • 1.7.3: the same for embed, gallery, date and tag sub-fields. A gallery block in a body showed [object Object],[object Object], and typing in the box replaced the images with a string.

Each was found on a real PawScapes page, the first time someone opened it in the admin, and fixed in highseam within days.

The blocks also carry a posted_on date, because Google's video markup needs an upload date and the post's date is the honest one.