Get instant push notifications on your phone when monitored URLs go down or recover.
Why Telegram?
- Free, no subscription required
- Instant push notifications
- Works on mobile and desktop
- No server-side setup needed
- Supports rich message formatting
Requirements:
- Telegram account (mobile or desktop app)
- WebStatusπ with webhook alerts enabled
- Internet connection from your Raspberry Pi
- Open Telegram and search for @BotFather
- Start a chat and send
/newbot - Choose a display name (e.g., "My Server Monitor")
- Choose a username ending in
bot(e.g.,myserver_monitor_bot) - Copy the bot token - it looks like:
123456789:ABCdefGHIjklMNOpqrsTUVwxyz
BotFather response:
Done! Congratulations on your new bot. You will find it at t.me/myserver_monitor_bot.
Use this token to access the HTTP API:
123456789:ABCdefGHIjklMNOpqrsTUVwxyz
Keep this token secret! Anyone with it can control your bot.
- Open a chat with your new bot (search for
@your_bot_username) - Send any message (e.g., "hello")
- Open this URL in your browser (replace
YOUR_TOKEN):https://api.telegram.org/botYOUR_TOKEN/getUpdates - Find your chat ID in the response:
Your chat ID is
{"ok":true,"result":[{"message":{"chat":{"id":123456789}}}]}123456789(a positive number)
- Create a Telegram group or use an existing one
- Add your bot to the group
- Send a message in the group
- Use the
getUpdatesURL above - Find the group chat ID (negative number, e.g.,
-100123456789)
WebStatusπ sends a generic JSON payload that isn't directly compatible with Telegram's API. You need a relay service to transform the payload.
Pipedream offers a free tier perfect for this use case.
- Create a free account at https://pipedream.com
- Create a new workflow with HTTP trigger
- Copy the webhook URL (e.g.,
https://eo1234abc.m.pipedream.net) - Add a Node.js code step with this code:
export default defineComponent({
async run({ steps }) {
const event = steps.trigger.event.body;
// Format the message
const isDown = event.event === "url_down";
const emoji = isDown ? "🔴" : "🟢";
const status = isDown ? "DOWN" : "UP";
const message = `${emoji} *${event.url.name}* is ${status}
URL: ${event.url.url}
Status Code: ${event.status.code || "N/A"}
Response Time: ${event.status.response_time_ms}ms
Time: ${new Date(event.status.timestamp).toLocaleString()}`;
// Send to Telegram
const TELEGRAM_TOKEN = "YOUR_BOT_TOKEN";
const CHAT_ID = "YOUR_CHAT_ID";
const response = await fetch(
`https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
chat_id: CHAT_ID,
text: message,
parse_mode: "Markdown"
})
}
);
return await response.json();
}
});- Replace
YOUR_BOT_TOKENandYOUR_CHAT_IDwith your values - Deploy the workflow
If you prefer self-hosting, n8n is a great option.
- Install n8n on your server or use n8n cloud
- Create a workflow:
- Webhook trigger node
- Telegram node (send message)
- Configure the Telegram node with your bot token
- Use expressions to format the message from the webhook data
- Copy the webhook URL
- Create a free account at https://make.com
- Create a new scenario with Webhooks → Custom webhook
- Add Telegram Bot → Send a Text Message
- Map the fields from the webhook to the Telegram message
- Copy the webhook URL
Add the relay webhook URL to your config.yaml:
alerts:
webhooks:
- url: "https://eo1234abc.m.pipedream.net" # Your Pipedream/n8n URL
enabled: true
on_failure: true # Alert when URL goes DOWN
on_recovery: true # Alert when URL comes back UP
cooldown_seconds: 300 # 5 minutes between alerts per URLwebstatuspi test-alertYou should receive a test notification in Telegram within seconds.
Telegram supports Markdown formatting in messages:
| Format | Syntax | Result |
|---|---|---|
| Bold | *text* |
text |
| Italic | _text_ |
text |
| Code | `code` |
code |
| Link | [text](url) |
text |
Example formatted alert:
🔴 *APP_PROD* is DOWN
URL: https://api.example.com
Status Code: 503
Response Time: 5000ms
Time: 1/21/2026, 10:30:15 AM
- Did you start a conversation? You must send at least one message to the bot first
- Is the token correct? Check for typos or extra spaces
- Test the bot directly:
Should return bot info, not an error
curl "https://api.telegram.org/botYOUR_TOKEN/getMe"
| ID Type | Format | Example |
|---|---|---|
| Personal | Positive number | 123456789 |
| Group | Negative number | -123456789 |
| Supergroup/Channel | Starts with -100 |
-1001234567890 |
- Check the relay service logs (Pipedream, n8n, etc.)
- Verify WebStatusπ is sending webhooks:
webstatuspi test-alert --verbose
- Test Telegram API directly:
curl -X POST "https://api.telegram.org/botYOUR_TOKEN/sendMessage" \ -H "Content-Type: application/json" \ -d '{"chat_id": "YOUR_CHAT_ID", "text": "Test message"}'
If you remove the bot from a group, you need to:
- Add the bot back to the group
- Get the new chat ID (it may change)
- Update your relay configuration
Telegram limits bots to ~30 messages per second. If monitoring many URLs that fail simultaneously, alerts may be delayed. Consider:
- Increasing
cooldown_secondsto reduce alert frequency - Using a group chat for multiple administrators
- Never commit bot tokens to version control
- Use environment variables in your relay service for sensitive values
- Restrict bot permissions - Telegram bots can only read messages sent to them directly
- Monitor relay service logs for unusual activity
alerts:
webhooks:
- url: "https://your-relay-service.com/webhook"
enabled: truealerts:
webhooks:
# Primary: Telegram via Pipedream
- url: "https://eo1234abc.m.pipedream.net"
enabled: true
on_failure: true
on_recovery: true
cooldown_seconds: 300
# Backup: Slack for redundancy
- url: "https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK"
enabled: true
on_failure: true
on_recovery: false # Only critical alerts to Slack
cooldown_seconds: 600WebStatusπ sends this JSON structure to your relay service:
{
"event": "url_down",
"url": {
"name": "API_PROD",
"url": "https://api.example.com"
},
"status": {
"code": 503,
"success": false,
"response_time_ms": 5000,
"error": "Service Unavailable",
"timestamp": "2026-01-21T10:30:00Z"
},
"previous_status": "up"
}| Field | Description |
|---|---|
event |
Either url_down, url_up, or test |
url.name |
The URL's configured name |
url.url |
The full URL being monitored |
status.code |
HTTP status code (null if connection failed) |
status.success |
Boolean indicating if check passed |
status.response_time_ms |
Response time in milliseconds |
status.error |
Error message if failed |
status.timestamp |
ISO 8601 timestamp |
previous_status |
up, down, or null (first check) |
- Webhook Alerts - General webhook configuration
- Troubleshooting - General troubleshooting guide
- Architecture - System design and alert flow