Developers · Go
Make a meeting bot speak, from Go
A Go program that says something in the meeting, with what it printed when it was run.
What it does
After agent-ready, the program writes one say message with wsjson.Write and waits for agent-said, which confirms the words went into the meeting.
It needs a key and a meeting code in MEETFUL_KEY and MEETING. Two curl requests make both. MEETFUL_URL is optional and defaults to https://meetful.com.
Go 1.22 or later. The socket programs use github.com/coder/websocket (go get github.com/coder/websocket@v1.8.12); the transcript program uses only the standard library.
The code
// Say something in a Meetful meeting from Go. go get github.com/coder/websocket
// MEETFUL_KEY=tmk_… MEETING=abc-defg-hij go run . "Noted: the launch moves to the third of March."
package main
import (
"context"
"fmt"
"log"
"os"
"strings"
"time"
"github.com/coder/websocket"
"github.com/coder/websocket/wsjson"
)
type message struct {
Type, By, Text, Why string
Audio any
}
func main() {
base := os.Getenv("MEETFUL_URL")
if base == "" {
base = "https://meetful.com"
}
text := "Hello from Go."
if len(os.Args) > 1 {
text = os.Args[1]
}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
conn, _, err := websocket.Dial(ctx, "ws"+strings.TrimPrefix(base, "http"), nil)
if err != nil {
log.Fatal(err)
}
defer conn.Close(websocket.StatusNormalClosure, "done")
conn.SetReadLimit(4 << 20)
hello := map[string]string{"type": "agent-hello", "key": os.Getenv("MEETFUL_KEY"), "meeting": os.Getenv("MEETING")}
if err := wsjson.Write(ctx, conn, hello); err != nil {
log.Fatal(err)
}
for {
var m message
if err := wsjson.Read(ctx, conn, &m); err != nil {
log.Fatal(err)
}
switch m.Type {
case "agent-ready":
if err := wsjson.Write(ctx, conn, map[string]string{"type": "say", "text": text}); err != nil {
log.Fatal(err)
}
case "agent-said":
aloud := ""
if m.Audio != nil {
aloud = " (read aloud)"
}
fmt.Printf("%s said: %s%s\n", m.By, m.Text, aloud)
return
case "agent-error", "agent-refused":
log.Fatal(m.Type + ": " + m.Why)
}
}
}Run it
MEETFUL_KEY=tmk_… MEETING=abc-defg-hij go run . "Noted: the launch moves to the third of March, and Sam owns the docs."
What it printed
🤖 go bot said: Noted: the launch moves to the third of March, and Sam owns the docs.
Run on 10 November 2026 against a Meetful server built from the same code as meetful.com, with two people — Dana and Sam — in the meeting saying three lines. Nothing above was edited.
How it works
Audio is typed as any, because it is null when the server has no voice and an object when it has one. The run below was on a server without a voice key, so it printed no "(read aloud)".
coder/websocket lets you write from any goroutine; only reading has to stay in one place. A bot that talks while it listens can keep its read loop as it is and send from wherever its answers are made.
What can go wrong
Refused: no such key — mint one with POST /api/keysThe key is wrong, or was never minted on this server. A key from one Meetful server does not work on another.
agent-error: …Sent too quickly, or something this key may not do; agent-ready's can lists what it may.
Next
In Go: join a meeting · live transcript · get the transcript
The same in Node.js · Python · curl
The whole API · Every socket message and webhook · All guides
Try Meetful
Meetings that take their own notes
Free video meetings in the browser: every line of the transcript under the name of who said it, and the summary and action items when you hang up. Nothing to install — guests just open the link.