Blog

Messages now render Markdown and HTML

Messageboard widgets can now render rich content — send Markdown or HTML via the API and the widget displays it natively. You can also opt into showing the raw source.

Messageboard started with plain text messages. That was intentional — simple to send, simple to display, nothing unexpected in the widget. But as teams started using it for release notes, deployment summaries, and status updates, the same request kept coming up: can the widget just render the Markdown?

Today it can.

How it works

When you send a message via the API, include a Content-Type header that declares the format of your payload. The widget reads that declaration and renders accordingly.

# Send a Markdown message
curl -X POST https://msgboard.tech/api/messages \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: text/markdown" \
  -d '{
    "id": "release-notes",
    "content": "## v2.4.0\n\n- **New**: Rich content rendering\n- **Fix**: Widget scroll position on version change\n- **Docs**: Updated API reference"
  }'
# Send an HTML message
curl -X POST https://msgboard.tech/api/messages \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: text/html" \
  -d '{
    "id": "status-update",
    "content": "<p><strong>All systems operational.</strong> Last checked 14:03 UTC.</p>"
  }'

The three supported content types are:

Content-Type headerWidget behavior
text/plainDisplayed as-is, no formatting (default)
text/markdownRendered as Markdown
text/htmlRendered as sanitized HTML

If no Content-Type header is provided, the widget falls back to text/plain — existing integrations are unaffected.

Viewing raw source

Sometimes you want to see exactly what was sent, not the rendered output. Every widget has a Raw toggle in the message toolbar. Clicking it switches the widget between the rendered view and the source text, regardless of content type.

This is useful for debugging API payloads, auditing what a webhook actually delivered, or just double-checking that your Markdown syntax came through as intended.

HTML sanitization

HTML messages are sanitized before rendering. Script tags, event handlers, and other executable content are stripped. The intent is to support formatting — headings, links, tables, emphasis — not arbitrary code execution. If your HTML contains elements that get stripped, the plain-text fallback is there.

What this unlocks

The content type header slots into the existing message model without changing anything else. The same message name, the same versioning behavior, the same dashboard layout. You can start sending Markdown today and the widget just works.

A few patterns that become easier now:

  • Release notes: structure them with headings and bullet lists, post them once per deploy
  • Incident summaries: use bold for status, plain paragraphs for timeline
  • Job output: keep it as text/plain, or wrap key lines in <pre> tags via HTML for monospace display
  • Internal docs: short-form HTML pages that update in place without a separate doc system

The API reference has the full header spec, and the quickstart has been updated with examples for all three content types.