Telegram channels are where a lot of news, crypto, product and community announcements land first. If you want to archive a channel, track keywords across several channels, or feed posts into an LLM, the official route (MTProto via Telethon) needs an API ID, a phone number and a logged-in session. For public channels there is a simpler way.

The trick: the public web preview

Every public channel has a read-only web preview at https://t.me/s/<channel>. It is plain HTML, works without login, and shows the latest ~20 posts with dates, view counts and text.

# pip install requests beautifulsoup4 import requests from bs4 import BeautifulSoup def latest_posts(channel): html = requests.get(f"https://t.me/s/{channel}", timeout=20).text soup = BeautifulSoup(html, "html.parser") for msg in soup.select(".tgme_widget_message"): text = msg.select_one(".tgme_widget_message_text") views = msg.select_one(".tgme_widget_message_views") yield { "url": "https://t.me/" + msg["data-post"], "date": msg.select_one(".tgme_widget_message_date time")["datetime"], "views": views.text if views else None, "text": text.get_text(" ", strip=True) if text else "", } for p in latest_posts("telegram"): print(p["date"], p["views"], p["url"], p["text"][:60]) 

Output:

2026-08-26T19:12:24+00:00 1.87M https://t.me/telegram/459 Signed Gifts. You can now add your signature and a comment t 2026-08-26T19:12:34+00:00 2.12M https://t.me/telegram/460 For all the info from today's update and a look back at 13 y 

Gotchas if you extend this yourself:

  • Only ~20 posts per page. Older posts need ?before=<postId> pagination, looping until you pass your start date.
  • Views come as 1.87M / 12.3K strings; convert them before sorting.
  • Use the time inside .tgme_widget_message_date — videos also contain <time> elements (durations) without a datetime attribute, which crashes a naive select_one("time").
  • Forwards, replies, reactions, media URLs and edited flags each live in different elements.
  • Channels with the preview disabled return no messages at all.

If you don't want to maintain that

Disclosure: I built a small Apify Actor that does the pagination, date range, keyword filter and field parsing above: Telegram Channel Posts Scraper. It costs $1.50 per 1,000 posts (Apify's free monthly credit covers a few thousand) and you can call it with plain requests:

# pip install requests import os, requests URL = ("https://api.apify.com/v2/acts/bachiembmt~telegram-channel-posts-scraper" "/run-sync-get-dataset-items") run_input = { "channels": ["durov", "https://t.me/telegram"], "maxPostsPerChannel": 60, "fromDate": "2026-01-01", "keywords": ["gift", "update"], "includeChannelInfo": False, } items = requests.post(URL, json=run_input, timeout=300, headers={"Authorization": f"Bearer {os.environ['APIFY_TOKEN']}"}).json() for post in items: print(post.get("date"), post.get("views"), post.get("url"), (post.get("text") or "")[:60]) 
2026-02-10T17:44:05+00:00 1940000 https://t.me/telegram/426 Gift Crafting. Collectible gifts can now be combined to crea 2026-01-07T18:17:53+00:00 2730000 https://t.me/telegram/423 Happy New Year! Telegram released 13 major updates in 2025 – 

Each post has channel, postId, url, date, text, views (as an integer), forwardedFrom, replyTo, hasMedia, mediaType, mediaUrls, links, reactions, edited. The dataset exports to CSV/Excel/JSON from the Apify console, and you can schedule the run daily to build a keyword alert.

Limits, honestly

  • Public channels with the web preview enabled only. No private channels, groups or comments.
  • It reads the same public HTML as the snippet above, so if Telegram changes the markup both break until fixed.
  • Respect each channel's content rights when you republish anything.

If the DIY snippet is enough for you, use it — it is genuinely 20 lines. The Actor is for when you need many channels, history and a schedule without babysitting a parser.