apps/meeting-bot) that automatically joins Google Meet meetings, records audio/video, and streams live transcripts back to the backend.
What it does
- Joins a Google Meet URL using headless browser automation (Puppeteer)
- Records the meeting as a WebM file and uploads it to S3
- Streams live transcripts to the backend in real-time using Deepgram
- Captures chat messages and responds to
@zukomentions via the AI agent - Emits status webhooks throughout the meeting lifecycle
- Auto-leaves when it’s the only participant remaining
How it works
When the backend callsPOST /api/google-meet/join, the meeting-bot:
- Launches an ephemeral Fly.io machine (in production) or runs locally (in dev)
- Opens Chrome via Puppeteer and navigates to the Meet URL
- Injects a browser script that extracts participants and chat via a local WebSocket
- Streams audio through FFmpeg to Deepgram for live transcription
- Sends transcript chunks (buffered at ~600 chars) to the backend
- On meeting end, uploads the recording and full transcript JSON to S3
- Emits a
completedwebhook with the S3 artifact keys
Environment variables
apps/meeting-bot reads:
BACKEND_URL: Backend base URL (example:http://localhost:3001)AGENT_TOKEN: Shared token for authenticating requests to the backendDEEPGRAM_API_KEY: Deepgram API key for live transcriptionAWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_REGION,AWS_BUCKET_NAME: S3 credentials for uploading recordings and transcriptsFLY_API_TOKEN,FLY_APP_NAME: Fly.io credentials for launching worker machines (production only)PUPPETEER_EXECUTABLE_PATH: Path to the Chrome binaryBOT_NAME: Display name shown in the meeting (default:Zuko AI)PORT: HTTP server port (default:8000)
AGENT_TOKEN configured to validate incoming transcript and callback requests.
Run locally
API
Join a meeting
POST/api/google-meet/join
Triggers the bot to join a Google Meet.
| Field | Type | Required | Description |
|---|---|---|---|
meetingId | string | Yes | Meeting ID from the database |
meetingUrl | string | Yes | Full Google Meet URL |
callbackUrl | string | No | Webhook URL for status updates |
Status webhooks
The bot sendsPOST requests to callbackUrl (or BACKEND_URL/api/meetings/webhook) at each lifecycle stage.
| Event | Description |
|---|---|
fly-machine-launched | Fly worker machine created |
in_progress | Bot successfully joined the meeting |
processing | Meeting ended; uploading artifacts to S3 |
completed | Recording and transcript uploaded; S3 keys in data |
failed | An error occurred |
rejected | Host denied the bot entry |
Transcript streaming
During the meeting, the bot streams transcript chunks to the backend in real-time. POST/api/meetings/:meetingId/transcript-chunks
Headers:
x-agent-token: must matchAGENT_TOKENx-user-provider:google-meet
S3 artifacts
After a meeting, two files are written to S3:| File | Path | Description |
|---|---|---|
| Recording | meetings/{meetingId}/recording.webm | Raw WebM video; the backend transcodes this to MP4 asynchronously |
| Transcript | meetings/{meetingId}/transcript.json | Full speaker-diarized transcript with timestamps and chat messages |
Chat and AI responses
The bot captures all chat messages from the meeting. When a participant sends a message containing@zuko, the bot queries the backend AI agent and posts the response back to the meeting chat.