# TradingView Webhook Bot: a Flask endpoint that fans one alert out to five channels

> fabston/TradingView-Webhook-Bot is a MIT Python service that receives TradingView webhook alerts over Flask and relays them to Telegram, Discord, Slack, Twitter or email. Its design is one JSON payload with a shared secret and optional per-alert channel overrides, and its pinned 2021 dependency set is the part most likely to hurt you.

**fabston/TradingView-Webhook-Bot** — 📊 Send TradingView alerts to Telegram, Discord, Slack, Twitter and Email. 

- Repository: https://github.com/fabston/TradingView-Webhook-Bot
- Stars: 1,898 · Forks: 508
- Language: Python
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/fabston-tradingview-webhook-bot

## One webhook in, several chat channels out

The bot listens for TradingView alerts through webhooks using Flask, and forwards them to Telegram, Discord, Twitter and email. That is the whole product, and the code fits in a handful of files: `main.py`, `handler.py`, `config.py`, `requirements.txt`, a `Dockerfile` and a `docker-compose.yml`.

What makes it more than a script is the channel design. Each destination has its own client library and its own credential: Telegram goes through python-telegram-bot, Discord and Slack through their webhook libraries, Twitter through tweepy, and email through `smtplib` from the standard library.

Two details make it usable rather than merely demonstrative. Channels can be enabled or disabled individually in `config.py`, and alerts can be routed dynamically to different Telegram and Discord channels per alert, so one deployment can serve several symbols or several accounts.

TradingView's own template variables are substituted, so `{{close}}`, `{{exchange}}` and the rest resolve in the message body. That is what connects a chart alert to a readable notification rather than a generic ping.

## The alert payload and the key that gates it

The alert is a JSON body posted to `http://<YOUR-IP>/webhook`, and the README's example shows the shape:

```json
{
 "key": "9T2q394M92",
 "telegram": "-1001277977502",
 "discord": "789842341870960670/BFeBBrCt-w2Z9RJ2wlH6TWUjM5bJuC29aJaJ5OQv9sE6zCKY_AlOxxFwRURkgEl852s3",
 "slack": "T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX",
 "msg": "Long *#{{ticker}}* at `{{close}}`"
}
```

`key` is the only mandatory field, and the README is explicit about why: it has to match `sec_key` in `config.py`, and it is described as an extra security measure to ensure nobody else is executing your alerts.

The channel fields are optional and fall back to the settings in `config.py` when absent, which is what makes the dynamic routing work: an alert that names a Telegram chat overrides the default, and an alert that names none uses whatever you configured globally.

`msg` accepts Markdown for Telegram and Discord.

That single shared secret is the whole access control story, and it deserves a hard look. There is no rate limiting, no per-source allowlist and no signature over the body. Anyone who learns or guesses `key` can post alerts that will be delivered to your channels, and a webhook endpoint on a public IP is discoverable by port scanning.

## Running it directly on a VPS, in five commands

The README's installation path assumes a Linux host and a virtual environment:

```bash
git clone https://github.com/fabston/TradingView-Webhook-Bot.git
cd TradingView-Webhook-Bot
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```

For a local test, edit `config.py`, set up the alert and start the process with `python main.py`. For deployment, use a production WSGI server and an HTTPS reverse proxy, restrict access and use a strong unique webhook key. The README suggests PM2 for running it in the background or on system boot.

Notice that the Flask development server is what `main.py` runs. That matters for anything internet facing, and it is why the README has a section on forwarding port 80 to 8080 with NGINX, on the stated recommendation to run Flask on a different port such as 8080 and proxy to it:

```nginx
server {
    listen 80;

    server_name <YOUR-IP>;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
```

Installing it is `sudo apt-get install nginx`, editing `/etc/nginx/sites-enabled/tv_webhook`, and restarting with `sudo service nginx restart`.

The example configuration terminates TLS nowhere. It is not suitable for transmitting the webhook secret over the public internet: configure HTTPS with a valid certificate and restrict the endpoint before use. Flask explicitly advises against its development server in production.

## The Docker path maps port 80 directly, which is the whole difference

The Docker route is three commands:

```bash
git clone https://github.com/fabston/TradingView-Webhook-Bot.git
cd TradingView-Webhook-Bot
docker-compose build
docker-compose up
```

