A self-hosted Telegram bot for group chats.
Someone shares a video link, and the bot quietly replaces it with the actual video.
YouTube Β· Instagram Β· TikTok Β· VK Β· X / Twitter Β· Facebook Β· and many more
Install Β· How it works Β· Features Β· Configuration Β· Contributing
Without the bot, a group message often looks like this:
https://example.com/video/123456
With the bot, the same message becomes a normal Telegram video:
π¬ Native video
π Clickable link to the original source
π€ Name of the person who shared it
The group stays cleaner, videos are easier to watch, and nobody has to open a browser or use a separate download bot.
There is no need to forward links to another bot, wait for menus, choose formats, and send the result back.
Members simply post links as usual.
The bot does not fill the chat with messages like:
- βDownloadingβ¦β
- βPlease waitβ¦β
- βProcessingβ¦β
- βAn error occurredβ¦β
Instead, it uses reactions:
| Reaction | Meaning |
|---|---|
| π | The link is being processed |
| π | Instagram hid or restricted the content from the bot |
| π | The download failed |
| π | The video was posted, but the original link was kept |
If the link turns out to be an ordinary article or another page without video, the bot simply removes π and leaves the message untouched.
When everything succeeds, the original link can be removed automatically.
If the same video is shared more than once, the bot can reuse the copy already stored by Telegram.
That means:
- no second download;
- no second upload;
- less traffic;
- less waiting;
- lower VPS load.
If several people post the same video at the same time, the bot downloads it only once and delivers it to everyone who requested it.
A link posted in a topic is replaced with a video in that same topic. The bot does not move the conversation somewhere else.
You run the bot on your own VPS:
- your Telegram token stays on your server;
- your settings stay on your server;
- you control updates and limits;
- there is no third-party subscription;
- the project is open source.
This project is useful for:
- private groups of friends;
- Telegram communities;
- news and discussion groups;
- creator and moderation teams;
- groups where video links are shared frequently;
- self-hosters who do not want to depend on public downloader bots.
- A member posts a video link.
- The bot marks it with π.
- The video is downloaded and posted silently.
- The caption keeps a link to the original source and the sender's name.
- After a successful upload, the original link is removed when the bot has permission.
- If something fails, the original message remains available.
flowchart LR
A[Member posts a video link] --> B[Bot processes it quietly]
B --> C[Video appears in the same chat or topic]
C --> D[Original link is removed after success]
| Capability | Link Downloader Bot |
|---|---|
| Made specifically for Telegram groups | β |
Works without a /download command |
β |
| Does not spam the chat with progress messages | β |
| Keeps videos in the same forum topic | β |
| Remembers previously uploaded videos | β |
| Avoids duplicate simultaneous downloads | β |
| Can delete the original link only after success | β |
| Supports English and Russian | β |
| Runs on your own VPS | β |
| Includes Docker installation and safe updates | β |
The bot uses yt-dlp, which supports a large number of video websites.
For Telegram delivery, it prefers the highest-quality H.264 MP4 candidate that fits the configured size limit. The completed file is checked with ffprobe before upload, so an audio-only or incompatible partial download is never cached as a video.
Common examples:
- YouTube
- TikTok
- VK
- X / Twitter
Support for individual websites can change when those websites change their APIs or protection systems. The project includes an optional nightly yt-dlp updater to help keep extractors current.
Some websites may require cookies. DRM-protected content is not supported.
- a Debian or Ubuntu VPS;
- a Telegram bot token from @BotFather;
- permission to add the bot to your group.
Docker and other required packages can be installed automatically by the installer.
sudo git clone \
https://github.com/Avazbek22/LinkDownloaderBotForGroups.git \
/opt/linkdownloaderbot
sudo bash /opt/linkdownloaderbot/install.shThe installer asks for the Telegram bot token, builds the container, starts the bot, and prepares automatic updates when systemd is available.
To update an existing installation, run the same command again:
sudo bash /opt/linkdownloaderbot/install.shYour .env, settings, cache metadata, and logs are preserved.
Create a bot through @BotFather, then:
- Open Bot Settings.
- Open Group Privacy.
- Disable Group Privacy.
- Add the bot to your Telegram group.
- Grant Delete messages permission when you want original links removed.
No other administrator rights are required.
After startup, send:
/help
For normal use, members only need to post a supported link.
https://www.youtube.com/watch?v=...
No command is required.
| Command | What it does |
|---|---|
/start |
Show the introduction |
/help |
Show usage instructions |
/en |
Change the group language to English |
/ru |
Change the group language to Russian |
/settings |
Show group settings |
/delete_original on |
Delete processed links after success |
/delete_original off |
Keep original links |
Language and group settings can be changed only by group administrators.
A member can disable automatic downloads only for themselves:
@BotName me
or:
@BotName Ρ
After opting out, that member can still request a download manually:
@BotName https://example.com/video
Other members are not affected.
git clone https://github.com/Avazbek22/LinkDownloaderBotForGroups.git
cd LinkDownloaderBotForGroups
cp .env-example .env
nano .env
docker compose up -d --build
docker compose logs -f --tail=200Only BOT_TOKEN is required for a basic setup.
The default settings are suitable for a small private bot.
The most useful options are:
| Variable | Default | Purpose |
|---|---|---|
BOT_TOKEN |
required | Telegram bot token |
DEFAULT_LANGUAGE |
en |
Default language: en or ru |
DELETE_ORIGINAL |
true |
Remove links after successful delivery |
MAX_FILESIZE |
52428800 |
Maximum video size in bytes |
WORKERS |
2 |
Simultaneous downloads |
UPLOAD_WORKERS |
2 |
Simultaneous Telegram uploads |
MAX_QUEUE |
200 |
Number of waiting requests |
JOB_TIMEOUT_SECONDS |
900 |
Maximum processing time |
MEDIA_CACHE_ENABLED |
true |
Reuse recent and previously uploaded media |
STATUS_REACTIONS |
true |
Show π, π, π, and π reactions |
COOKIES_FILE |
empty | Optional cookies file for restricted websites |
LOG_LEVEL |
INFO |
Logging detail level |
See .env-example for all available settings.
For a low-traffic bot on a VPS with limited memory:
WORKERS=1
UPLOAD_WORKERS=1
MAX_QUEUE=30
YTDLP_CONCURRENT_FRAGMENTS=2
DISK_CACHE_MAX_FILES=3Advanced configuration
| Variable | Default | Purpose |
|---|---|---|
LOGS_CHAT_ID |
empty | Optional operator chat for critical notifications |
DISK_CACHE_MAX_FILES |
5 |
Maximum recent files kept on disk |
DISK_CACHE_TTL_SECONDS |
300 |
Lifetime of recent disk files |
FILE_ID_CACHE_MAX_ITEMS |
500 |
Maximum remembered Telegram media entries |
FILE_ID_CACHE_TTL_DAYS |
30 |
Lifetime of Telegram media entries |
YTDLP_CONCURRENT_FRAGMENTS |
4 |
Parallel download fragments |
YTDLP_JS_RUNTIMES |
node |
JavaScript runtime for yt-dlp |
YTDLP_REMOTE_COMPONENTS |
ejs:github |
Optional yt-dlp components |
YTDLP_INSTAGRAM_IMPERSONATE |
chrome |
Browser impersonation for Instagram |
YTDLP_INSTAGRAM_RETRIES |
8 |
Instagram request retries |
YTDLP_INSTAGRAM_FRAGMENT_RETRIES |
8 |
Instagram fragment retries |
YTDLP_INSTAGRAM_SOCKET_TIMEOUT |
30 |
Instagram timeout in seconds |
The bot tries to avoid repeated work at several levels:
- Equal links posted at the same time are grouped into one job.
- Different links that point to the same video are detected after metadata extraction.
- Recently downloaded files can be reused from the disk cache.
- Previously uploaded Telegram videos can be sent again using their
file_id.
This is especially useful in several groups or active communities, where the same popular video may be shared repeatedly.
The bot stores only the data needed to operate:
data/
βββ settings.json # group language and preferences
βββ users.json # personal opt-out choices
βββ state.json # welcome and migration state
βββ media_cache.json # reusable Telegram media references
βββ cache/ # temporary video files
Temporary media files are cleaned automatically.
Settings are written safely with temporary files and backups. If a JSON file becomes corrupted, the bot quarantines it and attempts to restore the last valid copy.
View container logs:
docker compose logs -f --tail=200Application logs are also written to:
logs/bot.log
They rotate daily. Old files are removed automatically after the retention period.
Sensitive URL query parameters are not written to logs.
Limit Docker log size
Add this to the service in docker-compose.yml:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"Video websites change frequently, so yt-dlp may need regular updates.
On systemd-based installations, the installer can enable:
- a nightly yt-dlp update;
- automatic application updates from the installation repository.
Updates are tested before the running bot is replaced. If the new version fails to start correctly, the previous version is restored.
Your token, settings, logs, and persistent data are not replaced.
Useful update commands
systemctl status linkdownloaderbotforgroups-yt-dlp-update.timer
sudo systemctl start \
linkdownloaderbotforgroups-yt-dlp-update.servicesystemctl status linkdownloaderbotforgroups-deploy.timer
sudo systemctl start \
linkdownloaderbotforgroups-deploy.serviceDisable automatic application updates:
sudo systemctl disable --now \
linkdownloaderbotforgroups-deploy.timerThe project rejects links that point to:
- localhost;
- private networks;
- loopback addresses;
- link-local addresses;
- non-public IP destinations;
- URLs containing usernames or passwords.
The Docker container runs with a read-only filesystem where possible and without additional privileges.
Secrets, cookies, downloaded media, and logs are excluded from Git.
For a public or untrusted deployment, host-level firewall rules are still recommended. Application checks reduce risk but cannot replace network isolation in every possible redirect or DNS-rebinding case.
Please report vulnerabilities according to SECURITY.md.
Disable Group Privacy in BotFather and restart the bot.
Grant the bot permission to delete messages, or use:
/delete_original off
Update yt-dlp and inspect the logs:
sudo systemctl start \
linkdownloaderbotforgroups-yt-dlp-update.service
docker compose logs --tail=200Some websites may require fresh cookies.
docker compose ps
docker compose logs --tail=200Check that .env contains a valid BOT_TOKEN.
Python 3.11 or newer is supported.
git clone https://github.com/Avazbek22/LinkDownloaderBotForGroups.git
cd LinkDownloaderBotForGroups
python -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements-dev.txt
python -m ruff check .
python -m ruff format --check .
python -m pytest
docker build -t linkdownloaderbotforgroups:test .Tests do not require a real Telegram token or live video websites.
Contributions are welcome.
Good contribution areas include:
- clearer documentation;
- new translations;
- better support for individual video websites;
- Telegram group and topic improvements;
- tests;
- deployment improvements;
- lower-resource operating modes;
- cache and queue improvements.
Before opening a pull request, read CONTRIBUTING.md.
For bugs and feature requests, use GitHub Issues.
Use this project only for content you are allowed to download and share.
The operator is responsible for complying with:
- website terms;
- copyright law;
- privacy rules;
- Telegram rules;
- local regulations.
This project does not bypass DRM and does not grant rights to third-party content.
Released under the MIT License.
A cleaner way to share videos in Telegram groups.
β Star the repository if the project is useful to you.