mtcute, a typed MTProto library for Telegram in the browser and on Node
modern typescript library for mtproto. supports browsers, node/bun, deno and more!
At a glance
- What is it?
- mtcute is a TypeScript library and bot framework for MTProto, the protocol Telegram clients speak, and it ships separate packages for Node, the browser, Bun and Deno. The interesting part is that it generates its API surface from the TL schema and regenerates it as Telegram changes it, which trades bundle size for freshness.
- Who is it for?
- mtcute suits a TypeScript team that wants to talk to Telegram over MTProto rather than the Bot API, and that wants the same code to run in a Node service and in a browser tab, which is what the web package and the memory usage figure are aimed at.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
MTProto rather than the Bot API
mtcute is described as a modern, performant and cute MTProto library and bot framework, supporting both web and Node.js, and the project description calls it a modern typescript library for mtproto that supports browsers, node, bun, deno and more.
The MTProto choice is the significant one. The Bot API is the HTTP interface most Telegram bots use, and it is limited to what Telegram chooses to expose. MTProto is the protocol the official clients speak, and it is much larger, which is why the project has a page explaining MTProto versus the Bot API. Talking to it means you can do things the Bot API does not offer, and you can also do things the Bot API does offer without a rate limit or a polling model in the way.
The cost is that MTProto is a binary protocol with a session model, a key exchange and an update stream, and a library that hides it is doing real work. The feature list says mtcute supports almost everything the Bot API does, and even more, and the project goals list a convenient high-level API for the most commonly used features.
The audience is a TypeScript developer who needs Telegram functionality the Bot API does not have, or who wants one codebase that runs on a server and in a browser, or who simply prefers MTProto.
The repository layout confirms the multi-runtime design. There is a `packages/` directory, a `deno.lock` alongside a `pnpm-lock.yaml`, an `e2e/` directory, `docs/`, `scripts/`, a `build.config.js`, a `.nvmrc`, and per-package configuration directories. The package manifest describes itself as a Type-safe library for MTProto for the Telegram API for browser and NodeJS, at version 0.32.5, with MIT licence.
The last push to the repository was on 2026-10-15, and the recorded releases are v0.32.5 on 2026-10-15, v0.32.4 on 2026-10-05 and v0.32.3 on 2026-09-25, so the project ships frequently.
The client, the dispatcher and a filter
The API shape is small enough to read in one screen, and the first thing it shows is that the library separates transport from update handling.
import { TelegramClient } from '@mtcute/node'
import { Dispatcher, filters } from '@mtcute/dispatcher'
const tg = new TelegramClient({
apiId: Number.parseInt(process.env.API_ID),
apiHash: process.env.API_HASH,
storage: 'my-account'
})
const dp = Dispatcher.for(tg)
dp.onNewMessage(filters.chat('private'), async (msg) => {
await msg.replyText('hiiii from mtcute! 🌸')
})
const self = await tg.start({ /* optional params */ })
console.log(`✨ logged in as ${self.displayName}`)The `TelegramClient` constructor takes the API credentials and a storage option, here the string `my-account`, which is a storage backend name rather than an object. The `Dispatcher.for(tg)` call then builds an update dispatcher bound to that client, and `dp.onNewMessage` registers a handler with a filter that narrows to private chats. The handler receives a message object with a `replyText` method, so the common case is a single await.
The `filters` object is the piece worth attention, because it is what stops every handler from running on every update. A filter of `filters.chat('private')` is a predicate on the update, and there are others in the same module. Without a filter layer, an update handler is a switch statement over update types, and the code gets unpleasant quickly.
The `tg.start()` call at the end is the login, and it returns the logged-in user, whose `displayName` is what gets printed. The comment notes that the start parameters are optional, which covers the case where you are running as a bot with a bot token rather than as a user.
What this snippet does not show is the part that matters operationally, which is the connection lifecycle. `Dispatcher.for(tg)` and `dp.onNewMessage` describe what happens when an update arrives, not how the client keeps a session alive, reconnects after a network drop, or handles the auth key sequence. The project documentation at mtcute.dev is where that lives, and the API reference is published separately at ref.mtcute.dev.
The third element of the design is the separate `@mtcute/dispatcher` package, which is the point of the split. The dispatcher knows about updates and filters, and the client knows about the transport, and a userbot framework that mixes the two is much harder to reason about.
Four runtimes, four packages
The quick start section branches by target, and the branching is the design.
If you are just starting a bot, there is a scaffolding tool.
pnpm create @mtcute/botIf you want to integrate into an existing Node.js application, you add the node package.
pnpm add @mtcute/nodeIf you are building something for the web, you add the web package.
pnpm add @mtcute/webAnd for the newer runtimes there are dedicated instructions: bun with `bun add @mtcute/bun`, and Deno with `import { TelegramClient } from 'jsr:@mtcute/deno'`.
The fact that the browser build is a first-class target rather than an afterthought is the thing that sets mtcute apart from most Telegram libraries. A library that only works under Node cannot be used for a Telegram client that runs in a page, and Telegram has a use case for that, with sessions that live in the browser and a connection that has to survive a reload.
The Deno route goes through JSR rather than npm, which is a separate distribution channel, and the repository carries a `deno.lock` to go with the `pnpm-lock.yaml`.
The web package comes with a real constraint, and it is the one the feature list hints at. Running a Telegram session in a browser means keeping credentials somewhere in the page, and the library's job is to give you the tools to do that rather than to decide for you. The `storage` option in the client constructor is where that decision lives, and the choice of storage backend is more consequential in the browser than on a server.
The audience for the package split is a developer who knows which runtime they are deploying to, and the split keeps the browser bundle from carrying Node-only code. The `sideEffects` flag and the `build.config.js` at the repository root are the machinery behind that.
The TL schema is the source of truth, and it moves
The most consequential design decision in mtcute is that its API types are generated from Telegram's own TL schema, and the badge in the project documentation tracks the layer of that schema in use.
The development setup shows the workflow.
git clone https://github.com/mtcute/mtcute
fnm use # or `nvm use`
cd mtcute
pnpm install --frozen-lockfile
# generate code from tl schema
pnpm -C packages/core run gen-tlSo the type definitions are not written by hand, they are generated, and the generation step is a first-class part of the build. The feature list states that mtcute uses the latest TL schema to provide the newest features as soon as possible, and the acknowledgement section credits TDLib, the official MTProto client library, as one of the sources the work was based on or inspired by.
The benefit is real. Telegram adds methods and fields regularly, and a hand-maintained TypeScript client lags. A generated surface does not.
The cost is equally real, and it is the thing to think about before you commit. The API is a moving target, which means the type definitions change between versions, which means an upgrade can break your code through a type error rather than through a behaviour change. For a team that pins its dependencies and upgrades deliberately, that is a manageable cost. For a team that floats its dependencies, it is not.
The same mechanism is why the project is honest about not being complete. The list of what mtcute is NOT includes a statement that it will never be a fully feature-complete library, because the high-level APIs will never cover the entirety of the APIs, with an invitation to contribute. That is a well-drawn boundary, and it is the one you should design around: use the generated types for the full surface, and the high-level helpers for the common cases.
What the project says it is not
The project goals section contains one of the more useful honesty statements in an open source README, because it defines the boundary of the library in terms you can check against.
mtcute strives to be customizable enough to fit most of the possible use cases, lightweight in terms of both runtime and bundle size, to support theoretically any environment without much hassle, to provide a solid foundation for all kinds of applications on the Telegram platform, and to provide a convenient high-level API for the most commonly used features.
Then the list of what mtcute is NOT and will never be. It is not a library for spam, flood or otherwise malicious activities. It is not a fully feature-complete library, because the high-level APIs will never cover the entirety of the APIs, with an invitation to contribute. It is not a drop-in replacement for another library. And it is not a teapot.
Two of those are worth taking seriously. The first is a scope statement about legitimate use, and it is a useful signal about the project's intent, since a Telegram library that is only useful for abuse is a different project. The second is the honest one: the high-level layer is a convenience, not the whole API, and if you need a method the helpers do not cover, you are dropping to the generated types.
The claim about lightness has a number attached. The feature list says a running instance uses less than 50 MB of RAM, which is a small figure for a long-lived Telegram client and explains why the browser build is plausible. The bundle size side of the same claim is the tree-shaking feature, and the two together are what the per-runtime package split is buying.
The project also states the hackability claim, that almost every aspect of the library is customizable including networking and storage, which is the other half of why the storage backend is a configuration option rather than a hardcoded one.
The acknowledgements name TDLib and TDesktop, the official client library and the official desktop client, plus Pyrogram and Telethon, described as popular Python libraries, and the project credits them as sources the work was based on or inspired by.
Editorial conclusion
mtcute suits a TypeScript team that wants to talk to Telegram over MTProto rather than the Bot API, and that wants the same code to run in a Node service and in a browser tab, which is what the web package and the memory usage figure are aimed at. It does not suit a project that wants the full Bot API surface, because the project states outright that high level APIs will never cover the entirety of the APIs, and it does not suit a team that needs the generated types to be stable, since they track the current TL schema. Verify first that the MTProto API layer you need is present in the version you pin, that the storage backend you choose fits your deployment, and that the package you install for your runtime is the one that matches your bundler.
Frequently asked questions
What is mtcute?
It is a modern TypeScript library and bot framework for MTProto, the protocol Telegram clients speak, rather than for the Bot API. It supports both web and Node.js, and it ships separate packages for Node, the browser, Bun and Deno.
How do I install mtcute for Node.js or for the browser?
For an existing Node.js application, pnpm add @mtcute/node. For a web project, pnpm add @mtcute/web. For Bun, bun add @mtcute/bun, and for Deno you import from jsr:@mtcute/deno. If you are starting a bot from scratch, the scaffolding tool is pnpm create @mtcute/bot.
How does mtcute handle Telegram API changes?
The API types are generated from Telegram's TL schema rather than written by hand, and the project states that it uses the latest TL schema so new features appear as soon as possible. In development the code is regenerated with pnpm -C packages/core run gen-tl.
Is mtcute a complete implementation of the Telegram API?
No. The project states that mtcute is not and will never be a fully feature-complete library, because the high-level APIs will never cover the entirety of the APIs, and it invites contributions. It is also explicitly not a library for spam, flood or otherwise malicious activities.
What licence is mtcute released under?
MIT, with the LICENSE file at the top of the repository. The package manifest also declares the licence as MIT and the author as alina sireneva.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/mtcute-mtcute)Was this useful?