How to Integrate Loom with Your Headless CMS
Connect Loom to your headless CMS so teams can record walkthroughs once, attach them to structured entries, and publish current video embeds across docs, support, and onboarding.
What is Loom?
Loom is an async video messaging platform used by product, support, sales, education, and operations teams to record screen, camera, and microphone walkthroughs. Teams use it for onboarding, bug reports, release demos, support answers, and internal training when a written note would take longer to explain. Its core capability is fast recording and sharing, with embeddable videos, viewer permissions, transcripts, and APIs for connecting video metadata to other systems.
Why integrate Loom with a headless CMS?
Loom videos often start as one-off links in Slack, docs, tickets, or onboarding checklists. That works for a week. Then the product UI changes, the help article moves, the release note gets archived, and nobody knows which Loom is still safe to share with customers.
Connecting Loom to a headless CMS gives each video a structured home. Instead of pasting an iframe into rich text, you can model a Loom video as fields like videoId, embedUrl, shareUrl, transcriptStatus, productArea, owner, and lastReviewedAt. With Sanity’s AI Content Operating System, that structured data lives in the Content Lake, and webhooks or Functions can run the moment a guide, lesson, or support article is published.
The practical difference is small but important. Manual setup means a teammate records a Loom, copies a link, pastes it into three places, updates the title in Loom, updates the title in the article, and hopes both stay in sync. An integrated setup lets your publishing event update Loom metadata, render the correct embed in your frontend, notify collaboration tools, and keep the same video attached to web, mobile, support, and AI agent experiences. The trade-off is that Loom remains the video system of record for recording and playback, so you still need to handle Loom OAuth tokens, permissions, and workspace access carefully.
Architecture overview
A common architecture starts in Sanity Studio, where editors attach a Loom video to a structured document, such as a help article, onboarding lesson, release note, or product walkthrough. The schema keeps Loom-specific fields like videoId, embedUrl, shareUrl, thumbnailUrl, duration, and transcriptStatus separate from the article body, so your frontend doesn’t need to parse HTML to find an iframe. When the document is published, a Sanity webhook fires with the document ID, or a Sanity Function runs directly on the content mutation. The handler uses GROQ to fetch exactly what Loom needs, for example the title, summary, canonical URL, product area, and Loom video ID. It can then call Loom’s REST API with an OAuth bearer token, commonly PATCHing the Loom video metadata so the video title and description match the published content. The end user sees the result in your site, app, or learning portal. Your frontend queries the Content Lake for the structured entry, renders the Loom embed URL, and can also show related content, transcript status, owner, or last review date. If you want recording inside an internal tool, use Loom’s Record SDK in the frontend to create the video, then write the returned Loom URL and video ID back to Sanity.
Common use cases
Product walkthroughs in documentation
Attach Loom demos to feature docs, then sync the Loom title and description whenever the article publishes.
Onboarding lessons with owner tracking
Model each training video with owner, role, team, and review date fields, so stale Loom walkthroughs are easy to find.
Support answers with reusable videos
Connect Loom explainers to help articles, macros, and support flows without copying the same embed into multiple places.
Release notes with async demos
Publish a release note and update the connected Loom video metadata with the shipped feature name, summary, and canonical URL.
Step-by-step integration
- 1
Set up Loom developer access
Create a Loom developer app, configure OAuth for the REST API, and note the public app ID if you plan to use @loomhq/record-sdk for in-app recording. For production, store the Loom access token and refresh token in your server environment or secret manager, not in Sanity Studio.
- 2
Install the packages you need
Install @sanity/client for GROQ reads from the Content Lake. If editors will record Loom videos from your app, also install @loomhq/record-sdk or @loomhq/record-sdk-react in the browser app where recording happens.
- 3
Model Loom fields in Sanity Studio
Add a typed object for Loom data, such as videoId, shareUrl, embedUrl, thumbnailUrl, durationSeconds, transcriptStatus, and lastSyncedAt. Keep these fields separate from Portable Text so you can validate required URLs, query video entries, and render embeds safely.
- 4
Create the sync trigger
Use a Sanity webhook filtered to published documents that include loom.videoId, or use a Sanity Function triggered by content mutations. Send the document ID to your handler, then fetch the current document with GROQ before calling Loom.
- 5
Call Loom’s REST API
Use Loom’s API with an OAuth bearer token to read or update video metadata. A common publish flow updates the Loom video name and description from the Sanity document, including a canonical URL back to the live page.
- 6
Test the frontend experience
Publish a test article with a Loom video, confirm the webhook or Function runs, verify the Loom metadata changed, and render the embedUrl in your frontend. Also test failure cases, such as an expired Loom token, a deleted video, or a private video that the viewer can’t access.
Code example
Minimal publish webhook handler. It receives a Sanity webhook, fetches the current document with GROQ, and updates the connected Loom video metadata through Loom’s REST API.
import {createClient} from '@sanity/client'
const sanity = createClient({
projectId: process.env.SANITY_PROJECT_ID!,
dataset: process.env.SANITY_DATASET!,
apiVersion: '2025-02-06',
token: process.env.SANITY_READ_TOKEN,
useCdn: false,
})
export async function POST(req: Request) {
const payload = await req.json()
const id = payload._id || payload.documentId
const doc = await sanity.fetch(`*[_id == $id][0]{
title,
"summary": pt::text(body)[0...700],
"url": canonicalUrl,
"loomVideoId": loom.videoId
}`, {id})
if (!doc?.loomVideoId) {
return Response.json({skipped: true})
}
const res = await fetch(`https://api.loom.com/v1/videos/${doc.loomVideoId}`, {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.LOOM_ACCESS_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: doc.title,
description: `${doc.summary}
Read more: ${doc.url}`,
}),
})
if (!res.ok) {
throw new Error(`Loom update failed: ${res.status} ${await res.text()}`)
}
return Response.json({synced: true, loomVideoId: doc.loomVideoId})
}How Sanity + Loom works
Build your Loom integration on Sanity
Sanity gives you the structured content foundation, real-time event system, and flexible APIs you need to connect Loom videos to docs, support, onboarding, and AI content workflows.
Start building free →CMS approaches to Loom
| Capability | Traditional CMS | Sanity |
|---|---|---|
| Attaching Loom videos to content | Editors usually paste an iframe or share URL into a rich text field, which makes validation and reuse hard. | Model Loom as a typed object with videoId, embedUrl, shareUrl, thumbnailUrl, transcriptStatus, owner, and review date. |
| Syncing on publish | Teams often update Loom and the page by hand, so titles and descriptions drift over time. | Webhooks or Functions can trigger on publish and call Loom immediately with the current document data. |
| Selecting context for Loom metadata | The integration may need to parse rendered HTML or fetch page data that includes more than Loom needs. | GROQ can return the exact fields for the Loom update, including joined references, in one query. |
| Recording from editorial tools | Editors record in Loom, switch tabs, copy a link, paste it, and hope the embed format is right. | Sanity Studio is React-based, so you can add a custom input that uses Loom’s Record SDK and writes the returned video data into structured fields. |
| Using Loom content across channels | Video embeds are often tied to one page template, which limits reuse in apps, support tools, and AI agents. | One structured back end can feed web, mobile, support surfaces, Loom sync jobs, and Agent Context for production AI agents. |
Keep building
Explore related integrations to complete your content stack.
Sanity + Slack
Post Slack updates when a Loom-backed article, lesson, or release note publishes.
Sanity + Microsoft Teams
Send Teams notifications for new training content with the right Loom walkthrough attached.
Sanity + Intercom
Connect structured help content and Loom explainers to customer support flows and in-app messages.