Getting started
What is Rundown Studio?Create an accountRundown
Rundown basicsColumnsTemplatesSettingsTrashCell historyMentionsText variablesRunning a showImport CSV rundownEvent
Event basicsSharing eventsAPI
Getting startedAPI reference ↗Build a rundown from CSVWorking with cell contentLive updates over SSEAdvanced usageError referenceMigrating from v0API v0 (deprecated)Integrations
Companion ModuleQLabSharing and outputs
Read-only rundownEditable rundownOutputPrompterPDF exportCSV exportAccount
Your teamSubscription and invoicesUpdates
ChangelogWorking with cell content
How rich-text cell content works on the wire — the two-field model, the tag taxonomy, and how mentions and variables resolve.
Cells in Rundown Studio hold rich text: formatting, colors, mentions, variables, images, and attachments. The API exposes that content in two parallel fields, and the rich one — content_html — is standard HTML plus three custom rs-* elements. This page is the reference for reading and writing it.
The two-field model
Every cell reads out with both fields:
{
"cue_id": "G0M48GugUIem6YOSIOyO",
"column_id": "EoeiemGEmeMOY8GwUK6s",
"content": "Host walks on stage\n@Alice Cooper is ready",
"content_html": "<p>Host walks on stage</p><p><rs-mention data-type=\"mention\" data-mention-id=\"RH0Ao1j2pZu4DhccM4N3\" data-fallback-name=\"Alice Cooper\"></rs-mention> is ready</p>"
}
content— plain text. Formatting is stripped, mentions render as@name, variables as their current$value, and images are kept asmarkdown (the one markdown exception, so the image URL isn’t silently lost). One line per paragraph, heading, or list item. The friendly representation for reading and for simple writes.content_html— the rich form, raw and lossless. Write it back to preserve everything.
Writes carry exactly one of the two. Sending both, or neither, is rejected with 400 cells.invalid_payload.
Writing content replaces the cell’s entire content with plain text — formatting, mentions, and media in that cell are destroyed. Use it only when that’s what you want. To edit a rich cell safely: read content_html, modify it, write content_html back.
Round-trips are semantic, not byte-identical. Read content_html, write it straight back, read again — you get equivalent HTML, not the same bytes: entities may be decoded ( becomes the actual U+00A0 character) and attribute order may normalize. Diff meaning, not bytes.
The tag taxonomy
content_html allows a fixed set of tags. Everything else is stripped on write.
Standard text — the ordinary HTML tags, doing exactly what they do everywhere else:
p— a paragraphstrong— bold textem— italic texts—struck-throughtextcode— monospaced “code-style” texta— a linkblockquote— a quoted passage, indentedul/ol/li— a bullet list / a numbered list / one item in eitherh1throughh6— headings, from largest to smallestbr— a line break within a paragraphhr— a horizontal divider lineimg— an embedded image:<img src="https://storage.example.com/…/stage-plot.png">
Task lists (checkboxes) are regular lists with data attributes and a checkbox wrapper per item — label, input (only type and checked survive), and div are allowed for exactly this structure:
<ul data-type="taskList">
<li data-checked="true" data-type="taskItem">
<label><input type="checkbox" checked="checked"><span></span></label>
<div><p>check audio</p></div>
</li>
</ul>
The checked state lives in data-checked on the li; the input mirrors it for rendering.
Inline color
- Text color:
<span style="color: #fca5a5">…</span> - Highlight:
<mark data-color="#7f1d1d" style="background-color: #7f1d1d; color: inherit">…</mark>
Only the color and background-color style properties survive; anything else inside style is stripped.
Interactive components — the three custom rs-* elements. Each carries its payload in attributes and has no children.
A mention — a person tagged in a cell:
<rs-mention data-type="mention" data-mention-id="RH0Ao1j2pZu4DhccM4N3" data-fallback-name="Alice Cooper"></rs-mention>
A text variable — a placeholder that displays the variable’s current value:
<rs-variable data-type="variable" data-variable-key="venue" data-fallback-value="Madison Square Garden"></rs-variable>
A file attachment:
<rs-file filename="run-sheet.pdf" url="https://storage.example.com/…/run-sheet.pdf"></rs-file>
(Images are not a custom element — they’re a plain <img src>, listed with the standard tags above.)
Resolving the data-* attributes
Mentions. data-mention-id is the stable reference to a mention record — it equals the id field on the mention resource. To resolve it, list the rundown’s mentions and match by id:
curl -H "Authorization: Bearer $TOKEN" \
https://api-v1.rundownstudio.app/rundowns/YOmm4UG2SGSomuOci44c/mentions
data-fallback-name is the display text to show when you don’t (or can’t) resolve the mention — so even a consumer that never calls the mentions endpoint can render something sensible. Its accuracy is aspirational, not guaranteed: it’s a snapshot from when the content was written, it is not validated against the mention record, and it does not update when the mention is renamed. For the current name, resolve data-mention-id.
Variables. data-variable-key is the variable’s key. Resolve it directly:
curl -H "Authorization: Bearer $TOKEN" \
https://api-v1.rundownstudio.app/rundowns/YOmm4UG2SGSomuOci44c/text-variables/venue
data-fallback-value is shown when the key doesn’t resolve. Like the mention fallback, it’s a best-effort snapshot — not validated, not kept in sync with the variable’s actual value. Note that the plain-text content field already does this resolution for you — variables appear as their current value there.
Images and files. src / url are plain HTTPS URLs to the stored asset; filename is the display name. Nothing to resolve.
Sanitization — what happens on write
content_html runs through a tag/attribute allowlist before storage:
- Unknown tags,
<script>, event-handler attributes (onclick,onerror, …),javascript:URLs, andurl()insidestyleare dropped silently. - The stored (cleaned) result is echoed back in the response — what you see in the response is exactly what was kept.
- Reads pass through the same allowlist, so content authored in the dashboard editor reads out in exactly the vocabulary documented on this page — you will never encounter a tag this page doesn’t list.
- Maximum length: 100,000 characters per cell.
If your write seems to “lose” markup, compare your request against the response — the difference is what the sanitizer removed.
Authoring caveat: edit existing, don’t mint new
Round-tripping mentions, variables, and media that already exist in a cell works fully — move them, copy them between cells in the same rundown, delete them, edit the text around them.
Authoring new ones via the API is not supported yet: you cannot mint a fresh data-mention-id, and you cannot upload an image and embed it through content_html. A fabricated data-mention-id won’t resolve to anything and won’t render as a live mention in the editor. Creating new mentions has an API of its own (POST /rundowns/:id/mentions) — but wiring a newly created mention into cell content is dashboard-only for now.
Quick reference
| You want to… | Do this |
|---|---|
| Read a cell for humans/agents | Use content |
| Preserve formatting through an edit | Read content_html, edit, write content_html |
| Overwrite a cell with plain text | Write content |
| Show a mention’s current name | GET …/mentions, match id to data-mention-id |
| Show a variable’s current value | GET …/text-variables/:key |
| Add a brand-new mention/image into a cell | Not via the API yet — dashboard only |