Easy dumping of all Telegram bot stuff.
Input: only bot token.
Output: bot name & info, all chats text history & media, bot's users info & photos.
This is a Python implementation.
π Fast Golang version by ScBoln.
A Telegram-Web-like browser UI for a dump: chat list, full message history with inline media, user profiles with a photo carousel, and global search across every conversation at once. Live mode supported: it runs the dumper in the background and streams new messages to the browser in real time.
Use case β pentesting a leaked bot token. Telegram bot tokens turn up constantly on an engagement β hard-coded in a mobile/desktop app, committed to a repo, or sitting in a CI log, config file, or client-side bundle. On its own a token looks like a low-severity finding; loading it here shows the real blast radius. For an internal bot (support desk, IT/DevOps helper, AI assistant) that is every employee conversation with it β internal hostnames, VPN profiles, credentials, and infrastructure details β browsable and searchable, so you can scope the impact and evidence the finding in your report.
docker run --rm -p 8010:8010 -v "$PWD:/data" soxoj/telegram-bot-dumper-webdocker compose up --build # builds and serves on http://127.0.0.1:8010pip install -r requirements.txt
python webapp/server.py # serves the current directory's dumps on :8010Open http://127.0.0.1:8010 and paste a bot token to pick its dump folder. Read-only viewing is auth-free, local, and needs no API credentials. Live mode additionally needs API_ID/API_HASH from my.telegram.org, passed via the environment β never baked into the image:
# one-off container
docker run --rm -p 8010:8010 -v "$PWD:/data" \
-e API_ID=123456 -e API_HASH=abc... soxoj/telegram-bot-dumper-web
# or with docker compose: put them in a local .env (see .env.example)
cp .env.example .env && $EDITOR .env && docker compose upPORT and HOST env vars override the defaults (8010, 127.0.0.1).
- Dump bot's messages with media content by walking message ids upwards (default) or downwards (
--down/--start-from-id). - Live listen mode (
--listen-only): receive new messages in real time and offer to dump history downwards from the first observed id. - Resolve user info both for incoming messages and for outgoing bot replies.
- Lightweight modes for fast user enumeration: skip media, skip per-chat text history, write users to a single CSV.
- Group / supergroup messages are tagged with
[from:USER][group:CHAT]. Outgoing bot DMs are tagged with[to:USER]. - Group monitoring: if the bot has been added to a group/supergroup AND its privacy mode is disabled, the bot receives all group messages β not just commands and replies β and
--listen-onlywill dump them in real time. With privacy mode enabled (the default) the bot only sees commands, mentions, and replies.
- Python >= 3.6
- Telethon (see
requirements.txtfor the pinned version) - Register a Telegram application to get
API_IDandAPI_HASH
pip install -r requirements.txt
# Telegram API credentials from https://my.telegram.org (read from the environment)
export API_ID=123456
export API_HASH=abc...Walks ids 1..β upwards in batches of 200, downloading every message, all media, and all user profile photos.
./dumper.py --token 12345678:ABCe2rPVteUWZ7wLeCqCb3CH3ilUY_fLabcFor an active bot the upward walk hits a long stretch of pruned (deleted/expired) old ids and gives up. Walking down from the most recent id is much more productive. --down auto-probes the upper bound (powers of 10 up to 10βΉ) and starts from the highest non-empty id it finds:
./dumper.py --token TOKEN --downNote. Telegram does not retain bot message history forever. Empirically, only the last few hundred thousand messages remain accessible β in our tests a busy bot exposed roughly the last 500K messages before
messages.getMessagesstarted returning onlyMessageEmptyfor older ids. If your bot has historically processed more traffic than that, the older history is simply gone server-side and no flag will recover it.
If you already know a recent message id (e.g. one you saw in real time), you can skip the probe and start exactly from it:
./dumper.py --token TOKEN --start-from-id 11922524Don't dump anything; just watch what arrives. On the first incoming message the script will offer to start a downward dump from that id:
./dumper.py --token TOKEN --listen-onlyUseful when you only need a roster of who has talked to the bot β no zips, no jpegs, no per-chat *_history.txt.
./dumper.py --token TOKEN --down --users-csv --no-photos --no-media --no-historyOutput: <bot_id>/users.csv with columns id, username, first_name, last_name, phone, lang_code, bot, premium, verified, scam, fake.
The downward walk prints Requesting message ids X..Y ... for every batch. If the run is interrupted, restart from the last printed lower bound:
./dumper.py --token TOKEN --start-from-id <Y>Smaller batches β faster feedback in the log and shorter recovery window after a FloodWait. Larger batches β fewer round-trips when scanning sparse / pruned id ranges. Values up to 1000 work fine in practice.
./dumper.py --token TOKEN --down --batch-size 50
./dumper.py --token TOKEN --down --batch-size 500
./dumper.py --token TOKEN --down --batch-size 1000| Flag | Effect |
|---|---|
--lookahead N |
After an all-empty batch, keep scanning N more batches before giving up. Useful when ids are sparse. |
--no-photos |
Skip downloading user profile photos (avatars). |
--no-media |
Skip downloading photos and documents inside messages; metadata is still written to text history. |
--no-history |
Don't write per-chat <chat_id>_history.txt. Combine with --users-csv for the lightest possible run. |
--users-csv |
Write users to a single <bot_id>/users.csv instead of <user_id>/<user_id>.json directories. |
--tor |
Route through a local Tor SOCKS5 proxy on 127.0.0.1:9050 (Telegram blocking bypass). |
Run ./dumper.py --help for the full list.
-
Bot exits before the history is fully dumped. If some messages have been deleted by users, a batch can come back entirely empty and the script may stop too early. Additionally, if the bot has processed a very large amount of traffic, old messages are simply not returned by Telegram's servers anymore β they have been pruned and no flag will recover them. For sparse-but-existing history, bump
--lookaheadto keep scanning past empty stretches:# check additionally 5*200 = 1000 ids ./dumper.py --token TOKEN --lookahead 5Or just use
--down, which is much less affected by gaps in old ids. -
History was not dumped for group chats (basic groups, supergroups).
messages.getMessagesonly returns the bot's PM history; supergroup history requires per-channel calls that bots typically can't make. Group messages are still captured live in--listen-onlymode if group privacy is off (see Features).
Offline unit tests (no network, no token):
pip install -r test-requirements.txt
pytest tests/ --ignore=tests/bot_test.pyIntegration test against a real bot (requires a working bot token):
TEST_TOKEN=12345678:... pytest tests/bot_test.pyDorks examples: telepot.bot
