ssheleg/telegram-dev

telegram-userbots

Use when a Telegram job needs a user account rather than a bot token: reading history a bot cannot see, acting as a person, bulk export with Telethon or another MTProto client, and the ban risk that comes with it.

Vedi sorgente

Come usare

  1. Copia il comando e controlla il pacchetto prima di installarlo nel tuo ambiente agente.
  2. Controlla strumenti, credenziali e ambienti richiesti nel documento originale.
  3. Descrivi input e risultato desiderato; confronta l’output con le fonti.
npx skills add https://github.com/ssheleg/telegram-dev --skill telegram-userbots

Prima di iniziare

  • L’installazione non include abbonamenti, quote API o accesso ai file.
  • Stelle e installazioni indicano attività, non un test indipendente di qualità o sicurezza.
Documento Skill originale

Contenuto dal repository con titoli, esempi, codice, tabelle, link e immagini preservati.

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.md`logging in, storing a session, rotating one, or moving between machines
`references/rate-and-flood.md`anything that loops over chats, users or messages — FloodWait, pacing, takeout
`references/entities-and-history.md`resolving 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

python
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

python
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?).

  1. The session is in a secret store, gitignored, and revocable (§ *The

session file is the credential*).

  1. `FloodWaitError` is caught, capped and alerted on — never slept off

unbounded (§ `FloodWaitError` is the API working).

  1. The client version is pinned, and the upgrade is its own change (§ *Pin

the minor*).

  1. A dead session pages a human rather than restarting forever (§ *Two

accounts, two lifetimes*).

  1. 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", "телетон".

dallo stesso repository

Altri Skills

Tutti gli Skills