Overview
@arnabxd/ntgcalls-napi lets your Node.js or Bun app join Telegram group voice/video chats and
stream media into them. It's a thin, thread-safe binding over
libntgcalls — the native WebRTC engine that does the
actual audio/video work.
It handles media: encoding your audio/video, the WebRTC transport, and the call lifecycle. It does not talk to Telegram's API. You bring that part yourself.
What you need first
Important
You need an MTProto library logged in as a regular user account — not a bot. Bots cannot join voice chats. Use MTKruto, GramJS, or any MTProto client.
The two halves of a call:
| Piece | Who does it | Examples |
|---|---|---|
| Signaling — join the call, exchange the SDP offer/answer with Telegram | Your MTProto library | MTKruto, GramJS |
| Media — produce the audio/video, run the WebRTC connection | This package | NtgCalls |
The flow is always: this package makes an offer → your MTProto lib joins the call with it and returns Telegram's answer → this package connects with that answer → you push media. The Quick Start walks through it end to end.
Installation
npm install @arnabxd/ntgcalls-napi
pnpm add @arnabxd/ntgcalls-napi
yarn add @arnabxd/ntgcalls-napi
bun add @arnabxd/ntgcalls-napi
The right prebuilt binary (Linux, macOS, Windows) is downloaded automatically on install — no
compiler or LD_LIBRARY_PATH setup needed.
You'll also need ffmpeg on the host, since the common way to feed media is to let ntgcalls run an ffmpeg command and read raw frames from its output (see Quick Start).
Good to know
- IDs accept
numberorbigint. PasschatId/userIdeither way —-1001234567890nor-1001234567890both work. Values the library returns (liketime()) come back asbigint. - It's an EventEmitter.
NtgCallsextends Node'sEventEmitter, so call state, incoming frames, and stream-end notifications arrive as ordinary events. Register listeners before you start a call. - Everything async is a Promise.
create,connect,set_stream_sources, etc. return promises; heavy native work runs off the main thread so your event loop stays responsive.
Building from source
You only need this if you're hacking on the binding itself:
- Install Rust & Cargo.
- Download the matching
libntgcallsshared library (libntgcalls.so/.dylib/ntgcalls.dll) from the ntgcalls releases into./lib/. - Run
npm run buildto compile the crate intontgcalls.node.