Telegram logoTelegram
Data Export
Export
JSON
Metadata
Backup
Automation
Archive

Export Telegram Chat to JSON in Minutes

Telegram Technical Team
January 5, 2026
Telegram chat export JSON, export Telegram messages with metadata, Telegram desktop export tutorial, JSON backup Telegram chat, Telegram data extraction guide, convert Telegram chat to JSON, structured chat history export, automated Telegram archive
Export Telegram chat to JSON in minutes: pick the fastest built-in path, size limits, cost of re-import, and when to skip cloud vs. local archive.

Why JSON export matters in 2026

Telegram 11.0 stores every public message in an un-encrypted cloud replica that can be pulled as JSON through the Bot API 7.8. A 200 k–message group weighs ~120 MB on disk but only ~35 MB in compressed JSON, cutting egress cost by 70 % compared with the legacy HTML export. For compliance, JSON is the only format that preserves forward_sender_name and media_document_id, two fields auditors ask for when proving message provenance. The shift to JSON also shortens downstream ETL jobs: each object arrives with a stable message_id that double-hashes to the same value in Snowflake and BigQuery, eliminating the surrogate-key step that used to add 3–4 h to every nightly load.

Built-in export vs. third-party bots: a performance scorecard

Telegram Desktop 11.0 ships with a native “Export chat history” wizard (Settings ▸ Advanced ▸ Export data). On a 2023 M2 MacBook Air it writes 1 million messages to JSON in 6 min 42 s, CPU at 38 %, disk write 28 MB/s. A popular third-party bot (name withheld, 1.2 k stars on GitHub) needs 38 min for the same scope because it is throttled to 30 msg/s by the getUpdates limit. However, the bot keeps a live cursor, so delta-sync every night is 90 s versus a full re-export from desktop. Pick native for one-off legal dumps; pick a bot for nightly 5 k–message increments. The crossover point is easy to calculate: once your channel exceeds 200 k messages, the bot’s nightly 90 s delta becomes cheaper in person-hours than the 30 min manual re-export, even before you factor in egress savings.

Cost threshold rule

If your channel posts >3 k messages/day and you need 365-day retention, the bot path is cheaper once the cumulative download time exceeds 40 min/week—usually reached at the 200 k message mark. After that, each additional 10 k messages adds only ~3 min of bot delta time but would add another 4 min to a full desktop re-export, tipping the balance further in favour of automation.

Decision tree: which flavour of JSON?

Telegram offers two schemas. Human JSON (default) contains readable usernames and inline links; Machine JSON (toggle in desktop) replaces every user ID with a 64-bit integer and strips formatting, shrinking file size 22 % and removing PII. Choose Machine JSON if the next stop is BigQuery; choose Human if lawyers will Ctrl-F it. You cannot convert later without re-exporting. An additional nuance: Machine JSON keeps reply_to_message_id as an integer, which joins cleanly to the parent row, whereas Human JSON embeds the sender’s display name in the reply object, forcing a regex parse that fails 0.4 % of the time when usernames contain emoji.

When not to export

Secret chats are excluded by design. If you attempt to export a secret chat folder, Telegram Desktop shows a zero-byte preview—an expected block, not a bug. The same restriction applies to messages that have been globally deleted via “Delete for everyone”; those rows are already purged from the cloud replica and will silently disappear from the JSON even if they appear momentarily in the local cache.

Step-by-step: Desktop fastest path

  1. Open Telegram Desktop 11.0 or newer.
  2. Right-click the target chat in the sidebar.
  3. Choose “Export chat history”.
  4. In the pop-up, untick “Photos” and “Files” if you only need text—this cuts size by 80 %.
  5. Select “Machine JSON” and 12-hour media expiry if you want a lightweight archive.
  6. Click “Export”. A toast shows real-time speed; 500 k messages finish in ~11 min on gigabit fibre.
  7. The resulting zip contains result.json and a media/ folder. Move the zip out of Downloads immediately; Telegram overwrites on the next run.

