Back to Blog

The Complete Telegram CSV Export Guide (2026)

May 13, 2026·

Open Telegram Web, click the extension, pick members, chats, contacts or media, and export a CSV that opens cleanly in Excel.

This is the Telegram Scraper extension — install it here.

CSV is the universal solvent of business data. It opens in Excel, Sheets, Numbers, every BI tool, every CRM importer, every legacy system that's been running since 2009. Telegram, by contrast, exports HTML and JSON — useful for engineers, opaque for everyone else.

This guide covers three paths from Telegram to a clean CSV, the encoding gotchas that break exports for everyone who skips them, and a downloadable sample so you can test your pipeline before you point real data at it.

Why CSV at all

JSON is great for engineers. HTML is great for nobody — at least not as a data format. CSV is what your finance team can open, what your CRM imports without a custom mapper, what your data-analyst intern can pivot in Sheets.

If your downstream is a Postgres ingest, sure, use JSON. If your downstream is a human, use CSV. Most exports are the second case.

What Telegram's native export gives you

Telegram Desktop has a built-in export buried under Settings → Advanced → Export Telegram Data. You can choose HTML or JSON. Both are everything-or-nothing: all your chats, all your media, no per-group control, no date range.

The HTML output is human-readable — open messages.html in a browser and scroll. It's a backup. It's not analyzable.

The JSON output is parseable but nested in a shape that needs flattening before it touches a spreadsheet. A typical message looks like:

{
  "id": 12345,
  "type": "message",
  "date": "2026-05-08T14:22:11",
  "from": "Jane Doe",
  "from_id": "user12345",
  "text": "Welcome to the group!"
}

Multiply by 200,000 messages and you've got 80MB of JSON to flatten. Doable, not delightful.

Neither output is CSV-ready. That's the gap this guide fills.

Code editor with a CSV export script open

Three paths to a clean CSV

Path Best for Time investment
Convert native JSON One-time pulls, technical user 20–60 min
Custom Python script Recurring exports, complex shaping 1–2 hours setup
Browser extension (Mastros) Recurring or ad-hoc, no setup 60 seconds

Path A — Convert the native JSON

If you already have the JSON dump and just need a one-off CSV, a 30-line script will get you there:

import json, csv

with open('result.json') as f:
    data = json.load(f)

with open('messages.csv', 'w', newline='', encoding='utf-8-sig') as f:
    w = csv.writer(f)
    w.writerow(['id','date','from','from_id','text'])
    for chat in data['chats']['list']:
        for m in chat.get('messages', []):
            if m.get('type') != 'message':
                continue
            text = m.get('text', '')
            if isinstance(text, list):  # text can be a list of styled fragments
                text = ''.join(t if isinstance(t, str) else t.get('text','') for t in text)
            w.writerow([m['id'], m['date'], m.get('from',''), m.get('from_id',''),
                        text.replace('\n', ' ')])

Watch out for the text field — Telegram returns a list of styled fragments when there's bold, italic, links, or mentions in the message, and a plain string otherwise. Flattening both shapes is the only fiddly part.

Path B — Write a fresh script with Telethon

If you don't have a JSON dump and you want repeatability, skip the conversion and pull straight to CSV with Telethon. This is covered in our member-export guide — the same client, different API call (iter_messages instead of GetParticipantsRequest).

Path C — Mastros → spreadsheet in 60 seconds

The Telegram CSV export is the whole of this path: install, open the chat on Telegram Web, pick what to save, download the file.

Open Telegram Web, click the Mastros toolbar icon, choose what to export (members, messages, media metadata), pick CSV, hit Go. The file lands in your Downloads folder. Drag it into Sheets. Done.

Behind the scenes: Mastros runs the same MTProto API calls Telethon would, but inside your browser tab — no credentials handshake, no Python, no server. Practically every benchmark we've run has Mastros faster than the equivalent Python script for the simple reason that it doesn't need to spin up a process or re-authenticate.

Encoding gotchas — the unsexy stuff that breaks exports

This is where most homegrown scripts fall over. Three rules:

1. UTF-8 with BOM, always

Without the BOM, Excel renders 中文, русский, 우리, العربية, and emoji as garbled boxes. Sheets is more forgiving but still mangles a few edge cases. The fix is one character — the byte-order mark  at the start of the file:

open('out.csv', 'w', encoding='utf-8-sig')  # the -sig variant adds the BOM

Mastros writes with BOM by default. Your homegrown script probably doesn't. If your CSV looks fine in Notepad and broken in Excel, this is why.

2. Phone numbers as text, not numbers

