openmic
Docs

The whole install.

Everything on this page is also at /llms.txt, in the shape a coding agent looks for. “Add Open Mic to my site” typed at an agent, plus that file, is a complete install.

Install

Paste one tag. No other attribute is required — the defaults render a working, themed widget. Your pk_… key is on the console's Install page, and it's public by design.

<script async src="https://openmic.dev/v1/embed.js"
        data-openmic="pk_live_yourkey"></script>

The recorder needs a secure context (https, or localhost). iOS Safari records audio/mp4; Chrome records audio/webm — both are transcoded server-side to MP3, so you don't need to care.

The pieces

The same tag renders different pieces, chosen by attribute:

AttributeWhat it does
data-mode="inline|modal|bubble" How the ask widget appears. Default inline — and inline on a page of its own is the one to use; a recording form is tall, and an overlay fights the viewport.
data-archive="list|grid|latest|featured" Render published episodes instead of the ask form. featured shows the few you picked on the console's Featured page, in your order — and your most recent until you've picked any, so the tag works the day it's pasted.
data-limit="10" How many episodes to show.
data-episode="<slug>" Embed one published episode's player.
data-view="full" On an episode embed, render the whole thing rather than the player: who asked, what the answer gets into, its themes, and both transcripts — the same content as the episode page on your space. This is what makes the page a data-episode-base click lands on worth arriving at. Note an iframe is not your SEO: everything in it is noindexed, so a verified CNAME is still what makes an episode page genuinely yours.
data-episode-base="/questions" Where your site keeps episode pages, so a click in an embedded archive goes there. Not optional on an archive — without it, a click navigates the iframe: your URL never changes, and the episode can't be linked, shared or bookmarked. It looks like it worked and quietly is not a page.

The layout that works

Three pages on your site, plus a link from wherever you already have one. This is the shape the first production install arrived at after trying the alternatives, and each piece of it is a mistake somebody already made.

/ask/              the recorder, inline, on a page of its own
<script async src="https://openmic.dev/v1/embed.js"
        data-openmic="pk_..."></script>

/questions/        your archive
<script async src="https://openmic.dev/v1/embed.js"
        data-openmic="pk_..."
        data-archive="list"
        data-episode-base="/questions"></script>

/questions/<slug>/ the whole episode, not just its player
<script async src="https://openmic.dev/v1/embed.js"
        data-openmic="pk_..."
        data-episode="<slug>"
        data-view="full"></script>

home page          your own button linking to /ask/, and optionally
<script async src="https://openmic.dev/v1/embed.js"
        data-openmic="pk_..."
        data-archive="featured"
        data-episode-base="/questions"></script>

Keep your own header, footer, nav, fonts and colours on all of these. Only the widget comes from us; the page is yours. A few rules that save a support thread:

  • Use your own button to reach /ask/. The modal launcher styles itself from your space's accent, so it will never quite match a button in your own stylesheet. A plain link you style yourself always matches.
  • Link to your own pages, never to a *.openmic.dev address. Sending a visitor to our hostname is the opposite of an embed.
  • Don't style the widget from your CSS. It's a cross-origin iframe and your rules can't reach inside — deliberately, since your global button and box-sizing rules can't break it either. Colours, fonts, radius and copy all come from the console's Branding step.
  • Set the accent to match your primary button, not your brand's loudest colour — that's what makes the widget read as part of the page.

Host page requirements

The widget records audio from a cross-origin iframe. Two headers on your page can block it, and both fail silently unless you set them. Name your space's host in them, not ours — that's the origin the iframe actually loads from, and it becomes your own domain the moment you verify one. The console's Install page prints these with your exact hostname filled in.

Permissions-Policy: microphone=(self "https://<your-space-host>")
Content-Security-Policy: frame-src https://<your-space-host>;
                         connect-src https://openmic.dev

Measured browser behaviour, so you can predict failures:

  • Chromium enforces Permissions-Policy and exposes document.featurePolicy, so a blocked microphone is detectable before the visitor taps record.
  • Safari ignores the Permissions-Policy response header entirely and exposes no featurePolicy API. A failure there is almost always a real user denial.
  • A policy denial, a missing allow attribute, and a user clicking “Block” all raise the identical NotAllowedError. The error name alone never tells you why.

What happens to a question

A recording is transcoded to MP3, transcribed, and lands in your inbox readable, with the asker's four consents beside it — voice, photo, name, location, each their own explicit checkbox. You answer by voice; the pair is spliced into one episode with chapter marks, a drafted title and teaser you can edit, and generated key art in your palette.

Publishing honours consent AND your own toggles: you can always withhold something the asker offered, and you can never show something they didn't. Askers get an email when their question is answered, manage their own name, photo and following from an emailed sign-in link — and can erase themselves entirely, which rebuilds the episode audio without their voice.

Your domain & the feed

Every space starts on yourname.openmic.dev. Verify a CNAME in the console and everything — episode pages, transcripts, canonical tags, /feed.xml, /sitemap.xml, even links in email already sent — moves to your address. Transcripts are the thing people search for, and search credits whoever's domain they sit on. The feed is a real podcast RSS with chapters, submittable to Apple and Spotify; oEmbed makes episodes unfurl playable elsewhere.

Themes live there too. Answers are filed under subjects you confirm, and each one is a page on that same domain — /themes/ lists them, /themes/<slug>/ holds the episodes filed under one, and both are in the sitemap. Renaming a theme keeps its address, so a link you've already sent goes on working. The embed deliberately renders no theme links: a chip inside a frame either loads a whole page into your widget or takes your visitor off your site. Link to the theme URLs yourself if you want them on your pages.

For agents

Point your coding agent at https://openmic.dev/llms.txt. It's this page's contract in the shape an agent looks for — attributes, the recommended layout, and the headers above.

Signed in? The console's own guide is written around your actual space, with your hostname and key filled in: /console/docs/.

To let an agent do things — read the inbox, answer, publish — connect it to the MCP server. One command, and you sign in as yourself:

claude mcp add --transport http openmic https://mcp.openmic.dev/

There is nothing to copy: you pick which space it may touch, it gets no more than you have, and you can disconnect it whenever you like. Other clients, and the REST API underneath, are at /docs/mcp/ and /docs/api/.

Paste the tag. See it on your page.

Free while we're in early access.

Create your space