Want to automatically post latest news to your Telegram channel every hour — without running any server or paying for hosting? In this guide, you will learn how to build a fully automated news bot using Python, Google News RSS, Telegram, and GitHub Actions.
By the end, you will have a bot that fetches fresh news on any topic and delivers it straight to your Telegram channel — completely free, no server required.
👉 Live Project: You can view the complete working example on GitHub: https://github.com/aiocrafters/telegram-channel
🚀 What You Are Building
A bot that:
- Fetches news from Google News RSS (based on a topic like AI News)
- Scrapes article text and generates AI summaries using OpenRouter
- Sends formatted updates to your Telegram channel
- Runs automatically every hour via GitHub Actions
- Tracks sent articles to avoid duplicate posts
🧠 Why This Approach is Powerful
Most bots require external infrastructure. This approach uses GitHub Actions as a free scheduler, giving you everything you need at zero cost.
| Requirement | Traditional Bot | This Method |
|---|---|---|
| Hosting / VPS | Required ❌ | Not needed ✅ |
| Background server | Required ❌ | Not needed ✅ |
| Monthly cost | $5–$20+ 💸 | $0 ✅ |
| Maintenance | High | Minimal ✅ |
| Scalability | Manual | Easy ✅ |
1 Create a Telegram Bot
The first step is to create a bot using Telegram's official BotFather.
- Open Telegram on your phone or desktop
- Search for BotFather and open the chat
- Send the following commands one by one:
/start
/newbot
- Enter a display name for your bot (e.g., AI News Bot)
- Enter a username ending with
bot(e.g., ainews_bot) - Copy the Bot Token that BotFather provides — you will need this later
⚠ Keep your Bot Token private. This token gives full control over your bot. Never share it publicly or commit it directly to your repository.
2 Create a Telegram Channel
- Open Telegram and tap the pencil icon to start a New Channel
- Give your channel a name (e.g., AI News Updates)
- Set the channel as Public and choose a username
- Open channel settings → Administrators → Add Administrator
- Search for your bot username and add it as an admin with Post Messages permission
- Copy your channel username — it looks like:
@your_channel_name
💡 Tip: Your Telegram Chat ID for a public channel is simply its username (e.g.,
@ainewsupdates). For private channels, you will need the numeric ID.
3 Set Up API Keys & Config
To enable AI summaries, you will need an OpenRouter API key. Go to OpenRouter.ai, sign up, and create an API key.
Create a file named config.py in your repository to separate the configuration:
# config.py
TOPIC = "AI News"
MODEL = "openai/gpt-4o-mini"
MAX_ARTICLES = 10
RSS_URL = f"https://news.google.com/rss/search?q={TOPIC.replace(' ', '%20')}"
SEEN_FILE = "seen_news.json"
SUMMARY_CACHE_FILE = "summary_cache.json"
Now, create prompt_template.py to instruct the AI on how to summarize:
# prompt_template.py
SUMMARY_PROMPT_TEMPLATE = """
You are a professional journalist writing crisp news briefs.
Your task:
- Extract the MOST important facts
- Focus on WHAT happened, WHERE, and WHY it matters
Write output in this format:
🧠 <One-line headline>
🔹 Point 1
🔹 Point 2
🔹 Point 3
Rules:
- Max 5 points
- Each point short (8–15 words)
- Simple English
- No opinions
News:
{content}
"""
4 Write the Main Python Script
Create a file named main.py. This script uses newspaper3k to scrape the text and calls
the OpenRouter API to summarize it.
import requests, feedparser, json, os, time
from datetime import datetime
from dotenv import load_dotenv
from newspaper import Article
from config import TOPIC, MODEL, RSS_URL, MAX_ARTICLES, SEEN_FILE, SUMMARY_CACHE_FILE
from prompt_template import SUMMARY_PROMPT_TEMPLATE
load_dotenv()
BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
CHAT_ID = os.getenv("TELEGRAM_CHAT_ID")
OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY")
def load_json_file(file):
return json.load(open(file, "r")) if os.path.exists(file) else {}
def save_json_file(file, data):
json.dump(data, open(file, "w"), indent=2)
def extract_article_text(url):
try:
article = Article(url)
article.download()
article.parse()
text = article.text.strip()
return text[:2000] if len(text) >= 200 else None
except:
return None
def generate_summary(news, cache):
news_id = news["link"]
if news_id in cache: return cache[news_id]
text = extract_article_text(news.get("real_link", news["link"]))
content = text if text else news["title"]
url = "https://openrouter.ai/api/v1/chat/completions"
headers = {"Authorization": f"Bearer {OPENROUTER_API_KEY}", "Content-Type": "application/json"}
payload = {"model": MODEL, "messages": [{"role": "user", "content": SUMMARY_PROMPT_TEMPLATE.format(content=content)}]}
try:
res = requests.post(url, headers=headers, json=payload, timeout=30).json()
summary = res["choices"][0]["message"]["content"].strip()
cache[news_id] = summary
return summary
except:
return news["title"]
def run():
seen = set(load_json_file(SEEN_FILE))
summary_cache = load_json_file(SUMMARY_CACHE_FILE)
feed = feedparser.parse(RSS_URL)
for entry in feed.entries[:MAX_ARTICLES]:
link = entry.get("link", "")
if not link or link in seen: continue
news = {"title": entry.get("title", ""), "link": link, "published": entry.get("published", ""), "source": entry.get("source", {}).get("title", ""), "real_link": link}
summary = generate_summary(news, summary_cache)
message = f"🚨 {news['title']}\n\n{summary}\n\n📍 {TOPIC}\n📰 {news['source']}\n🕒 {news['published']}\n\n🔗 <a href='{link}'>Read more</a>"
requests.post(f"https://api.telegram.org/bot{BOT_TOKEN}/sendMessage", json={"chat_id": CHAT_ID, "text": message, "parse_mode": "HTML"})
seen.add(link)
time.sleep(1)
save_json_file(SEEN_FILE, list(seen))
save_json_file(SUMMARY_CACHE_FILE, summary_cache)
if __name__ == "__main__":
run()
Here is what the script does:
- Fetches the latest articles from Google News RSS
- Checks
seen_news.jsonto prevent duplicates - Scrapes the article content and sends it to OpenRouter API for summarization
- Caches the summaries in
summary_cache.jsonand posts to Telegram
5 Create the Requirements File
Create a requirements.txt file in the root of your repository:
requests
feedparser
python-dotenv
newspaper3k
lxml_html_clean
This tells GitHub Actions (and your local environment) which packages to install before running the script.
6 Set Up Environment Variables
For local testing, create a .env file in the project root:
TELEGRAM_BOT_TOKEN=your_bot_token_here
TELEGRAM_CHAT_ID=@your_channel_name
OPENROUTER_API_KEY=your_openrouter_api_key_here
⚠ Important: Add .env to your .gitignore file to prevent
accidentally pushing your credentials to GitHub.
Add this line to .gitignore:
.env
In production (GitHub Actions), these values will be read from encrypted GitHub Secrets —
not from the .env file.
7 Automate with GitHub Actions
Create the following file in your repository:
.github/workflows/news.yml
Add this content:
name: Google News to Telegram
on:
schedule:
- cron: "0 * * * *"
workflow_dispatch:
permissions:
contents: write
jobs:
run-news-bot:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: "pip"
- run: pip install -r requirements.txt
- run: |
[ -f seen_news.json ] || echo "[]" > seen_news.json
[ -f summary_cache.json ] || echo "{}" > summary_cache.json
- run: python main.py
env:
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
- run: |
git config --global user.name "github-actions"
git config --global user.email "actions@github.com"
git add seen_news.json summary_cache.json
git commit -m "Update seen + summary cache" || echo "No changes"
git push
💡 workflow_dispatch: This option lets you trigger the workflow manually from the GitHub Actions tab — useful for testing before waiting for the scheduled run.
Here is what each step does:
| Step | Purpose |
|---|---|
actions/checkout@v4 |
Clones your repository into the runner |
actions/setup-python@v5 |
Installs Python 3.11 |
pip install |
Installs the required Python packages |
Initialize seen_news.json |
Creates the file on first run if it does not exist |
python main.py |
Runs the bot script with secrets injected as environment variables |
| Git commit and push | Saves the updated seen_news.json and summary_cache.json back to the
repository |
8 Add GitHub Secrets
Your bot token and channel ID must be stored as encrypted secrets — never hardcoded in the workflow file.
- Open your GitHub repository
- Go to Settings → Secrets and variables → Actions
- Click New repository secret
- Add the following secrets:
| Secret Name | Value |
|---|---|
TELEGRAM_BOT_TOKEN |
Your bot token from BotFather |
TELEGRAM_CHAT_ID |
Your channel username (e.g., @your_channel_name) |
OPENROUTER_API_KEY |
Your OpenRouter API key |
⚠ Secrets are encrypted and never visible in logs. GitHub Actions automatically masks them if they appear in output.
🔄 How the Full System Works
- GitHub Actions triggers the workflow every hour (cron schedule)
- The runner checks out your repository and installs dependencies
- The Python script fetches the latest articles from Google News RSS
- It compares each article URL against
seen_news.json - For new articles, it scrapes the full text and sends it to the OpenRouter API to generate a summary
- These AI-summarized articles are sent to the Telegram channel
- The updated
seen_news.jsonandsummary_cache.jsonare committed back to the repository - On the next run, the process repeats seamlessly
⏱ Understanding the Cron Schedule
cron: "30 * * * *"
| Field | Value | Meaning |
|---|---|---|
| Minute | 30 |
At 30 minutes past the hour |
| Hour | * |
Every hour |
| Day | * |
Every day |
| Month | * |
Every month |
| Weekday | * |
Every day of the week |
💡 Note: GitHub Actions uses UTC time. The 30 minute offset helps align
runs more closely with IST (UTC+5:30) timing, so news lands on the hour in Indian
Standard Time.
🎯 Customization Ideas
🔹 Change the News Topic
Simply update the TOPIC variable in main.py:
TOPIC = "Artificial Intelligence"
This will fetch news about AI instead. You can use any keyword or phrase that Google News supports.
🔹 Run Multiple Topics
Create separate workflow files or loop over a list of topics:
TOPICS = ["AI News", "Government Jobs", "Stock Market"]
for topic in TOPICS:
fetch_and_send(topic)
🔹 Add Custom Hashtags
Customize the message footer with relevant hashtags for discoverability:
f"#AiNews #BreakingNews #India"
🔹 Adjust the Posting Frequency
Modify the cron expression to post every 2 hours, 6 hours, or daily:
# Every 2 hours
cron: "0 */2 * * *"
# Twice a day (9am and 9pm UTC)
cron: "0 9,21 * * *"
🚀 Advanced Upgrade Ideas
Once your basic bot is running, here are powerful extensions you can build on top of it:
- 🎛️ Multiple Channels — Route technical news to one Telegram channel and general news to another
- 🌐 Store in Supabase — Replace
seen_news.jsonwith a Supabase table for better scalability and a browsable history - 📡 Public API — Expose the news data through a REST API so your website can consume it
- 📊 Admin Dashboard — Build a simple web interface to view sent articles, manage topics, and monitor bot health
- 🧵 Thread-style Posts — Group related articles into a single Telegram thread for cleaner channel presentation
- 🌍 Multi-language Support — Use Google Translate API to post news in multiple languages
💡 Pro Tips
- Keep bot admin in channel: If the bot loses admin status, it will fail silently. Check channel admin settings periodically.
- Rate limiting: Telegram allows ~30 messages per second per bot. Add a small delay
between sends if posting many articles:
import time time.sleep(1) # 1 second between messages - Use RSS over scraping: Google News RSS is official and stable. Scraping HTML pages is fragile and can break without warning.
- Test with workflow_dispatch first: Before relying on the cron schedule, trigger the workflow manually to confirm everything works.
- Monitor GitHub Actions logs: Go to the Actions tab in your repository to see the output of each run and debug any failures.
🏁 Final Result
You have now built a fully automated, serverless, free news bot that:
- Fetches fresh news from Google News RSS on any topic
- Posts formatted updates to your Telegram channel automatically
- Runs every hour using GitHub Actions at zero cost
- Tracks sent articles to prevent duplicate posts
This is one of the simplest yet most powerful automation systems you can build as a developer. You can expand it into a full News SaaS, alert system, or content automation engine.
Start small, run it for a week, then layer on the advanced features — your Telegram channel will grow on autopilot. 🔥
⭐ If you found this guide useful, consider starring the project on GitHub and sharing it with others:
https://github.com/aiocrafters/telegram-channel
Built with ❤️ by AIOCrafters
