Skip to main content
@komaa/elevenlabs-msteams-bridge brings a hosted ElevenLabs agent (STT + LLM + TTS + turn-taking, all run by ElevenLabs) onto a Microsoft Teams call. It is the ElevenLabs analogue of the OpenClaw and Hermes plugins: it hosts the HMAC WebSocket that StandIn connects to, then relays audio to and from an ElevenLabs Agent conversation.
Unlike the OpenClaw and Hermes plugins, this is a standalone Node service, not a framework plugin. You do not install it into an agent runtime - you run the bridge and point StandIn at it. ElevenLabs hosts the agent itself.
Prefer Python? The same bridge exists as a Python package: elevenlabs-msteams-bridge on PyPI (pip install elevenlabs-msteams-bridge), with its own docs site and repo. Same wire protocol, same environment variables, same hardening - pick the runtime that fits your stack. This page follows the Node package.

How it works

Audio is relayed verbatim - both sides speak base64 PCM 16 kHz, so there is no transcoding on the call path. The bridge opens one ElevenLabs Agent WebSocket per call (wss://api.elevenlabs.io/v1/convai/conversation), mints a short-lived signed URL for private agents, maps caller barge-in to ElevenLabs interruptions, and injects caller context.
ElevenLabs agent conversations are realtime WebSocket connections (one socket per call), not webhooks. ElevenLabs post-call webhooks are a separate, optional feature for pushing a transcript or analysis to your own server after a call ends - unrelated to the live audio path, and not required by the bridge.

Requirements

  • Node.js >= 20.
  • An ElevenLabs agent (Agents dashboard) with its audio input and output format set to PCM 16000 Hz, plus an API key.
  • A StandIn subscription (standin.komaa.com, free package works) - the hosted media bridge that joins the Teams call and connects to this service. See Architecture.
  • Your own Microsoft Teams bot connected to StandIn - the Teams setup walks through the Azure bot, the app package, and the upload. To try it without one, use the sandbox.

Run

Env-configured, no install step needed:
ELEVENLABS_API_KEY=sk_... \
ELEVENLABS_AGENT_ID=agent_... \
WORKER_SHARED_SECRET=... \
npx @komaa/elevenlabs-msteams-bridge
Or add it to a project (npm i @komaa/elevenlabs-msteams-bridge) and embed it - see the library API for the programmatic surface and a custom vision hook. The bridge binds its media WebSocket (default ws://<host>:8080/voice/msteams/stream; StandIn appends /{callId} per call).

Expose the WebSocket (Agent voice URL)

StandIn connects to the bridge from the internet, so the port must be reachable - a public host or a tunnel. With Tailscale Funnel:
tailscale funnel --bg --https=8080 8080
Your Agent voice URL is then:
wss://<machine>.<tailnet>.ts.net:8080/voice/msteams/stream

Connect it to StandIn

Register that URL (with a matching shared secret) on your identity in the dashboard, or use the sandbox to try it without your own Teams bot:
  1. Set the identity’s Agent voice URL to where the bridge listens.
  2. Set WORKER_SHARED_SECRET to the shared secret from pairing - both sides must match exactly, or the WebSocket handshake is rejected with 401.
  3. Place a Teams call (or join the sandbox meeting). StandIn joins, connects to the bridge, and your ElevenLabs agent answers.

Try the runnable example

The fastest way to understand the bridge is to run its example project - a minimal, working embedding you can copy straight into your own repo.

Run the example, step by step

Clone examples/basic-bridge, fill in three environment variables, expose the port, connect it to StandIn, and place a call - with the vision hook explained along the way.
Next: the full configuration reference - every environment variable, the call governor, and vision. Deep protocol and library docs live on the project site.

Docs site

npm

Source