Telegram OSINT, scraping and archival.
A local web app that runs entirely on your machine and talks only to Telegram.
npm install
npm startThen open http://127.0.0.1:5173. The first run walks you through API credentials, a QR sign-in and loading your dialogs. Telegram is the only server it talks to. There is no account to create, no telemetry and no service in between: what you collect stays in a SQLite file you own.
Successor to telegram-scraper, telescope and Harrier, built on Telethon 1.44.
| Collect | Channels, groups and forum topics across several accounts, with media, dedup and resume |
| Investigate | Phone, @username, id or t.me link to a profile, every historic photo, and a diff since last time |
| Export | Ten formats, from a plain CSV to a hashed evidence bundle |
| Runs on | Node 18+, Python 3.12+, SQLite. One database, one folder, no services |
Collect
- Every channel, group, forum topic and chat, across every signed-in account, in one selectable
tree with the full
-100id alongside the name and a badge for the account that sees it - Each dialog is collected under the account that can actually read it, so a selection spanning two accounts starts one run per account
- Messages with full metadata: views, forwards, reactions, edit dates, albums, polls, geo, links, reply chains, post authors and the forward source of every message
- Forum groups split by topic — collect single topics rather than whole groups
- Media downloaded in parallel and deduplicated by SHA-256 and Telegram file id, so a file forwarded to five channels is stored once
- Resume from a per-dialog watermark; continuous mode re-checks on an interval
- Saved collections re-run a selection with one click
Investigate
- Look up a phone number,
@username, user id ort.melink - Bio, flags, last-seen precision as a privacy indicator, chats in common, personal channel
- Anything Telegram chooses to volunteer about the account: the month it was registered, the country its phone number belongs to, when the person last renamed themselves or swapped their photo, their auto-delete timer, the name shown on restricted forwards. Be warned that it usually volunteers none of it. Those fields ride along on the anti-scam panel Telegram shows when a stranger writes to you, and come back empty for a profile you look up directly, so treat them as a bonus rather than something to plan around
- Business accounts do reliably give a street address, coordinates and a timezone
- Every visible profile photo, hashed with SHA-256 and a perceptual hash, shown as a gallery
- Perceptual hashes are matched across accounts, so the same picture on a second profile surfaces
- Message senders are recorded as they are scraped, so a name in the browser is a working link to a lookup even when the person has no username; "Sync members" fills that in for anything collected earlier
- Every lookup is snapshotted and diffed: username changes, display-name changes, bio edits, photos added or removed, changed privacy
Export
| Format | What you get |
|---|---|
csv |
One file per dialog |
json / jsonl |
Full metadata; JSONL streams row by row |
xlsx |
Sheets for messages, media, participants and reactions |
html |
Standalone report: stats, activity, top senders, forward sources, searchable table |
markdown |
The same report as text |
gexf / edges |
Forward graph for Gephi and Maltego |
sqlite |
A standalone database of only the selected dialogs |
bundle |
ZIP with data, media, a manifest of SHA-256 hashes and the collection log |
- Node.js 18+
- Python 3.12+
- API credentials from my.telegram.org/apps
npm install creates the Python environment under server/.venv and installs both sides.
| What | Where |
|---|---|
| Config | ~/.config/tgscope/config.json (mode 600) |
| Database | ~/.local/share/tgscope/tgscope.db (WAL, FTS5) |
| Media | ~/.local/share/tgscope/media/ |
| Exports | ~/.local/share/tgscope/exports/<timestamp>-<label>/ |
One database holds everything, which is what makes cross-dialog search, the shared user table, media dedup and the forward graph possible.
Files are filed by dialog type, then dialog, then forum topic, then media kind:
media/
├── channels/technews_-1001234567890/
│ ├── photos/00004711-8001-conference-slides.jpg
│ └── documents/00004802-8210-quarterly-report.pdf
├── groups/pythondev_-1009876543210/
│ ├── general/photos/…
│ └── help/voice/00000004-9004-voice.ogg
└── profiles/123456789/000-5544332211.jpg
Directory names combine the handle with the full id, non-ASCII titles are transliterated, and file names are zero-padded so they sort chronologically.
Every Telegram call goes through a per-account governor with a token bucket and FloodWait
backoff, and every paged read - messages, dialogs, members, profile photos - waits a flood out and
resumes rather than failing the run. Three profiles:
| Profile | Media workers | Request spacing | Waits absorbed silently |
|---|---|---|---|
stealth |
1 | 1.6 s | up to 180 s |
balanced |
4 | 0.35 s | up to 90 s |
fast |
8 | none | up to 45 s |
Longer waits are announced in the activity log and waited out; twelve in a row on one read gives up and reports it.
Multiple accounts are supported. Mark one as a burner in Settings and phone lookups run on it automatically, because that is the one risky operation:
A phone lookup imports the number as a contact for a moment and deletes it again. If the owner already has your number saved, they may see a "joined Telegram" notification. tgscope asks first, every time, and the profile card records which account it used.
npm test # 92 backend and 42 frontend tests, no network needed
npm run build # production bundle of the clientThe backend is FastAPI over a Telethon core, tested against a fake Telethon client: the scraper, the exporters, the media layout and every schema migration. The frontend tests cover the pure logic behind the browser, period arithmetic, histogram bucketing and the number and timestamp formatting, and render every screen twice, once empty and once populated.
scripts/demo/ regenerates docs/preview.gif from seeded fake data. It needs chromium and
ffmpeg, touches nothing in your real workspace, and is not part of the app.
The source carries no comments — naming and structure carry the meaning, and a test enforces it.
For research, journalism and authorised investigations. It uses the official Telegram API through Telethon and reads only what your account can already see — it does not bypass anyone's privacy settings. Do not use it for harassment or stalking, respect Telegram's terms of service, and mind the data-protection law that applies to you.
MIT licensed.
