Public Telegram channels are a good source of news, crypto signals, product announcements and community chatter. Getting that data into a spreadsheet is harder than it should be. The official Telegram API (MTProto) needs an account, a phone number and an api_id. Libraries like Telethon need a logged-in session, and copying posts by hand doesn't scale.

There is a simpler route for public channels. Telegram publishes a web preview of every public channel at https://t.me/s/<channel>. Anyone can see it without logging in. This tutorial shows how to turn that preview into a clean CSV: posts, view counts, reactions, links and media. It uses the Telegram Channel Scraper on Apify. You can run it from the browser, or call it from Python or curl.

What you can and can't scrape

What you can get from a public channel:

  • post text, date (UTC), post URL and ID
  • view count and the reaction breakdown (including paid ⭐ Stars reactions)
  • links, hashtags, mentions and link previews
  • photos, videos and documents (CDN URLs), forwards and replies
  • channel title and subscriber count

What you can't get, by design: private channels, invite links (t.me/+...), groups, chats, comment threads and member lists. If you need those, you need the official API and an account. Some channels also switch off the web preview. The scraper reports these as preview_disabled and doesn't charge for them.

Step 1: Check that the channel has a web preview

Open https://t.me/s/durov in a browser. If you see a scrollable list of posts, the channel can be scraped this way. If Telegram only shows a "View in Telegram" button, the owner has disabled the preview.

The input accepts several formats, so use whichever you have:

  • durov
  • @durov
  • https://t.me/durov
  • https://t.me/s/durov

Step 2: Run the scraper

  1. Open Telegram Channel Scraper and click Try for free. You need a free Apify account. No credit card is needed for the free plan.
  2. In Channels, add one or more channel names.
  3. Set Max posts per channel. Start with 100. Telegram serves about 20 posts per page, so 100 posts is about five page loads.
  4. Optional: set Date from / Date to for a time window, or add Keywords to keep only matching posts.
  5. Click Start.

Here's the input we used for a test run on Nov 11, 2026:

{ "channels": ["durov", "telegram"], "maxPostsPerChannel": 100, "includeMedia": true } 

That run returned 200 posts from 2 of 2 channels in about a minute.

Step 3: Look at the output

Each post is one dataset item. Here's a real item from that run, trimmed (media CDN URLs shortened):

{ "channel": "durov", "channelTitle": "Pavel Durov", "channelSubscribers": 10000000, "postId": 554, "url": "https://t.me/durov/554", "datetime": "2026-11-10T12:59:06+00:00", "text": "Any Telegram message can now become an app. ...", "views": 993000, "isForwarded": false, "isReply": false, "links": ["https://t.me/BotNews/122"], "hashtags": [], "media": [{ "type": "video", "url": "https://cdn4.telesco.pe/file/...mp4", "thumbnailUrl": "https://cdn4.telesco.pe/file/..." }], "reactions": [{ "emoji": "⭐", "isPaidStars": true, "count": 4870 }, "..."] } 

Notes on the data:

  • views are abbreviated on Telegram's side ("993K" becomes 993000), so treat them as rounded. Very new posts keep gaining views.
  • channelSubscribers is also Telegram's rounded public figure.
  • Media URLs are temporary Telegram CDN links. If you need the files, download them soon after the run.

Step 4: Export to CSV or Excel

In the run's Output tab, pick a view and click Export. You can choose CSV, Excel (XLSX), JSON, XML or HTML. The views are:

View Columns
Overview channel, postId, datetime, text, views, mediaTypes, isForwarded, url
Engagement channel, channelSubscribers, postId, datetime, views, reactions, url
Links & media channel, postId, links, linkPreview, media, forwardedFrom, replyTo, url

Overview is the best fit for a spreadsheet. Nested fields like reactions and media are flattened into columns in CSV. Use JSON if you want to keep them as lists.

Step 5: Automate it from Python or the command line

To skip the browser, call the Actor through the Apify API. Get your API token from Apify Console → Settings → API & Integrations.

curl: this endpoint runs the scraper and returns the results as CSV in one call (for runs up to 5 minutes):

curl -X POST \ "https://api.apify.com/v2/acts/signalwharf~telegram-channel-scraper/run-sync-get-dataset-items?format=csv&view=overview" \ -H "Authorization: Bearer $APIFY_TOKEN" \ -H "Content-Type: application/json" \ -d '{"channels": ["durov"], "maxPostsPerChannel": 50}' \ -o durov.csv 

Python (pip install apify-client):

import os from apify_client import ApifyClient client = ApifyClient(os.environ["APIFY_TOKEN"]) run = client.actor("signalwharf/telegram-channel-scraper").call( run_input={"channels": ["durov", "telegram"], "maxPostsPerChannel": 100} ) # Save as CSV csv_bytes = client.dataset(run["defaultDatasetId"]).get_items_as_bytes(item_format="csv") open("telegram_posts.csv", "wb").write(csv_bytes) # Or work with the items directly for post in client.dataset(run["defaultDatasetId"]).iterate_items(): print(post["datetime"], post["views"], post["url"]) 

Step 6: Monitor a channel for new posts

If you want only the posts published since the last run, turn on Only new posts (onlyNewPosts: true). The scraper remembers the last post it saw for each channel. The state lives in a named key-value store in your own Apify account. Then create a Schedule in Apify Console, for example every 15 minutes or every morning, and connect it to Google Sheets, Slack, a webhook, Make or Zapier using Apify's integrations.

Example monitoring input with a keyword filter:

{ "channels": ["durov", "telegram"], "onlyNewPosts": true, "keywords": ["update", "launch"], "maxPostsPerChannel": 50 } 

A monitoring run that finds nothing new charges nothing.

How much does it cost?

The Actor uses pay-per-event pricing, with no monthly fee:

Event Price
Channel with results (once per channel per run, only if it yields at least one post) $0.002
Post saved $0.0015 ($1.50 per 1,000 posts)

Our 200-post test run cost 2 × $0.002 + 200 × $0.0015 = $0.304. One channel with 100 posts costs about $0.15. Filtered-out posts, empty channels and failed channels aren't charged. You can set a maximum cost per run in the run options, and the scraper stops cleanly when it reaches it. Apify's free plan includes a monthly platform credit, which covers small tests like these. Check Apify's pricing page for the current amount.

Troubleshooting

  • Channel returns preview_disabled: the owner turned off the web preview. There's no way around this without the official API.
  • Fewer posts than requested: the channel has fewer posts, or your date or keyword filters removed them.
  • views is null: some service messages have no view count.
  • Very deep history is slow: each page is about 20 posts, fetched with a polite delay (1.5 s by default). Thousands of posts take a few minutes.

Is it legal to scrape Telegram?

This approach reads only what Telegram publishes openly at t.me/s/. It doesn't log in, bypass access controls, or touch private messages or member lists. Posts can still contain personal data, so make sure your use complies with the GDPR and other privacy laws, Telegram's Terms of Service, and copyright. When in doubt, ask a lawyer.

Related tools

Built and maintained by Signal Wharf. Telegram is a trademark of its owner; this tool is not affiliated with or endorsed by Telegram.