verify_feature

Every option and step type the Tada MCP tool accepts: navigation, clicks, captions, drag-and-drop, checkpoints, walking authenticated pages, and driving email flows. (Formerly record_demo — the old name still works.)

verify_feature is the tool your agent calls to walk a feature (it was named record_demo until 2026-08-24, and that name still works). Your agent calls it with a title and an ordered list of steps; Tada drives a headless browser through them, records the screen, verifies the checkpoints and uploads one mp4.

Options

OptionTypeDefaultWhat it does
titlestringrequiredShown on the watch page. 1–200 characters.
stepsarrayrequiredThe ordered actions. At least one.
devicedesktop · mobile · tabletdesktopViewport preset.
width / heightnumberExact viewport, overriding device.
taskIduuidAttach the demo to a Tada task.
storageStatepathA Playwright storageState JSON, so the demo starts already signed in.
initScriptstringJavaScript run in every page before the app’s own scripts.
dryRunbooleanfalseRecord and transcode only, with no upload. Returns the local mp4 path.

The presets are desktop 1920×1080, tablet 820×1180, mobile 390×844. Use mobile only for genuinely mobile-first features; a desktop app filmed at 390px wide is a demo of your responsive breakpoints, not of your feature.

dryRun is the fast loop while you’re getting the steps right: same recording, same checkpoints, nothing published.

Steps

Every step is { action, ...fields }. Which fields matter depends on the action.

ActionFieldsNotes
gotourlNavigate. Supports ${magicLink} from a preceding awaitEmail.
clicktext or selectorPrefer text: visible labels survive refactors that break CSS selectors.
filltext (the label) or selector, valuevalue supports ${inbox}.
selecttext or selector, valueFor custom comboboxes: the role=combobox widgets a plain click can’t drive.
presskeye.g. "Enter".
hovertext or selector
scrollvalue or selector, msvalue is "top", "bottom" or a pixel offset. ms sets the animation duration. It scrolls smoothly, on an ease-out curve, because a teleporting page is unreadable on video.
dragtext/selectortoText/toSelector, nativeSee below.
waitmsA plain pause.
waitForTexttextWait for text to appear. Not a checkpoint; see expect.

wait and waitForText are pacing, not proof. Only expect gates the publish.

Narrating

ActionFieldsNotes
captiontext, msNarrates the next action. Defaults to 2500ms.

Write captions for every meaningful action. A silent demo is a bad demo. Keep them to roughly six words: anything over 90 characters fills the frame, and the tool will tell you when you’ve crossed that line. Detail belongs in the voice-over, not on screen.

Whether captions are shown, spoken, and in which voice comes entirely from your Tada account settings. There’s no agent-side override: your agent writes the words, your dashboard decides how they’re delivered. If you supply no captions at all, Tada injects one from the demo title so every demo carries its mark.

Verifying

ActionFieldsNotes
expecttext, urlIncludes or selector, msBlocks the publish if it fails. Waits up to 8s by default.

Put one after every meaningful action. Full detail in Verification.

Drag-and-drop

{ "action": "drag", "text": "My card", "toText": "In Progress" }

Tada tries a pointer-based drag first, which is what dnd-kit and react-beautiful-dnd listen for, and switches automatically to real HTML5 dragstart/dragover/drop events when the source element is draggable="true". Set native: true only if that auto-detection misses.

Always follow a drag with an expect asserting the item landed. An unverified drag can silently no-op, and a video of a card that didn’t move is exactly the kind of thing verification exists to catch.

Keeping credentials off camera

pause and resume take no fields. Between them the browser still performs every step, but no frames are captured.

[
  { "action": "pause" },
  { "action": "goto",  "url": "http://localhost:3000/login" },
  { "action": "fill",  "text": "Email",    "value": "[email protected]" },
  { "action": "fill",  "text": "Password", "value": "hunter2" },
  { "action": "click", "text": "Sign in" },
  { "action": "goto",  "url": "http://localhost:3000/tasks" },
  { "action": "resume" },
  { "action": "caption", "text": "Adding a task" }
]

The demo opens on the authed page with no login sequence and no password on screen. For a longer-lived alternative, storageState starts the run already signed in with no login steps at all, useful when you want to demo inside an account that has real data in it.

Demoing an email flow

Magic links and OTP codes are demoable: Tada can mint a disposable inbox and read it mid-recording.

ActionFieldsNotes
createInboxMints an inbox. Use its address as ${inbox} in a later fill.
awaitEmailtext, msWaits for the mail. text filters on a subject substring; ms defaults to 20000.

After awaitEmail, the link from the email is available to a later goto as ${magicLink}:

[
  { "action": "createInbox" },
  { "action": "fill",  "text": "Email", "value": "${inbox}" },
  { "action": "click", "text": "Send me a link" },
  { "action": "awaitEmail", "text": "Sign in to" },
  { "action": "goto",  "url": "${magicLink}" },
  { "action": "expect", "urlIncludes": "/dashboard" }
]

An email that never arrives is a verification failure, not a skipped step. The demo doesn’t publish.

What comes back

On success: the share URL, the duration, and a ✓ verified marker if the demo had checkpoints. Alongside it, any notes worth your attention: skipped steps, captions that ran long, which narration mode was applied, whether a newer recorder version is out.

On a failed checkpoint: no link, the list of failures, and the path to the local recording. See Verification.

Next: the CLI reference.