with `config.py` edited first. The `Dockerfile` builds on `python:3.9-alpine`, installs build dependencies with `apk add gcc python3-dev openssl-dev musl-dev libffi-dev`, installs `requirements.txt` with `pip install --no-cache-dir`, copies `main.py`, `handler.py` and `config.py`, exposes port 80 and starts `python main.py`.

`docker-compose.yml` builds from the local directory, names the container `tradingview-webhook-bot`, maps `'80:80'` and sets `restart: unless-stopped`.

Two observations follow. The container publishes port 80 directly with no NGINX in front, so if you follow this path you are exposing the Flask server to the internet without the reverse proxy the other path recommends. And the compose file has no volume, no environment section and no secrets mechanism, so `config.py` is baked into the image at build time, which means rotating a channel token requires a rebuild rather than a restart.

## A 2021 dependency set, and what that means for a service you leave running

The requirements file is fully pinned, with `==` on every entry, and the versions are old. `Flask==2.0.1`, `Werkzeug==2.0.1`, `Jinja2==3.0.1`, `MarkupSafe==2.0.1`, `requests==2.25.1`, `urllib3==1.26.5`, `certifi==2021.5.30`, `python-telegram-bot==13.6`, `tweepy==3.10.0`, `discord-webhook==0.14.0` and `slack-webhook==1.0.6`. Development tools are pinned alongside them: `black==21.5b1`, `flake8==3.9.2` and `isort==5.8.0`.

`APScheduler==3.6.3` and `tornado==6.1` are present as well, along with `waitress==2.1.1`, which is a production WSGI server for Python, so the dependencies are broader than the runtime path alone requires.

Pinning is the right instinct for a service, and it cuts both ways here. You get a reproducible install, but you get it at versions selected in 2021, with no security updates arriving because the file pins them. The repository is not archived and the last push was on 2026-10-01, so work is happening, but there are no GitHub releases at all, which means there is no version marker to track and upgrading means reading the file.

A team deploying this should expect to bump these pins itself, which in practice means becoming the maintainer of a small Python service rather than consuming one.

## Conclusion

TradingView Webhook Bot fits an individual trader who wants a TradingView alert to land in Telegram or Discord within seconds and is willing to run a small Flask process on a VPS. It does not fit a team that cannot accept a 2021 dependency set in production, because `requirements.txt` pins Flask 2.0.1 and python-telegram-bot 13.6, and it does not fit anyone who needs authentication beyond the single `key` check. Verify first that `pip install -r requirements.txt` resolves on your Python, that the `key` in your alert matches `sec_key` in `config.py`, and that the endpoint is behind TLS before you point TradingView at `http://<YOUR-IP>/webhook`.

## FAQ

### How do I set up TradingView Webhook Bot?

Clone the repository, create and activate a virtual environment, run `pip install -r requirements.txt`, edit `config.py`, set the TradingView alert webhook to `http://<YOUR-IP>/webhook`, open the port if needed, then start it with `python main.py`.

### Which channels does TradingView Webhook Bot support?

Telegram via python-telegram-bot, Discord and Slack via their webhook libraries, Twitter via tweepy, and email via smtplib. Channels can be enabled or disabled in config.py.

### What does the key field in the TradingView alert do?

It is mandatory and has to match `sec_key` in config.py. The README describes it as an extra security measure to ensure nobody else is executing your alerts.

### Can I run TradingView Webhook Bot with Docker?

Yes. Edit config.py, then run `docker-compose build` and `docker-compose up`. The compose file maps port 80 to the container and sets `restart: unless-stopped`, with no volume or environment section.

### Does the bot support TradingView template variables?

Yes. Variables such as `{{close}}`, `{{exchange}}` and `{{ticker}}` are substituted in the message, so an alert message like "Long *#{{ticker}}* at `{{close}}`" renders with the chart's values.

### Can one alert go to a different Telegram or Discord channel each time?

Yes. The README lists dynamic sending to different Telegram and/or Discord channels as a feature, with per-alert channel fields that fall back to config.py when they are not set.

## Sources

- [fabston/TradingView-Webhook-Bot on GitHub](https://github.com/fabston/TradingView-Webhook-Bot)
- [Issues](https://github.com/fabston/TradingView-Webhook-Bot/issues)
- [License: MIT](https://github.com/fabston/TradingView-Webhook-Bot/blob/master/LICENSE)
- [README](https://github.com/fabston/TradingView-Webhook-Bot/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/fabston-tradingview-webhook-bot
