Getting started

What is Rundown Studio?Create an account

Rundown

Rundown basicsColumnsTemplatesSettingsTrashCell historyMentionsText variablesRunning a showImport CSV rundown

Event

Event basicsSharing events

API

Getting startedAPI reference ↗Build a rundown from CSVWorking with cell contentLive updates over SSEAdvanced usageError referenceMigrating from v0API v0 (deprecated)

Integrations

Companion ModuleQLab

Sharing and outputs

Read-only rundownEditable rundownOutputPrompterPDF exportCSV export

Account

Your teamSubscription and invoices

Updates

Changelog
Docs API

Working with cell content

Working 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 as ![image](url) markdown (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 (&nbsp; 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 paragraph
  • strongbold text
  • emitalic text
  • sstruck-through text
  • code — monospaced “code-style” text
  • a — a link
  • blockquote — a quoted passage, indented
  • ul / ol / li — a bullet list / a numbered list / one item in either
  • h1 through h6 — headings, from largest to smallest
  • br — a line break within a paragraph
  • hr — a horizontal divider line
  • img — 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, and url() inside style are 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/agentsUse content
Preserve formatting through an editRead content_html, edit, write content_html
Overwrite a cell with plain textWrite content
Show a mention’s current nameGET …/mentions, match id to data-mention-id
Show a variable’s current valueGET …/text-variables/:key
Add a brand-new mention/image into a cellNot via the API yet — dashboard only