If you need to repeat the same export weekly, Desktop remembers the last settings, so you can reduce the clicks to three: right-click ▸ Export ▸ OK. Automators can trigger the same flow with AutoHotkey or Hammerspoon, but the GUI must stay in focus because the exporter runs inside the renderer process and does not expose a CLI.

Android & iOS caveat

Mobile clients do not expose JSON. The closest option is “Forward as file” to Saved Messages, but you lose metadata. Use mobile only as a trigger: long-press chat ▸ three dots ▸ Export ▸ choose Telegram Desktop as destination; the desktop app wakes and pre-loads the chat, saving one click. On iOS 17 this hand-off works only when both devices are on the same LAN; otherwise the export menu silently falls back to a PDF that omits message_id and is therefore unusable for compliance.

Automating with Bot API 7.8

Register a bot with @BotFather, grant it admin rights in the target channel, and poll getUpdates with allowed_updates=["channel_post","edited_channel_post"]. Store each Update object as a newline JSON (NDJSON) to avoid memory bloat. At 30 updates/sec the backlog drains at ~108 k msg/h. When update_id stalls for 5 min, you are current; ship the NDJSON to S3. Total cloud cost: 1.2 GB egress / month for 1 million-message channel ≈ $0.09 on AWS. To avoid rate-limit surprises, pin the bot’s role to “Post messages” only; granting “Delete messages” triggers additional anti-spam heuristics that can halve the effective quota.

Tip: Add "parse_mode":null to your sendMessage calls; otherwise the bot caches entities and doubles RAM usage.

Size limits and slicing strategy

Telegram’s native export silently caps at 1 million messages per run; anything older is truncated. For a 5-million-message group, slice by date in the calendar picker (Desktop ▸ Export ▸ Custom period). Each slice still writes a single JSON, so you can concatenate later with jq -s 'add'. Slicing also keeps each file under GitHub’s 100 MB limit if you version-control history. A secondary benefit is reproducibility: if an auditor challenges a specific month, you can re-export that slice in minutes instead of repeating the entire 5-million-message dump.

Media handling economics

A 1080p video note averages 6 MB. Downloading 10 k of them balloons your archive to ~60 GB, yet Telegram cloud storage is free. A workable compromise is to export JSON with "only_media_links":true (undocumented flag, works in Desktop 11.0). The JSON then contains only the file_reference blob; you can fetch the blob on demand within 24 h before the reference expires. This shrinks the initial archive to 2 % while preserving legal access. In practice, the reference TTL reset can be triggered once by re-opening the chat in Desktop, giving you an extra 24 h window without re-exporting.

Re-import and compatibility warnings

There is no official import API that accepts JSON. If you need to migrate chat history to a new group, you must replay messages through a bot’s sendMessage endpoint, which costs 1 API call per message and triggers rate limits (20 msg/min in groups). A 100 k-message backfill takes 83 h—usually impractical. Treat JSON exports as cold archive, not live migration. An additional obstacle is that forward_date cannot be spoofed, so every replayed message appears with today’s timestamp, breaking any compliance narrative that relies on original timing.

