Упоминания в Discord Webhook — allowed_mentions, @everyone, роли, пользователи
Контролируйте, кого пингует ваш Discord webhook. Освойте allowed_mentions для безопасного пинга пользователей, ролей и @everyone — на Python, JavaScript и curl.
По умолчанию Discord webhook пингует всех, кого упомянул в content. Звучит разумно — пока ваш мониторинг случайно не пингует @everyone 50 000 пользователей сервера, потому что в тексте алерта была подстрока <@&>. Решение — allowed_mentions, маленький, но критичный кусок payload’а.
В гайде — что делает allowed_mentions, как ведут себя режимы и паттерны безопасного пинга на Python, JavaScript и curl.
Что контролирует allowed_mentions
Когда Discord парсит content на упоминания вида <@123>, <@&456> или @everyone, он может:
- Отрисовать как текст (без уведомления, без подсветки)
- Реально пингануть пользователя/роль/everyone
allowed_mentions говорит, какие упоминания в сообщении могут пинговать. Всё, что не в списке — становится текстом.
Поведение по умолчанию (ОПАСНО)
Если allowed_mentions не указан:
{ "content": "<@&123456789> деплой упал" }
Discord пингует роль. И если в content где-то есть @everyone, тоже пингует. Самая частая причина «упс, мой CI разбудил весь сервер в 3 ночи».
Безопасный default: не пинговать никого
Самый безопасный паттерн — отключить все пинги, если не разрешены явно:
{
"content": "Server warning <@&999>",
"allowed_mentions": { "parse": [] }
}
parse: [] = «не парсить никакие упоминания». Роль рендерится как кликабельное имя, но уведомление не приходит.
Массив parse
parse принимает до трёх значений: "users", "roles", "everyone".
{
"content": "Hey @everyone, deploy is live",
"allowed_mentions": { "parse": ["everyone"] }
}
Это пингует @everyone (и @here). ["users"] пингует все user-упоминания, но не роли, и т. д.
Пинг конкретных пользователей
parse — топорный инструмент. Для точечных пингов — users со списком ID, без users в parse:
{
"content": "<@111> <@222> review please",
"allowed_mentions": {
"parse": [],
"users": ["111"]
}
}
Пингуется только 111. 222 показан как кликабельное упоминание, но без уведомления.
Важно:
"users"вparseИusers: ["111"]одновременно — Discord вернёт 400. Они взаимоисключающие — на один вызов выбирайте один подход.
Пинг конкретных ролей
То же для ролей:
{
"content": "<@&100> <@&200> on call!",
"allowed_mentions": {
"parse": [],
"roles": ["100"]
}
}
Уведомление получит только роль 100.
Python — хелпер
import requests
WEBHOOK_URL = "https://discord.com/api/webhooks/ID/TOKEN"
def send(content: str, ping_users=None, ping_roles=None, ping_everyone=False):
"""Отправка с явными правилами упоминаний."""
parse = []
payload = {"content": content, "allowed_mentions": {"parse": parse}}
if ping_everyone:
parse.append("everyone")
if ping_users:
payload["allowed_mentions"]["users"] = [str(u) for u in ping_users]
if ping_roles:
payload["allowed_mentions"]["roles"] = [str(r) for r in ping_roles]
r = requests.post(WEBHOOK_URL, json=payload, timeout=10)
r.raise_for_status()
# Примеры
send("Daily report posted", ) # Без пингов
send("<@123> code review please", ping_users=[123]) # Один юзер
send("<@&999> incident!", ping_roles=[999]) # Одна роль
send("@everyone maintenance window", ping_everyone=True) # Аккуратно!
«Не пинговать никого» становится default’ом, и нужно явно opt-in.
JavaScript — тот же паттерн
async function send(content, { users = [], roles = [], everyone = false } = {}) {
const allowed_mentions = { parse: [] };
if (everyone) allowed_mentions.parse.push('everyone');
if (users.length) allowed_mentions.users = users.map(String);
if (roles.length) allowed_mentions.roles = roles.map(String);
const res = await fetch(process.env.WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ content, allowed_mentions }),
});
if (!res.ok) throw new Error(`Send failed: ${res.status}`);
}
await send('<@&999> incident!', { roles: ['999'] });
curl
curl -H 'Content-Type: application/json' \
-d '{
"content": "<@123> review please",
"allowed_mentions": { "parse": [], "users": ["123"] }
}' \
https://discord.com/api/webhooks/ID/TOKEN
Шпаргалка по синтаксису
| Цель | Формат в content |
|---|---|
| Упомянуть пользователя | <@USER_ID> |
| Упомянуть роль | <@&ROLE_ID> |
| Упомянуть @everyone | @everyone |
| Упомянуть @here | @here |
| Ссылка на канал | <#CHANNEL_ID> |
User и role ID — числа из 17–19 цифр. ПКМ по пользователю/роли с Developer Mode → «Copy ID».
Флаг replied_user
Если webhook отвечает на сообщение через message_reference, replied_user контролирует, пинговать ли автора оригинала:
{
"content": "Got it",
"message_reference": { "message_id": "1234" },
"allowed_mentions": { "replied_user": false }
}
В большинстве автоматизаций ставьте replied_user: false, если не хотите явно дёргать автора.
Лимиты
- Максимум 100 user ID в
users - Максимум 100 role ID в
roles - ID должны быть строками в JSON (Discord ID — 64-битные, JS-числа теряют точность)
parseиusers/rolesне должны пересекаться (400)
Паттерны защиты от ошибок
Паттерн 1: allowlist ID ролей. Хардкод небольшого набора ролей, которые webhook’у разрешено пинговать.
ALLOWED_ROLES = {"on-call-eng", "ops-lead"}
ROLE_IDS = {"on-call-eng": "111", "ops-lead": "222"}
def page(role_name: str, message: str):
if role_name not in ALLOWED_ROLES:
raise ValueError(f"Пинг '{role_name}' запрещён из этого webhook")
rid = ROLE_IDS[role_name]
send(f"<@&{rid}> {message}", ping_roles=[rid])
Паттерн 2: фильтр @everyone из пользовательского ввода. Если webhook ретранслирует чужой текст:
import re
def safe(text: str) -> str:
text = text.replace("@everyone", "@\u200beveryone")
text = text.replace("@here", "@\u200bhere")
return re.sub(r"<@&?\d+>", lambda m: m.group(0).replace("<", "<\u200b"), text)
Zero-width space ломает парсер упоминаний, не меняя текст визуально.
Паттерн 3: dry-run. На тестах в проде форсировать allowed_mentions: { parse: [] } независимо от вызова. Спасает от ошибки в 3 ночи.
Частые ошибки
| Ошибка | Причина |
|---|---|
400 allowed_mentions: cannot have both parse and users/roles | "users" в parse И заполнен массив users |
| Упоминание видно, уведомления нет | Норма при parse: [] и ID не в списке |
@everyone пингует даже с безопасным конфигом | У роли webhook’а нет права mention_everyone — Discord тут запрещает |
Проверьте в конструкторе
Конструктор Discord Webhook визуально отображает allowed_mentions — переключатели «Ping users», «Ping roles», «Ping @everyone» до отправки, чтобы видеть, какие уведомления уйдут. Полезно для уведомлений и автоматизации.
Источники
- Discord docs: Allowed Mentions Object
- Discord docs: Message Formatting
Попробуйте в нашем инструменте
Открыть конструктор Discord Webhook