mcpField
T
telegram-userbots

telegram-userbots

github.com/sshelegDevelopment4157 installsUpdated 5d ago
Repository

About telegram-userbots

telegram-userbots is a development and operations guide for Telegram MTProto automation using human accounts, aimed at Telethon developers. It emphasizes session credential risks, rate-limit handling, entity resolution, and operational responses to revoked authentication.

Key features

  1. 01Assess whether a user account is necessary
  2. 02Store and revoke session credentials safely
  3. 03Handle and cap FloodWaitError retries
  4. 04Manage entity resolution and history requests
  5. 05Distinguish recoverable from revoked authentication

Use cases

  1. 01Assess risks before automating a Telegram user account
  2. 02Deploy and rotate Telethon sessions securely
  3. 03Handle Telegram rate limits in message jobs
  4. 04Detect revoked sessions and stop restart loops

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/ssheleg/telegram-dev --skill telegram-userbots

After installing, type/telegram-userbotsin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

references/
entities-and-history.md
rate-and-flood.md
sessions-and-auth.md

Details

From the project README

Telegram userbots — MTProto, and what it costs

A bot token is issued to software. An MTProto session is a logged-in human being — the same authority the person has, held in a file, with none of the protections a token has. Everything in this skill follows from that one difference.

Read against Telethon 1.44.0 and core.telegram.org on 2026-08-25. Telethon minor releases change session and entity-cache behaviour; the version you are on is a fact to check, not to assume.

Deep material, loaded on demand:

ReadWhen
references/sessions-and-auth.mdlogging in, storing a session, rotating one, or moving between machines
references/rate-and-flood.mdanything that loops over chats, users or messages — FloodWait, pacing, takeout
references/entities-and-history.mdresolving peers, iterating history, downloading media at scale

First: do you actually need one?

Answer this before writing a line, and write the answer down.

The jobBot API canVerdict
React to messages in chats the bot is inyesuse a bot
Send to users who started the botyesuse a bot
Read a public channel it is admin ofyesuse a bot
Read history of a channel it does not administernouserbot
Read a chat's past, from before it joinednouserbot
Act as a specific personnouserbot
Download a file over 20 MBnouserbot, or a local Bot API server
Enumerate a group's members at scalenouserbot, and see the risk below

The local Bot API server closes the file ceiling without an account. Reaching for a user session because of a 21 MB video is trading a permanent liability for an infrastructure task you were going to have anyway.

The refusal, and it is not a formality: a user account can be limited or banned, and Telegram does not explain, appeal quickly, or restore what was in it. If the account is a real person's, the blast radius is their messages, their groups and their logins. Automating a personal account is a decision with a named owner or it is not a decision.

The session file is the credential

import os
from telethon import TelegramClient
from telethon.sessions import StringSession

client = TelegramClient(
    session=StringSession(os.environ["TG_SESSION"]),   # from the secret store
    api_id=int(os.environ["TG_API_ID"]),
    api_hash=os.environ["TG_API_HASH"],
)
  • A .session file grants full access to the account, without the password and without the 2FA prompt. Copying one to another machine logs that machine in. It belongs in .gitignore, in a secret store, in backups you would give a password the same treatment — and never in an image layer or a log.
  • api_id/api_hash come from my.telegram.org and identify the application, not the account. They are not a session and not a secret of the same weight, but they are still not public.
  • Losing a session is recoverable; leaking one is an incident. Revoke from the account's own Devices screen, which ends that session everywhere.
  • Log Out is not a lockout, and termination comes from an older session. auth.logOut can return a future_auth_token that skips the next login code, so the two-step password is the real gate; a session under 24 hours old cannot terminate others (FRESH_RESET_AUTHORISATION_FORBIDDEN). Accepting a tg://login?token= link logs in whoever generated it. List, watch (UpdateNewAuthorization) and terminate sessions: references/sessions-and-auth.md.
  • Verified on this machine on 2026-08-25: five of five Telethon projects gitignore the session and none has one tracked in git — the one trap this estate has actually closed. Keep it closed.