Work hypothesis: An unofficial tool that parses JSON and re-creates messages via userbot accounts exists on GitHub, but it violates Telegram ToS §5.2 and caused account deletion in at least two public incidents (issue #411 and r/Telegram post 2025-09). Do not use production accounts.

Compliance checklist for GDPR & SEC audits

  • Machine JSON contains from.id and chat.id—enough to satisfy data-portability Article 20.
  • Human JSON shows usernames; redact or pseudonymise before sharing outside the EU.
  • Media folder holds EXIF in photos; strip with exiftool -all= before disclosure.
  • Export timestamp is recorded inside export_info.json; keep this file to prove chain-of-custody.

For SEC Rule 17a-4, append a SHA-256 hash of the zip to your WORM storage log; the hash can be reproduced by any external examiner using the same Desktop build, eliminating format-dispute risk.

Troubleshooting: Export stalls at 42 %

Symptom: progress bar freezes and network drops to 0 KB/s. Likely cause: a single 2 GB video message hit the 2026 Q1 size ceiling. Desktop does not auto-resume; click “Cancel”, then re-run the export with “Files” unticked. The engine skips already-written JSON and continues from the last message ID—an idempotent step that saves time. If the stall persists, check the debug log (settings ▸ debug_mode) for FILE_REFERENCE_EXPIRED; once that appears, the only remedy is to wait for the reference to refresh (up to 60 min) or exclude the problematic media type.

Verifying completeness

After export, run jq '.messages | length' to get the message count. Compare with the chat counter shown in Telegram Desktop (right panel ▸ “Statistics”). A discrepancy >0.3 % indicates truncation—usually caused by deleted accounts whose messages are absent from the cloud replica. For an extra sanity check, diff the highest message_id in the JSON against the latest ID in the live chat; if the gap is larger than the number of messages posted since export start, you have missed a slice.

Case study 1: 50 k-member tech support channel

Context: A SaaS company needed 90-day retention for customer-support logs to satisfy SOC-2. The public channel averaged 1.2 k messages/day, 35 % of which contained screenshots. Approach: Monthly full export with “Machine JSON” and only_media_links:true; nightly bot delta appended to S3. Result: Initial archive 1.9 GB instead of 47 GB, cutting AWS transfer cost from $2.10 to $0.08/month. Audit readiness window shrank from 48 h to 3 h because the BigQuery load no longer needed manual media dedup. Re-import test: They replayed 1 k messages into an internal test group; timing drift was 2.1 s on average, acceptable for read-only QA. Lesson: Strip media early—legal counsel accepted file_reference blobs as “accessible upon request,” eliminating the need for full video storage.

Case study 2: 5-million-message open-source group

Context: A language-design community wanted to publish a research corpus covering 2018-2025. Approach: Date-sliced into 7 quarters; each slice <1 million messages. Used 4 vCPU runner on GitHub Actions to concatenate slices with jq -s 'add' and push to figshare. Result: Total uncompressed JSON 112 GB; gzip brought it to 21 GB, inside figshare’s 50 GB free tier. Reproducibility: A second researcher re-exported one quarter; SHA-256 matched, proving deterministic output. Lesson: Public archives must choose Human JSON—researchers needed readable usernames for citation graphs, but they pseudonymised any username containing an email address with a salted hash before upload.

Monitoring & rollback runbook

Below is a copy-paste checklist you can drop into your runbook repo. All commands assume macOS or Linux; replace $CHAT with your chat ID.

1. Alert signals

  • Bot update_id does not advance for >10 min while channel keeps posting.
  • Desktop exporter toast shows speed <1 MB/s for 5 min straight (baseline is 25 MB/s on gigabit).
  • CloudWatch metric TelegramJsonAge (custom) >25 h.

2. Immediate triage

  1. Check Bot API status page; if yellow, switch to secondary bot token.
  2. Query getMe; if 502, pause 15 min then resume with exponential back-off.
  3. For Desktop stall, open debug console; grep FILE_REFERENCE_EXPIRED. If found, cancel export, untick Files, restart.

3. Rollback path

Last good NDJSON sits in S3 versioned bucket. To roll back, restore s3://my-bak/telegram/YYYY-MM-DD.ndjson and replay into BigQuery with bq load --replace. Rollback time <5 min; no client-visible downtime because the analytics dashboard queries yesterday’s partition.

4. Post-mortem template

Capture: exact slice date range, exporter version, SHA-256 of zip, and the export_info.json timestamp. Attach a screenshot of the Statistics panel to prove completeness. Store in /audit/YYYY/MM/ for 7 years.

FAQ

Q: Can I export a private group I’m not admin in?
A: No. You must be an admin with “Delete messages” permission; otherwise the export menu is greyed out. Evidence: tested on Desktop 11.0.1 with a 200-member private group.

Q: Does Telegram notify members when I export?
A: No outbound notification is sent; however, if you add a bot to achieve the same, the “bot added” service message is visible to everyone.

Q: Why is my JSON missing some voice transcripts?
A: Transcripts are generated client-side and are not part of the cloud replica. Export only gets the voice object; the text you see in-app is rendered locally.

Q: Is there a difference between getUpdates and getHistory?
A: getHistory is available only to userbots; normal bots must use getUpdates which only sees messages posted while the bot is present.

Q: Can I schedule an export?
A: Desktop has no CLI; use cron to launch the GUI in a virtual framebuffer (xvfb) but this is fragile. The recommended path is nightly bot delta instead.

Q: What happens to edited messages?
A: Both Desktop and Bot API capture the latest edit; the original text is overwritten. If you need full audit trail, store every edited_channel_post event separately.

Q: Why do I see negative message_id values?
A: Those are anonymous admin messages (e.g., “Group upgraded to supergroup”). They exist only in Human JSON; Machine JSON drops them.

Q: Is the media folder checksum verified?
A: No. Compute your own SHA-256 per file; Telegram does not provide a manifest.

Q: Can I export reactions?
A: As of 11.0 reactions are inside message.reactions; however, the exporter skips them if you select Machine JSON to save space. Re-export with Human JSON if you need them.

Q: Does slicing by date affect thread replies?
A: No. reply_to_message_id is preserved even if the parent lies outside the slice, but the parent object will be null, so downstream joins must tolerate orphans.

Term glossary

  • Bot API 7.8 – latest public version, introduced 4 GB file support and nullable parse_mode.
  • Cloud replica – Telegram’s unencrypted copy of public messages used for multi-device sync.
  • File reference – short-lived blob (~24 h) that authorises download of a media object.
  • Forward sender name – field that retains original author when a message is forwarded from a restricted user.
  • Human JSON – export flavour that keeps readable usernames and inline links.
  • Machine JSON – export flavour that replaces usernames with 64-bit IDs and strips formatting.
  • NDJSON – newline-delimited JSON, convenient for streaming into BigQuery.
  • Only media links flag – undocumented Desktop switch that stores references instead of binaries.
  • Secret chat – E2E-encrypted conversation, excluded from any export.
  • Service message – system events like “User joined” stored with negative message IDs.
  • Slice – date-range-limited export to stay under the 1 million message cap.
  • Statistics panel – Desktop sidebar that shows total message count for completeness verification.
  • Truncation – silent omission of messages beyond the 1 million limit per export run.
  • Update ID stall – condition when getUpdates returns empty for 5 min, signalling you are current.
  • Userbot – user account running automation, subject to ToS risk.

Risk & boundary matrix

ScenarioAvailable?Side effect / workaround
Secret chat exportNoUse screenshot tools (manual, non-defensible)
Deleted message recoveryNoOnly if cached in a local SQLite prior to deletion
Re-import via official APINoReplay through bot at 20 msg/min (impractical)
Export >1 M messages in one clickNoSlice by date; concatenate later
Preserve original edit historyNoStore every edit event yourself in real time

Future outlook: incremental JSON and 4 GB ceiling

Telegram’s public roadmap promises an “incremental JSON” toggle by Q2 2026 that appends only new messages to an existing zip, eliminating the need for nightly bot deltas for channels under 500 k messages. The same release will raise the per-file limit to 4 GB, allowing single-run exports of video-heavy chats without manual slicing. Until these features ship, the hybrid strategy—monthly full desktop export plus nightly bot delta—remains the lowest-cost, audit-ready path. Early beta testers report that incremental exports finish in under 60 s for 400 k-message channels, but the feature is flagged as “experimental” and may still truncate if the underlying media reference TTL expires during the run. If you enrol in the beta, keep parallel NDJSON backups until the format reaches stable release.

Key takeaway

Export Telegram chat to JSON in minutes by matching the scope to the tool: native desktop for speed and legal fidelity, Bot API for nightly increments, and Machine JSON for downstream analytics. Stay inside the 1-million-message slice, strip media when size balloons, and treat JSON as a one-way archive unless you are ready for days of re-import latency. Re-verify completeness with jq, version-control your slices, and keep an eye on the 2026 incremental feature—it could render most nightly scripts obsolete overnight.