Keyword check — это дополнительная проверка для HTTP-мониторов: помимо стандартного контроля статус-кода Tracker.ru ищет в теле ответа заданную подстроку и считает URL рабочим только тогда, когда подстрока найдена. Если страница вернула 200 OK, но ожидаемое слово исчезло — URL переходит в down и срабатывают уведомления.
Это закрывает целый класс инцидентов, при которых сервер технически жив, а контент сломан: пустой шаблон, белая страница после деплоя, страница-заглушка от reverse-proxy, дефейс или неработающая фича-флаговая панель. Без keyword-check такие случаи проходят мимо HTTP-мониторинга молча.
Когда нужен keyword check
- Anti-deface. Подстрока — фрагмент уникального текста, который должен быть на сайте всегда (например, копирайт в подвале). Если злоумышленник заменил главную страницу — keyword не найден, алерт уходит.
- SLO для feature-flag. Страница содержит маркер вида
Feature: enabled. Когда фича-флаг сломался и страница возвращает200, но без маркера — мониторинг ловит регрессию. - Контроль шаблона при
200. Кеш отдал устаревший HTML, фронт сломан, но статус всё равно 200 — keyword из ожидаемого блока (имя пользователя, нав-меню, конкретный заголовок) сразу скажет, что что-то не так. - Статус-страница. На публичной status-page обычно есть фраза вроде «All systems operational». Keyword-check по этой фразе превращает её в монитор «всё ли в порядке».
- Маркер версии деплоя. Footer или meta-тег с номером версии (
v1.42.0). Если deploy проехал мимо — версия не обновилась — алерт.
Как настроить
В форме редактирования URL заполните поле «Ожидаемое ключевое слово» (expected_keyword). Можно ввести любую подстроку до 255 символов: фразу, фрагмент HTML-разметки, текст из футера, имя класса CSS — что угодно, что точно встречается на ожидаемой странице.
Через API:
curl -X POST https://tracker.ru/api/v1/urls \
-H "Authorization: Bearer <api_token>" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/status",
"monitor_type": "http",
"period": 60,
"expected_keyword": "All systems operational"
}'
Лимит длины — 255 символов (max:255 в StoreUrlRequest). Этого достаточно для уникального фрагмента; не пытайтесь засунуть туда весь HTML страницы — храните минимально-достаточную подстроку, которую ваш фронтенд гарантирует выводить на работающей версии.
Логика срабатывания
Каждая HTTP-проверка с заданным expected_keyword отрабатывает по схеме:
- Чекер делает HTTP-запрос.
- Получает ответ, читает тело (с учётом ограничений ниже).
- Ищет подстроку в теле — case-insensitive substring match.
- Если подстрока не найдена — взводит флаг
keyword_not_found = true, ставит результатOk = false, ошибка:Expected keyword not found: <keyword>. URL переходит вdown. - Когда подстрока появляется обратно —
keyword_not_foundсбрасывается, URL восстанавливается, отправляется уведомление о восстановлении.
В таблице check_log сохраняется флаг keyword_not_found для каждой проверки — это позволяет в журнале URL отличать «упало по статусу» от «упало по keyword».
Технические нюансы
- Auto-switch HEAD → GET. По умолчанию Tracker.ru использует HTTP-метод
HEAD— он быстрее и дешевле для проверяемого сайта. Но HEAD-ответ не содержит body, и keyword там искать нечего. Поэтому если заданexpected_keyword, чекер автоматически переключает метод наGET(http_checker.go:108-110). Никаких настроек на стороне пользователя для этого не нужно. Если в форме явно выбранHEAD— он будет проигнорирован и заменён наGETдля этого URL. - Case-insensitive. Поиск нечувствителен к регистру. Обе стороны — keyword и тело ответа — приводятся к нижнему регистру через
strings.ToLower(http_checker.go:168). То естьOperational,operational,OPERATIONAL— это одно и то же. Удобно: не ломается от случайной правки шаблона, в которой поменяли регистр заголовка. - Plain substring, не regex. Значение поля — обычная строка. Никаких метасимволов, групп, якорей. Ищется буквальное вхождение подстроки. Если нужен regex — keyword-check вам не подходит, посмотрите в сторону кастомных webhook-чекеров или health-эндпоинта.
- Лимит body 1 MB. Чекер читает тело через
io.LimitReader(resp.Body, 1<<20)— то есть только первый мегабайт ответа (http_checker.go:164). Поиск keyword идёт только в этом мегабайте. Если ваш HTML больше 1 MB — поместите ожидаемое слово ближе к началу страницы (в<head>или сразу после<body>), иначе оно окажется за лимитом и URL будет постоянно отдавать ложныйkeyword_not_foundалерт. На практике 1 MB — это очень много для одной страницы, проблема возникает редко. - UTF-8. Кириллица, китайские иероглифы, эмодзи в keyword поддерживаются — оба сравниваемых байтовых потока обрабатываются как строки в UTF-8. Laravel-валидатор
max:255используетmb_strlen— лимит измеряется в символах (включая многобайтовые), а не в байтах. Для большинства практических сценариев 255 символов достаточно. - Совместимость с TCP-мониторингом. Поле
expected_keywordдоступно только дляmonitor_type=http. Для TCP-чеков оно игнорируется — у TCP нет body, искать негде. Подробнее в /docs/features/tcp-monitoring.
Уведомления
Когда keyword пропадает, в выбранные каналы уходит уведомление с явным указанием причины — оно отличается от обычного «status 5xx» алерта:
Сайт недоступен! https://example.com/status
Ошибка: Ключевое слово не найдено
Ожидалось: "All systems operational"
Недоступен с 2026-05-01 19:15:09
В webhook-payload поле error_status принимает значение keyword_not_found — это удобно для разделения incident-флоу: keyword-падения часто требуют другого типа реакции, чем 5xx (например, дёрнуть фронтенд-команду, а не SRE).
При восстановлении (keyword вернулся в ответ) приходит обычное сообщение о recovery с указанием длительности downtime.
Связанные статьи
- /docs/features/tcp-monitoring — TCP-мониторинг для портов без HTTP.
- /docs/features/maintenance-windows — окна обслуживания: заглушение keyword-алертов на плановое ТО.
- /docs/notifications/telegram — настройка Telegram-уведомлений.
- /docs/notifications/webhooks — Webhook с подписью HMAC-SHA256.