FloodWaitError is the API working

from telethon.errors import FloodWaitError

try:
    await client.send_message(peer, text)
except FloodWaitError as e:
    if e.seconds > MAX_ACCEPTABLE:      # a decision, not a sleep
        raise
    await asyncio.sleep(e.seconds + 1)
    await client.send_message(peer, text)
  • It is not a failure to swallow and not a signal to retry blindly. It names exactly how long to wait; anything else is guessing at a number Telegram already told you.
  • A very large seconds is a different event. Minutes mean you are pacing too hard; hours mean the account is being limited, and continuing is how a limit becomes a ban. Cap it, alert, stop.
  • Sleeping inside a request handler is how one flood becomes an outage. The wait belongs in a worker with a queue, not in the path a user is waiting on.
  • Measured across six Telethon projects here on 2026-08-25: three of six handle FloodWaitError at all. The other three run until the first limit and then stop, in whatever state they were in.

Pin the minor, and know why

Four bots in this estate pin telethon==1.37.0 while a fifth runs 1.44.0, and the pin carries its reason in requirements.txt: minor releases change session and entity-cache behaviour, and a jump of seven minors on a live bot needs its own change with its own verification.

That is the right shape and it is worth stating as doctrine. A userbot's dependency is not a library, it is a protocol client holding a login. An upgrade can invalidate a session format, change what get_entity costs, or move an exception's module. Upgrade deliberately, one bot at a time, with a session you can recreate.

Entities are resolved, and resolution is not free

get_entity may hit the network, and doing it in a loop is the most common way to earn a FloodWait that looks unexplained.

  • Prefer ids you already have. A cached InputPeer costs nothing; a username costs a request.
  • PeerIdInvalidError usually means the account has never seen that peer, not that the id is wrong. A user account can only address what it has encountered.
  • Iterate with the library's own iterators (iter_messages, iter_dialogs) and let them page; hand-rolled offsets re-request and re-trip the limits.
  • For a bulk export, takeout exists and is the sanctioned path — it raises the limits for exactly this and tells Telegram what you are doing.

Detail in references/entities-and-history.md.

Two accounts, two lifetimes

A userbot has a second failure mode a bot does not: the human logs in somewhere, changes the password, or terminates sessions, and your process dies holding a session that is no longer valid. This is a terminal / revoked auth state, not a transient one: the process may still be LIVE, but it is NOT READY, and a restart just re-loops a login that can never succeed. Surface it as an alert with the account named, stop work until FRESH auth (a re-login that needs the phone), and never a crash loop — the same three-state contract sheleg-dev's error-tracking states for any long-lived authenticated connection: liveness, readiness, degraded_auth (transient retries, terminal stops). A supervisor restart is for the recoverable policy only; a revoked session is terminal and lands on the STOP-and-alert row of that skill's recovery-contract table, so the identical event cannot draw opposite actions in the two packs. Never put a userbot on the critical path of something a bot could serve.

Before you ship

  1. The reason a user account is required is written down, and the bot-API alternative was checked (§ First: do you actually need one?).
  2. The session is in a secret store, gitignored, and revocable (§ The session file is the credential).
  3. FloodWaitError is caught, capped and alerted on — never slept off unbounded (§ FloodWaitError is the API working).
  4. The client version is pinned, and the upgrade is its own change (§ Pin the minor).
  5. A dead session pages a human rather than restarting forever (§ Two accounts, two lifetimes).
  6. The account has a two-step password, and someone watches its sessions: a new UpdateNewAuthorization reaches a human, and the oldest trusted session is the one that terminates (§ The session file is the credential).

Triggers

More phrases that route here: "user account", "read channel history", "api_hash", "телетон".

Moved here from the description in 0.5.4: "pyrogram", "мтпрото", "сессия телеграм".

Comments

Markdown supported