# Real-time tweet alerts in Discord, Telegram or Slack

> Get a message in Discord, Telegram or Slack within seconds of an X account posting. A small Python relay receives the tweet webhook, checks the signature and forwards it.

HTML page: https://www.twittrapi.com/blog/tweet-alerts-discord-telegram-slack
Published 2026-10-14.

You want a message in a Discord channel, a Telegram chat or Slack whenever certain X accounts post. This guide builds that with account monitoring and a relay of about 60 lines of Python. The relay receives each new tweet as a webhook, checks that it came from us and posts it to your chat.

Monitoring checks each account at least every 60 s, 5 s or 1 s, depending on the plan, so the alert arrives seconds after the tweet. The smallest plan watches 10 accounts for $5 a month.

## Step 1: Create the chat endpoint

Pick one, or set up all three:

- **Discord**: channel settings → Integrations → Webhooks → New Webhook → Copy Webhook URL.
- **Telegram**: create a bot with [@BotFather](https://t.me/BotFather) and copy its token. Add the bot to your group or channel and get the chat ID, for example by sending a message and opening `https://api.telegram.org/bot<token>/getUpdates`.
- **Slack**: create an app with an [incoming webhook](https://api.slack.com/messaging/webhooks) for the channel and copy the webhook URL.

Put the values in environment variables on the server that will run the relay:

```bash
export TWITTRAPI_WEBHOOK_SECRET="whsec_..."   # from step 3
export DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/..."
export TELEGRAM_BOT_TOKEN="123456:ABC..."
export TELEGRAM_CHAT_ID="-1001234567890"
export SLACK_WEBHOOK_URL="https://hooks.slack.com/services/..."
```

Leave out the ones you do not use.

## Step 2: Run the relay

The relay verifies the signature on the raw body, answers right away and forwards the tweet in a background thread, so a slow chat API never makes the webhook time out. Save it as `relay.py`:

```python
import hashlib
import hmac
import os
import threading
import time

import requests
from flask import Flask, abort, request

SECRET = os.environ["TWITTRAPI_WEBHOOK_SECRET"].encode()
app = Flask(__name__)

def verify(header: str, raw_body: bytes, tolerance: int = 300) -> bool:
    parts = dict(p.strip().split("=", 1) for p in header.split(",") if "=" in p)
    t, sig = parts.get("t", ""), parts.get("v1", "")
    if not t.isdigit() or not sig or abs(time.time() - int(t)) > tolerance:
        return False
    expected = hmac.new(SECRET, t.encode() + b"." + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, sig)

def forward(tweet: dict) -> None:
    text = f"@{tweet['author']['username']}: {tweet['text']}\n{tweet['url']}"
    if url := os.environ.get("DISCORD_WEBHOOK_URL"):
        requests.post(url, json={"content": text[:2000]}, timeout=10)
    if token := os.environ.get("TELEGRAM_BOT_TOKEN"):
        requests.post(
            f"https://api.telegram.org/bot{token}/sendMessage",
            json={"chat_id": os.environ["TELEGRAM_CHAT_ID"], "text": text[:4096]},
            timeout=10,
        )
    if url := os.environ.get("SLACK_WEBHOOK_URL"):
        requests.post(url, json={"text": text}, timeout=10)

@app.post("/hooks/twittrapi")
def hook():
    if not verify(request.headers.get("X-TwittrAPI-Signature", ""), request.get_data()):
        abort(401)
    event = request.get_json()
    if event["event"] == "tweet":
        threading.Thread(target=forward, args=(event["tweet"],), daemon=True).start()
    return "", 204
```

```bash
pip install flask requests
flask --app relay run --host 0.0.0.0 --port 8000
```

The relay must be reachable over `https` on a public address. Put it behind your existing web server, deploy it to any small host, or use a tunnel such as ngrok or Cloudflare Tunnel while you test.

Discord limits a message to 2,000 characters and Telegram to 4,096, which is why the text is cut. A tweet is shorter, but long posts on X can exceed both.

## Step 3: Point the webhook at the relay

Book a plan under **Monitors** in the dashboard, then add the accounts and set the webhook with your API key:

```python
import os
import requests

API = "https://api.twittrapi.com"
HEADERS = {"X-API-KEY": os.environ["TWITTRAPI_API_KEY"]}

requests.post(f"{API}/monitors/accounts", headers=HEADERS, json={"usernames": ["NASA", "SpaceX"]}, timeout=30)
r = requests.put(f"{API}/monitors/webhook", headers=HEADERS, json={"url": "https://relay.example.com/hooks/twittrapi"}, timeout=30)
print(r.json()["webhook"]["secret"])
```

Copy the printed `whsec_` secret into `TWITTRAPI_WEBHOOK_SECRET` on the relay and restart it.

## Step 4: Send a test event

```python
print(requests.post(f"{API}/monitors/webhook/test", headers=HEADERS, timeout=30).json())
```

The answer shows whether your relay accepted the event and how long it took. The test event has `"event": "test"`, so the relay above accepts it without posting to your chat. To see a real alert, wait for one of the accounts to post.

## Only the alerts you want

Every tweet of a watched account is sent, including replies and reposts. Filter in `forward` before sending:

```python
def wanted(tweet: dict) -> bool:
    if tweet.get("replyTo") or tweet.get("retweetOf"):
        return False  # original posts only
    return "launch" in tweet["text"].lower()
```

Call `if not wanted(tweet): return` at the top of `forward`. You can also route accounts to different channels by checking `tweet["author"]["username"]`.

## No server? Use n8n

With [n8n](https://www.twittrapi.com/docs/no-code) you can skip the Python. Create a workflow with a **Webhook** node as the trigger, use its production URL as your monitoring webhook, and connect a **Discord**, **Telegram** or **Slack** node that sends `{{ $json.body.tweet.url }}`. The Webhook node does not check our signature, so keep its URL secret.

## Frequently asked questions

### How fast do the alerts arrive?

Each account is checked at least every 60 s, 5 s or 1 s, depending on your plan. X's own delay before a tweet appears comes on top, plus a moment for the chat API. Each event carries `tweetCreatedAt` and `detectedAt`, so you can measure it.

### Can I get alerts for keywords instead of accounts?

Account monitoring follows accounts. For keywords, poll [search](https://www.twittrapi.com/blog/search-twitter-without-developer-account) with `since_id` on a schedule and send the results the same way.

### What happens when my relay is down?

Deliveries are retried for up to 24 hours, and events stay readable for 7 days through the pull API, as shown in the [webhook guide](https://www.twittrapi.com/blog/twitter-webhook-new-tweets#step-6-catch-up-after-downtime).

### Does this work for small accounts?

Yes. There is no follower minimum. An account with 50 followers is checked as often as one with 5 million.

## Sources

- [Account monitoring docs](https://www.twittrapi.com/docs/monitoring) (webhook, signature, retries, pull API)
- [Discord webhooks](https://support.discord.com/hc/en-us/articles/228383668), [Telegram Bot API sendMessage](https://core.telegram.org/bots/api#sendmessage), [Slack incoming webhooks](https://api.slack.com/messaging/webhooks)

TwittrAPI is not affiliated with X Corp. It reads only public data.