+44 7700 900123 becomes 4.47e10 in Excel if you let the spreadsheet infer types. Solutions, in order of preference:

  • Prefix with an apostrophe in the cell ('+44 7700 900123) — Excel reads as text.
  • Wrap in ="…" syntax (="+447700900123") — also forces text.
  • Train your downstream to use Sheets, which handles +-prefixed strings correctly.

Mastros uses the apostrophe-prefix approach because it survives a round-trip through Excel.

3. Line breaks inside bios and messages

Replace \n with or just a space. Do not let raw newlines into a CSV cell unless you enjoy debugging at 11pm. Strict CSV allows quoted newlines, but half the world's importers don't.

text.replace('\r', ' ').replace('\n', ' ')  # belt and suspenders

The CSV pitfalls every script hits

Beyond the big three, a handful of smaller landmines:

Commas in bios ("Founder, builder, dad") — quote the field. Python's csv module does this automatically; if you're hand-rolling, use csv.writer instead of f.write.

Quotes inside fields — double them. She said "hi" becomes "She said ""hi""". Again, csv.writer handles it.

Trailing whitespace from copy-paste — strip on read. df['username'].str.strip() in pandas, or s.strip() in raw Python.

Inconsistent column counts — your script crashed mid-export and resumed without truncating; rerun, don't patch. A CSV with 9 columns on row 4,801 and 10 columns elsewhere will silently corrupt every downstream join.

Trailing commas vs. trailing emptiesa,b, and a,b,"" look the same in Excel but parse differently in pandas. Pick one; standardize.

Sample dataset

Grab a 200-row sample CSV (members of a fictional crypto community) below. Use it to test your import pipeline before you point real data at it.

The sample includes:

  • All field types (numeric IDs, Unicode names, emoji-laden bios, blank phones)
  • Edge cases (commas in bios, quotes in messages, RTL languages, mixed-script display names)
  • A few rows of bots — useful for testing filter logic
  • 200 rows total — enough to feel real, small enough to inspect manually

A 60-second test of your pipeline

Once you have the sample:

  1. Drop into Sheets — does it open with columns aligned and emoji intact?
  2. Pivot by role — do you get member, admin, creator and not member , admin?
  3. Filter is_bot = TRUE — do you get the four bots and not 0 or 12?
  4. Sort by join_date desc — are the recent rows at the top, dates not jumbled by string-sort?

If any of those fail, you've got an encoding or quoting problem to fix before you process real data.

When CSV stops being the right format

CSVs scale fine to a few hundred thousand rows. Past that, columnar formats (Parquet, Arrow) load faster and compress better. If you're piping daily Telegram exports into a warehouse, switch to Parquet at the ingestion step — Mastros has a Parquet output for paid tiers, or convert post-hoc with pandas.read_csv(...).to_parquet(...).

For pure analyst use cases under a million rows? Stay on CSV. The portability beats the performance gain.


Install the Telegram Scraper → mastros.online/telegram-scraper — get your first clean CSV out of Telegram in 60 seconds, encoding handled.

FAQ

Why does my Telegram CSV show garbled characters in Excel?

The file is missing its byte-order mark. Without a BOM, Excel renders Chinese, Russian, Korean, Arabic, and emoji as boxes — Sheets is more forgiving but still mangles edge cases. In Python the fix is one flag: open the file with encoding='utf-8-sig' instead of utf-8. If the CSV looks fine in Notepad but broken in Excel, this is always the reason.

Why did Excel turn my phone numbers into scientific notation?

Excel infers types on open, so +44 7700 900123 becomes 4.47e10. The most reliable fix is to prefix the value with an apostrophe in the cell, which forces Excel to treat it as text and survives a round-trip through the spreadsheet.

How should line breaks inside bios and messages be handled?

Replace them before writing, with a space or a pilcrow. Strict CSV does permit quoted newlines, but a large share of real-world importers mishandle them, so raw newlines in cells are a reliable source of late-night debugging.

Does Telegram export CSV directly?

No. The native export produces HTML or JSON — useful to engineers, opaque to everyone else. Getting to CSV means converting the JSON, writing a script against the API, or using a tool that outputs CSV directly.

What breaks CSV exports most often?

Commas and quotes inside bios (use a real CSV writer rather than string concatenation — it quotes and escapes for you), trailing whitespace from copy-paste, and inconsistent column counts after a script crashed and resumed without truncating. That last one is the dangerous case: a row with nine columns among tens, and every downstream join silently corrupts.

At what point should I stop using CSV?

CSV is fine to a few hundred thousand rows. Past that, columnar formats like Parquet or Arrow load faster and compress far better, so switch at the ingestion step if you are piping exports into a warehouse daily. For analyst work under a million rows, portability still beats the performance gain.

Related reading