meetbot.dev

v1shipping for production · meet · teams · zoom

The meeting-bot API.

$0.005 per minute. Billed by the minute, not the meeting. Drop a Meet, Teams, or Zoom URL — get per-speaker audio, a tab video, timestamped captions, and inbound chat shipped to your S3-compatible bucket. A signed webhook arrives when the meeting ends.

Sign in →Try free with bot@meetbot.devfirst hour free · no card · per-minute billing
~/your-app/dispatch.tsmain
import { createMeetbot } from "@meetbot/sdk";

const meetbot = createMeetbot({ apiKey: process.env.MEETBOT_API_KEY! });

const job = await meetbot.dispatchBot({
  url: "https://meet.google.com/abc-defg-hij",
  externalId: "session-42",
  webhooks: { onFinalize: "https://yours.example/hook" },
});

console.log(job.id, job.status);

02 · what you get back

Four files. In your bucket.

No proprietary container. No "go to our portal to download." When the meeting ends, these land in the prefix you nominated, and a webhook arrives with the manifest path.

audio · per speaker

audio.{speaker}.webm

One Opus track per participant. No mixing, no leakage. WebRTC SSRC-keyed; speaker tags carry through from the meeting roster.

manifest/
├─ alice.audio.webm        12.3 MB · opus@48k mono
├─ bob.audio.webm           8.7 MB · opus@48k mono
└─ carol.audio.webm         9.1 MB · opus@48k mono
video · whole tab

tab.video.webm

ffmpeg x11grab of the meeting tab — what a viewer would see, including shared screens. VP9, configurable bitrate.

tab.video.webm
  vp9 · 1920×1080 · 15 fps · 1.5 Mbps
  duration 00:42:17 · 412 MB
captions · live JSON

captions.jsonl

Newline-delimited JSON. One row per finalized utterance — speakerId, text, start/end ms. From Meet's data channel where available; live DOM scrape otherwise.

{"speakerId":"p-2","name":"alice",
 "text":"so the redesign…",
 "tStart":423120,"tEnd":425840}
{"speakerId":"p-3","name":"bob",
 "text":"yeah, ship it.",
 "tStart":425900,"tEnd":426710}
chat · inbound

chat.jsonl

Whatever participants typed in the meeting's chat. Timestamped, sender attributed. Same wire shape across Meet/Teams/Zoom.

{"sender":"alice","text":"link?",
 "tMs":1827000}
{"sender":"bob",
 "text":"https://docs.example/x",
 "tMs":1834120}

03 · platforms

Three platforms. One contract.

Google Meet

shipping*

Joins as anonymous guest by default. Workspace-account login is in progress for the April 2026 dual-queue admit rollout.

Microsoft Teams

shipping

Web client, anonymous join. Captions via the data-channel intercept; real participant names from the People pane.

Zoom (Web)

shipping

Web client only — no Zoom SDK key required, no native binary. Per-speaker audio via WebRTC SSRC mapping.

* About the asterisk: Google rolled out a dual-queue admit system for Meet in April 2026 that auto-denies anonymous joiners on Workspace meetings. We're shipping a Workspace-bot identity pool to handle it — landing this month.

04 · the flow

An HTTP POST in. Files in your bucket out.

The orchestrator runs on your infrastructure or ours. No black-box state machine — the job table, the bot containers, the webhook deliveries are all visible to you (and inspectable in the admin) at every step.


  your app                                  meetbot orchestrator
 ┌────────────┐         POST /jobs         ┌──────────────────────┐
 │            │ ─────────────────────────▶ │                      │
 │  Linqua    │   Bearer mb_…              │   Next.js + Drizzle  │
 │  worker    │ ◀───────────────────────── │   pg-boss queue      │
 │            │   201 { id, status }       │                      │
 └────────────┘                            └──────┬───────────────┘
                                                  │ docker run
                                                  ▼
                                         ┌──────────────────────┐
                                         │   meetbot/bot        │
                                         │   ─────────────      │
                                         │   puppeteer + xvfb   │
                                         │   joins the meeting  │
                                         └──────┬───────────────┘
                                                │  per-speaker tracks,
                                                │  captions, chat
                                                ▼
                                         ┌──────────────────────┐
                                         │   YOUR  S3  BUCKET   │
                                         │   manifest.json      │
                                         │   alice.audio.webm   │
                                         │   bob.audio.webm     │
                                         │   tab.video.webm …   │
                                         └──────┬───────────────┘
                                                │
                              POST /your-hook   │  HMAC-SHA256
                              ◀─────────────────┘  X-Meetbot-Signature
                                  signed event              

05 · pricing

$0.005 per minute.

That's $0.30 an hour. Billed by the minute, not the meeting — a 17-minute call costs you 8.5 cents. First meeting (up to one hour) is free. We publish our pricing because we have nothing to hide — including the math against the closed-source alternative.

updated 2026-05-08billed monthly · stripe
meetbotRecall.ai
per meeting-minute$0.005$0.008340% less
billing granularityper minuteper minute (rounded up)
free tier1 hour first meeting5 hours / mo
per-bot fee
minimum spend
pricing exposedthis pageafter a sales call

Recall.ai pricing as of their public pricing page; we'll update this row when theirs moves. This is a comparison, not a takedown — they built a great product.

06 · code

The whole API. Three calls.

import { createMeetbot } from "@meetbot/sdk";

const meetbot = createMeetbot({ apiKey: process.env.MEETBOT_API_KEY! });

const job = await meetbot.dispatchBot({
  url: "https://meet.google.com/abc-defg-hij",
  externalId: "session-42",
  webhooks: { onFinalize: "https://yours.example/hook" },
});

console.log(job.id, job.status);

07 · faq

Things engineers actually ask.

Q.How does the bot show up in the meeting?
As a regular participant tile, with whatever displayName you passed to dispatchBot. By default it's meetbot; pass displayName: "Linqua note-taker" if you want the participant list to say so. Hosts still admit it from the lobby like any guest.
Q.How do you handle anti-bot detection?
Three layers, in escalating order: Workspace bot accounts on a rotation pool (the only thing that survives Google's April-2026 dual-queue admit screen on Workspace meetings), cookie persistence across runs, and tier escalation on retry — each retry uses a stealthier Chrome fingerprint.
Q.What if the meeting runs three hours?
The orchestrator monitors the bot container with periodic heartbeats. There's no timeout to configure — the run ends when the host leaves, when the meeting ends, or when the bot is kicked. You're billed by the second of meeting time, not by container wall clock.
Q.How do I get started?
Easiest path: add bot@meetbot.dev to your next Google Meet, Teams, or Zoom calendar invite. The bot joins, records, and emails you the recording when the meeting ends. First meeting (up to one hour) is on us — no signup, no card. After that you can keep going on a paid account.
Q.How do you handle GDPR / recording consent?
We don't, and we won't pretend to. meetbot is infrastructure — you tell participants the meeting is being recorded, you get their consent under whichever jurisdiction applies, you decide whether to honor "do not record" requests. The bot has a configurable display name precisely so participants know it's there.