SEO и контент

IndexNow на практике: как быстро сообщать Яндексу о новых и изменённых страницах

Представим динамический сайт с редакционной системой.

В 10:00 редактор публикует новую статью:

https://example.ru/expert/webhook-security

Сайт уже сделал всё необходимое:

HTTP 200
TITLE
H1
self-canonical
Article JSON-LD
sitemap.xml
внутренняя ссылка из /expert

Для пользователя страница появилась мгновенно.

Но поисковая система работает независимо.

Она должна:

узнать о новом URL
↓
запланировать обход
↓
получить страницу
↓
проанализировать её
↓
принять решение об индексации

Если просто ждать очередного обхода сайта, между публикацией и обнаружением изменения может пройти некоторое время.

Для динамического сайта, где регулярно появляются:

новые статьи;
обновлённые услуги;
изменённые карточки;
новые кейсы;
удалённые страницы;

возникает логичный вопрос:

Можно ли самим сообщать поисковой системе, что конкретный URL только что изменился?

Да.

Для этого существует протокол IndexNow.

Яндекс официально поддерживает IndexNow и позволяет автоматически уведомлять его о новых, изменённых и удалённых страницах, не ожидая, пока робот самостоятельно обнаружит изменение при очередном обходе. При этом Яндекс отдельно подчёркивает: отправка URL через IndexNow не гарантирует его включение в индекс.

Это принципиально важно.

IndexNow — не:

«добавить страницу в Яндекс»

а:

«сообщить Яндексу:
этот URL изменился,
обратите на него внимание»

И если воспринимать протокол именно так, он очень хорошо встраивается в современную редакционную систему.


Что решает IndexNow

У поискового робота традиционно есть несколько способов обнаружить изменение сайта.

Например:

внутренняя ссылка;
sitemap.xml;
повторный crawl известной страницы;
ручная отправка на переобход;
другие сигналы.

IndexNow добавляет ещё один канал:

Сайт
↓
сам сообщает:
URL изменился
↓
поисковая система получает сигнал

То есть модель меняется с полностью pull-подхода:

поисковик когда-нибудь
сам проверит страницу

на комбинацию:

crawler
+
активное уведомление сайта.

Яндекс рекомендует сочетать подходящие способы уведомления об изменениях — Sitemap, переобход, IndexNow и другие доступные механизмы, а не рассматривать их как взаимоисключающие технологии.


IndexNow не заменяет Sitemap

Это одна из самых важных практических границ.

Sitemap отвечает на вопрос:

Какие канонические публичные страницы составляют наш сайт?

IndexNow:

Какие конкретные страницы только что добавились, изменились или были удалены?

Например Sitemap содержит:

/
/prices
/services
/expert/article-a
/expert/article-b
/expert/article-c

и отражает текущее состояние сайта.

В 14:37 изменяется:

/expert/article-b

Нет смысла заново сообщать поисковику:

вот весь сайт.

Можно отправить:

/expert/article-b

через IndexNow.

Яндекс прямо рекомендует через IndexNow передавать новые, изменённые или удалённые страницы, а не использовать протокол для периодической массовой отправки всех URL сайта. Для полного представления структуры сайта остаётся Sitemap.

Получается полезное разделение:

Sitemap
=
состояние сайта

IndexNow
=
события изменения сайта

Это почти snapshot и event

Если смотреть на архитектуру как разработчик:

sitemap.xml

похож на snapshot:

Вот актуальный набор наших индексируемых страниц.

А:

IndexNow

на event:

URL X только что изменился.

Это хорошая модель для динамического продукта.


Когда отправлять URL через IndexNow

Первый очевидный случай — новая публикация.

Статья переходит:

DRAFT
↓
PUBLISHED

и впервые становится:

public;
HTTP 200;
indexable;
self-canonical.

После успешной публикации можно сформировать событие:

INDEXNOW_SUBMIT
url=https://example.ru/expert/article
reason=published

Второй случай — существенное изменение страницы

Например статья уже существует, но редактор:

добавил большой новый раздел;
обновил устаревшие данные;
изменил основной текст;
существенно переработал структуру;
изменил важные SEO-данные.

Теперь есть смысл сообщить:

Эта известная вам страница изменилась.

Но не нужно отправлять IndexNow после каждого UPDATE в базе

Например произошло:

view_count += 1

Публичный текст статьи не изменился существенно.

Или:

admin_last_opened_at = now()

Вообще не связано с публичной страницей.

Или:

internal_note = ...

Пользователь этого даже не видит.

Если IndexNow привязан просто к:

row.updated_at changed

система начнёт генерировать огромное количество бессмысленных уведомлений.


Лучше иметь понятие public change

Например:

content_revision

или:

public_updated_at

изменяется только когда модифицирована публичная версия документа.

Тогда правило становится:

public content changed
→ IndexNow event

а не:

любой SQL UPDATE
→ IndexNow.

Третий случай — удаление страницы

Допустим материал:

/expert/old-api

удалён без замены.

Теперь сервер отвечает:

410 Gone

или:

404 Not Found

IndexNow можно использовать и для сообщения о таком изменении.

Яндекс прямо разрешает передавать через IndexNow страницы, которые теперь возвращают 404 или 410.

То есть событие:

PUBLISHED
↓
DELETED

тоже может автоматически создавать IndexNow notification.


Четвёртый случай — URL переехал

Было:

/expert/old-url

Стало:

/expert/new-url

Старый URL:

301 → /expert/new-url

Новый:

200 OK

В такой ситуации полезно сообщить об изменении соответствующих адресов.

Яндекс допускает отправку через IndexNow URL, которые теперь возвращают 301 или 302, то есть протокол можно использовать и для уведомления об изменившейся redirect-семантике страницы.

При этом сам SEO-lifecycle всё равно должен быть правильным:

old
→ 301 new

new
→ 200
→ self-canonical

sitemap
→ new only

IndexNow это дополняет, а не заменяет.


Что не стоит отправлять

Представим страницу:

/admin/articles

Она изменилась.

Это не означает, что её нужно отправлять Яндексу.


Внутренний search:

/search?q=crm

сгенерировал новый результат.

Тоже не обязательно поисковое событие.


Появилась временная preview-страница:

/preview/article/1842

Если она не предназначена для organic search, IndexNow ей не нужен.


Поэтому перед созданием notification полезно сначала проверить:

Это публичный URL?

и уже затем:

Какое именно SEO-событие произошло?

IndexNow должен идти после публикации, а не перед ней

Это важная инженерная деталь.

Плохой процесс:

начали публиковать статью
↓
IndexNow отправлен
↓
запись в БД не сохранилась
↓
URL возвращает 404

Мы сообщили поисковой системе об URL, который ещё не существует корректно.


Лучше так

Publish transaction
↓
COMMIT
↓
public URL available
↓
SEO validation
↓
IndexNow job

То есть внешний notification является следствием успешно завершённой публикации.


Ещё лучше проверить страницу перед отправкой

Например после publication:

GET public URL

и убедиться:

HTTP 200;
не noindex;
canonical корректный.

После этого:

IndexNow.

Это особенно полезно для собственной CMS

Если статья:

PUBLISHED

но из-за ошибки маршрутизации реально:

404,

IndexNow лишь быстрее сообщит поисковику о сломанной странице.

Сам протокол не проверяет качество вашего релиза за вас.


Ключ подтверждения

Нельзя позволить любому человеку сообщать Яндексу:

На example.ru изменились вот эти страницы.

Поэтому IndexNow использует ключ подтверждения управления сайтом.

Общая схема:

генерируем key
↓
размещаем key-файл
на сайте
↓
передаём key
в IndexNow request
↓
поисковая система
проверяет файл

Яндекс требует ключ длиной от 8 до 128 символов; допустимы латинские буквы, цифры и дефис. Файл должен содержать ключ и быть доступен поисковой системе. Яндекс рекомендует размещать его в корне сайта.


Как выглядит key-файл

Допустим ключ:

ExampleKey-8F42A7

Тогда удобно разместить:

https://example.ru/ExampleKey-8F42A7.txt

Содержимое:

ExampleKey-8F42A7

Без HTML.

Без JSON.

Просто текст.


Почему корень удобнее

Если key-файл находится в корне host:

https://example.ru/<key>.txt

он может использоваться для URL этого host.

Если разместить его глубже:

/catalog/<key>.txt

область применения ключа ограничивается соответствующим путем.

И официальная документация IndexNow, и Яндекс рекомендуют корневой вариант как наиболее простой.


Отдельно про поддомены

Если архитектура:

example.ru
blog.example.ru
shop.example.ru

нельзя без проверки предполагать, что ownership автоматически распространяется одинаково на всё.

Яндекс рекомендует использовать отдельный ключ для каждого поддомена.

Для обычного проекта это ещё один аргумент не плодить subdomains без необходимости.


Отправка одного URL

Для одного адреса Яндекс поддерживает GET-запрос:

GET https://yandex.com/indexnow
    ?url=https%3A%2F%2Fexample.ru%2Fexpert%2Farticle
    &key=ExampleKey-8F42A7

Если key-файл расположен нестандартно, можно дополнительно передать:

keyLocation.

Текущий официальный endpoint Яндекса для IndexNow — https://yandex.com/indexnow.


Но для редакционной системы удобнее POST

Представим одновременно опубликовано:

7 статей;
2 кейса;
1 новая услуга.

Делать десять отдельных запросов необязательно.

IndexNow поддерживает batch submission.

Яндекс принимает JSON:

{
  "host": "example.ru",
  "key": "ExampleKey-8F42A7",
  "urlList": [
    "https://example.ru/expert/article-a",
    "https://example.ru/expert/article-b",
    "https://example.ru/services/crm"
  ]
}

через:

POST https://yandex.com/indexnow
Content-Type: application/json

В одном запросе Яндекс разрешает передать до 10 000 URL. Такой же лимит указан в официальном протоколе IndexNow.


Но возможность отправить 10 000 URL не означает, что это нужно делать постоянно

Представим сайт содержит:

350 статей.

Редактор изменил одну.

Плохая автоматизация:

статья изменена
↓
отправляем все 350 URL.

Лучше:

изменена одна
↓
отправляем одну.

IndexNow — change notification.

Не ежедневный полный экспорт Sitemap.


Какой ответ считать успешным

При нормальной подтверждённой отправке Яндекс возвращает:

200 OK

Это означает:

URL принят сервисом.

Но не:

URL уже проиндексирован.

И официальный протокол IndexNow отдельно подчёркивает: HTTP 200 подтверждает получение URL поисковой системой, а не включение страницы в индекс.


При первом использовании можно получить 202

Яндекс использует:

202 Accepted

когда новый key ещё ожидает проверки.

Документация рекомендует убедиться, что файл размещён правильно, немного подождать и отправить несколько других адресов; переход ответа к 200 означает, что проверка ключа завершилась и URL принимаются обычным образом.

Это важно для собственной админ-панели.

Не нужно интерпретировать:

202

как:

индексация выполнена.

Лучше сохранить:

pendingVerification.

Полезная внутренняя модель состояния

Например:

PENDING
SENT
ACCEPTED
PENDING_KEY_VERIFICATION
RETRY
FAILED

И хранить ответ отдельно от состояния страницы

Статья:

PUBLISHED

не должна становиться:

UNPUBLISHED

только потому, что IndexNow временно ответил ошибкой.

Это независимые процессы.


Хорошая таблица IndexNow jobs

Например:

indexnow_jobs

с полями:

id
url
reason
created_at
attempts
next_attempt_at
last_http_status
last_error
accepted_at

и, если нужно:

content_revision

Почему полезно хранить reason

Например:

PUBLISHED
CONTENT_UPDATED
DELETED
REDIRECTED

Через месяц можно понять:

Почему этот URL вообще был отправлен?

Почему useful content_revision

Допустим статья быстро редактируется:

revision 41
↓
42
↓
43

За десять секунд.

Не обязательно создавать три внешних запроса.

Можно оставить одну pending job:

URL
latest_revision=43.

Это называется coalescing

То есть:

UPDATE
UPDATE
UPDATE

сливаются в:

один notification
последнего состояния.

Для редакционных систем это особенно полезно.


Не отправляйте URL на каждое нажатие «Сохранить»

Редактор может:

исправить заголовок;
сохранить;
исправить абзац;
сохранить;
добавить ссылку;
сохранить.

Если каждый autosave вызывает IndexNow:

10 изменений
→ 10 запросов.

Никакой пользы.


Лучше привязать уведомление к публикационному событию

Например:

Save draft
→ ничего.

Publish
→ send.

Edit published article
→ mark public revision changed.

Publish changes
→ send.

Если CMS сохраняет изменения сразу публично, можно использовать debounce.

Например:

после изменения
подождать небольшой период
↓
если новых изменений нет
↓
отправить latest revision.

Но не нужно придумывать частоту отправки случайно

У Яндекса нет фиксированного общего лимита на число IndexNow-запросов, но используются алгоритмы защиты от чрезмерных отправок. Один и тот же URL Яндекс не рекомендует посылать слишком часто; если повтор действительно нужен, в документации указан ориентир не чаще примерно 10-минутного интервала. При слишком большом числе запросов возможен 429 Too Many Requests.

Следовательно, архитектура:

каждую секунду
повторять URL,
пока он не появится в поиске

неправильна.


IndexNow не нужно использовать как polling

Плохо:

не нашли URL в Яндексе
↓
send IndexNow
↓
через минуту ещё раз
↓
ещё
↓
ещё

Протокол сообщает факт изменения страницы.

Он не является командой:

Попробуй индексировать ещё раз, пока не получится.

Если страница не появляется в поиске

Нужно диагностировать:

HTTP;
robots;
noindex;
canonical;
контент;
дубли;
SSR/rendering;
качество документа.

Не увеличивать число IndexNow-запросов.


Потому что IndexNow не отменяет обычные правила SEO

Представим:

/article-a

отправлен успешно.

IndexNow:

200 OK.

Но сама страница:

<meta
  name="robots"
  content="noindex"
>

IndexNow не должен «победить» noindex.


Или canonical указывает на другую страницу

/article-a
canonical → /article-b.

IndexNow сообщил:

A изменился.

После обхода поисковик всё равно видит:

Сам сайт считает основным B.

Или страница возвращает soft 404

HTTP 200

но основной контент:

Материал не найден.

IndexNow лишь ускоряет доставку информации о текущем состоянии URL.

Он не делает плохую страницу хорошей.


Поэтому правильная последовательность важнее скорости

Для новой статьи:

Create
↓
Publish
↓
HTTP 200
↓
Indexability check
↓
Canonical check
↓
Sitemap update
↓
Internal listing update
↓
IndexNow

Не обязательно выполнять всё синхронно

Например публикация статьи не должна ждать:

ответа Яндекса.

Иначе внешний сервис становится частью критического пользовательского transaction.


Представим Яндекс временно недоступен

Редактор нажимает:

Опубликовать.

Если код делает:

save article
↓
send IndexNow
↓
timeout
↓
transaction failed

статья почему-то не публикуется из-за внешней SEO-интеграции.

Это плохая зависимость.


Лучше использовать outbox/job

Publication transaction
        │
        ├── article = PUBLISHED
        │
        ├── SEO metadata committed
        │
        └── IndexNow job created
                ↓
             COMMIT
                ↓
         article available
                ↓
             worker
                ↓
            IndexNow

Теперь:

Яндекс доступен
→ job completed.

Если:

timeout
→ retry later.

Статья всё равно опубликована.


Это особенно хорошо сочетается с PostgreSQL job queue

Например:

indexnow_jobs

worker забирает через:

FOR UPDATE SKIP LOCKED

необработанные задачи.

Система получает:

retry;
failed state;
наблюдаемость;
durability.

Сам IndexNow при этом остаётся внешней интеграцией, которая не может остановить редакционную систему.


Какие ошибки стоит retry

Например:

network timeout;
5xx;
429.

могут быть временными.


Но 403 — другой класс

Яндекс возвращает:

403 Invalid key

если ключ невозможно загрузить либо он не соответствует запросу.

Бесконечный retry:

403
↓
ещё 403
↓
ещё 403

не решит проблему.

Нужна проверка конфигурации.


То же с 422

Например:

Invalid URL;
Invalid key location;
неподходящий key;
слишком короткий key;
слишком длинный key.

Это configuration/data error, а не временный outage.


Значит retry policy должна различать ошибки

Условно:

200
→ DONE

202
→ PENDING_KEY_VERIFICATION

429
→ RETRY_WITH_BACKOFF

5xx/network
→ RETRY

400/403/422
→ FAILED_CONFIGURATION

Это гораздо профессиональнее:

if status != 200:
  retry forever

Exponential backoff

Если внешний сервис временно недоступен, можно использовать:

1 min
5 min
15 min
1 h
...

с ограничением числа attempts.

Не:

100 запросов в секунду.

У IndexNow job должен быть terminal failed state

Например после нескольких безуспешных попыток:

FAILED.

Администратор видит:

URL:
/expert/article

Reason:
CONTENT_UPDATED

Attempts:
7

Last response:
403 Invalid key

Теперь понятно, что проблема требует человека.


Не скрывайте сбой IndexNow

Плохая реализация:

try {
  await sendIndexNow(url);
} catch {
  // ignore
}

Система выглядит исправной.

Но уже полгода ничего не отправляет.


Нужна наблюдаемость

Минимально полезные метрики:

indexnow_jobs_created
indexnow_requests_total
indexnow_accepted_total
indexnow_pending_verification_total
indexnow_failed_total
indexnow_retry_total

И:

oldest_pending_job_age.

Особенно полезно показывать состояние в админ-панели

Например у статьи:

Опубликовано:
09.10.2026 16:14

Sitemap:
✓

IndexNow:
200 OK
09.10.2026 16:14

Причина:
Published

Или:

IndexNow:
⚠ 202 Pending verification

IndexNow:
✗ 403 Invalid key

Теперь IndexNow — наблюдаемая часть редакционной системы.

Не скрытый fetch() где-то после сохранения статьи.


Но не путайте статус IndexNow со статусом индексирования

Это очень важно для интерфейса.

Плохо показывать:

Проиндексировано:
✓

только потому, что Яндекс ответил:

200.

Это фактически неверно.


Лучше:

IndexNow:
URL принят Яндексом

или:

Уведомление отправлено.

Потому что решение о crawling и indexing принимается отдельно. Яндекс прямо пишет, что IndexNow не гарантирует индексацию переданного URL.


Значит в админке можно разделить

Publication:
PUBLISHED

Sitemap:
INCLUDED

IndexNow:
ACCEPTED

Search indexing:
отдельная информация,
если она вообще доступна

Это профессиональная семантика

Не обещать системе больше, чем она реально сообщает.


IndexNow при массовой публикации

Допустим была миграция редакционной системы.

Опубликовано:

800 новых страниц.

Не обязательно создавать:

800 GET requests.

Можно сформировать batch.


Но batch лучше строить из событий

Например worker каждые несколько секунд собирает:

до N pending URL

и отправляет:

{
  "host": "example.ru",
  "key": "...",
  "urlList": [
    "...",
    "...",
    "..."
  ]
}

Очень большой batch не всегда нужен

Разрешено до:

10 000 URL.

Но технический максимум не означает оптимальный размер конкретной queue.

Можно использовать:

50;
100;
500

в зависимости от нагрузки и удобства retry.


Почему маленькие batch иногда удобнее

Представим один batch:

10 000 URLs.

возвращает:

422.

Теперь нужно выяснить, какой URL или параметр испортил request.

При меньших партиях диагностика проще.


Можно валидировать URL до постановки job

Например:

protocol = https/http;
host = production host;
URL RFC3986-compatible;
no preview token;
no localhost.

Яндекс требует корректные URL и возвращает 422 при неподходящих данных.


Не отправляйте localhost

Кажется очевидным.

Но генератор может взять:

PUBLIC_BASE_URL

из неправильного environment:

http://localhost:4173

и начать создавать IndexNow jobs.

Это production configuration bug.


Поэтому startup preflight полезен

В production:

PUBLIC_BASE_URL
=
https://example.ru

и:

IndexNow host
=
тот же ожидаемый host.

Если нет:

application startup fails

или SEO subsystem явно переходит в failed configuration.


IndexNow key тоже проверяем при deployment

Полезный smoke test:

GET https://example.ru/<key>.txt

Ожидаем:

HTTP 200
Content-Type: text/plain
body = expected key

Не превращайте IndexNow key в application route, который иногда ломается

Например:

/<key>.txt

генерируется через:

React;
database;
authentication middleware.

Слишком много зависимостей.

Лучше key-файл отдаётся максимально просто:

Nginx/static file

или простым серверным endpoint без авторизации.


Но ключ не должен попадать в случайные места

Не нужно:

console.log(INDEXNOW_KEY)

или отправлять его в client-side JavaScript.

IndexNow вызывается:

с backend.

Не из браузера пользователя.


Почему не frontend

Если browser после публикации делает:

fetch('https://yandex.com/indexnow?...&key=...')

ключ становится доступен клиенту.

Кроме того, notification начинает зависеть от:

закрыл ли редактор вкладку;
сработал ли браузер;
CORS;
сетевого соединения пользователя.

Это серверная интеграция.


IndexNow — часть backend publication pipeline

Хорошая архитектура:

Admin
↓
Publish
↓
Backend
↓
DB commit
↓
Outbox/job
↓
IndexNow worker
↓
Yandex

Frontend только отображает результат.


Можно ли использовать один IndexNow endpoint и получить пользу в других поисковиках

Сам протокол IndexNow устроен так, что участвующие поисковые системы договариваются делиться полученными URL между собой. Это описано в официальной спецификации IndexNow.

Но для практической интеграции WebRuta с Яндексом разумнее считать гарантированным только то, что документировано Яндексом для его собственного endpoint:

https://yandex.com/indexnow

Не строить бизнес-логику на предположении:

Один POST гарантированно означает одинаковую обработку всеми поисковиками.

У каждого поисковика остаются собственные процессы crawling и indexing.


IndexNow и Google

Здесь важно не создавать ложных ожиданий.

IndexNow не является универсальной командой:

«отправить страницу во все поисковые системы».

Для Google по-прежнему актуальны собственные механизмы обнаружения:

crawlable links;
Sitemap;
обычный crawling;
другие поддерживаемые Google инструменты.

Поэтому Sitemap и нормальная архитектура сайта всё равно обязательны, даже если Яндекс уведомляется практически мгновенно.


IndexNow и sitemap.xml должны использовать один canonical generator

Например статья:

/expert/article

Sitemap generator создаёт:

https://example.ru/expert/article

А IndexNow почему-то:

https://example.ru/expert/article/

или:

https://www.example.ru/expert/article

Получаем расхождение.


Лучше иметь одну функцию

Условно:

getCanonicalPublicUrl(entity)

Её используют:

SSR canonical;
Sitemap;
IndexNow;
internal link generator.

Тогда URL-policy едина.


Это очень сильный архитектурный принцип

Не четыре subsystem, каждое из которых самостоятельно «угадывает» публичный адрес.

А одна canonical URL model.


Например

Article:
slug = indexnow-na-praktike

Функция возвращает:

https://example.ru/expert/indexnow-na-praktike

Именно этот URL:

в HTML canonical;
в sitemap.xml;
в IndexNow job;
во внутренних ссылках.

При переименовании slug

Система знает:

old canonical
new canonical

и может автоматически:

old → 301 new

обновить Sitemap и создать IndexNow notification.


Это уже не SEO «после разработки»

Это SEO как часть domain lifecycle.


Как может выглядеть публикационная state machine

Например:

DRAFT
   ↓
SCHEDULED
   ↓
PUBLISHED
   ↓
UPDATED
   ↓
ARCHIVED
   ↓
DELETED

Для каждого перехода определяем side effects.


DRAFT → PUBLISHED

создать public URL;
обновить Sitemap;
добавить в listing;
IndexNow(PUBLISHED).

PUBLISHED → UPDATED

Если изменение значимо для публичной страницы:

обновить lastmod;
IndexNow(CONTENT_UPDATED).

PUBLISHED → DELETED

удалить из Sitemap;
HTTP 404/410;
убрать внутренние ссылки;
IndexNow(DELETED).

Slug change

old → 301 new;
Sitemap old remove;
Sitemap new add;
IndexNow URL-change events.

Теперь IndexNow становится обычным side effect бизнес-перехода.


Как не потерять уведомление при падении сервера

Плохая реализация:

UPDATE article
COMMIT

sendIndexNow()

Между:

COMMIT

и:

sendIndexNow

process падает.

Статья опубликована.

Job не существует.

IndexNow потерян.


Надёжнее transactional outbox

В одной транзакции:

UPDATE article
+
INSERT outbox_event

Затем:

COMMIT.

Worker читает:

outbox_event.

Теперь возможны только два состояния

Транзакция не прошла:

нет публикации
и нет notification.

Транзакция прошла:

публикация есть
и durable событие тоже есть.

Это значительно надёжнее callback после commit

Особенно для:

scheduled publishing;
массового импорта;
автоматической публикации.

Что если IndexNow job выполнится дважды

Допустим worker:

отправил URL;

но умер до:

status = completed.

После restart job повторяется.

Это нормально.

IndexNow notification не должен быть финансовой операцией с exactly-once semantics.


Но повторять слишком часто всё равно не нужно

Поэтому можно хранить:

last_accepted_revision.

Если уже отправлена:

revision 43

и повторно worker видит ту же:

43,

можно не создавать лишнюю заявку.


Дедупликация job

Условный ключ:

url + public_revision

или:

entity + revision.

Если появилась revision 44

Новая отправка оправдана.


Это полезнее простой дедупликации по URL

Потому что один URL совершенно нормально отправлять:

при первой публикации;
после существенного обновления;
после изменения его состояния.

Не удаляйте историю полностью

Полезно знать:

09.10
published
→ accepted 200

12.10
content updated
→ accepted 200

18.10
content updated
→ 429
→ retry
→ accepted 200

Это уже audit trail редакционной SEO-системы.


Но не храните бесконечно каждую мелкую попытку без retention

Например подробные HTTP attempts можно хранить:

30–90 дней

а итоговое состояние публикационной сущности — дольше.

Конкретный срок зависит от эксплуатации.


IndexNow и scheduled publishing

Для отложенной статьи особенно важно не отправить URL раньше срока.

Например:

publish_at:
15.10.2026 09:00

13 октября запись уже существует.

Но IndexNow job не должен создаваться.


В 09:00 scheduler выполняет transaction

SCHEDULED
→ PUBLISHED

Только теперь:

Sitemap update;
IndexNow event.

Это предотвращает преждевременное обнаружение preview URL

И сохраняет правильную связь:

уведомление
следует за реальной публикацией.

Массовый импорт старых статей

Допустим в новую CMS перенесено:

500 уже существовавших статей

с теми же URL и без фактического изменения контента.

Нужно ли все 500 сразу отправлять?

Не обязательно.

Яндекс прямо рекомендует при подключении IndexNow отправлять изменения, происходящие после начала поддержки протокола, а не пытаться ретроспективно переслать все прошлые изменения сайта.

Sitemap остаётся источником полного набора актуальных URL.


А если миграция реально изменила страницы

Например одновременно:

изменились URL;
контент;
canonical;
структура.

Это уже настоящие изменения.

Тогда соответствующие URL могут быть кандидатами на notification.


Как тестировать интеграцию

Проверять только:

fetch() не бросил exception

недостаточно.

Нужны tests на полный contract.


Например test key-file

GET /<indexnow-key>.txt

ожидаем:

200
body = key.

Test published article

Создаём:

DRAFT.

Ожидаем:

IndexNow jobs = 0.

Публикуем.

Ожидаем:

IndexNow jobs = 1.

Test repeated draft save

save
save
save

Ожидаем:

0 notifications.

Test published content update

Меняем публичный контент.

Ожидаем:

new revision notification.

Test internal metadata update

Меняем:

admin_note.

Ожидаем:

no new IndexNow job.

Test deletion

Удаляем опубликованную страницу.

Ожидаем:

URL исчез из Sitemap;
HTTP 404/410;
создан IndexNow deletion notification.

Test slug migration

Ожидаем:

old URL → 301;
new URL → 200;
Sitemap → new;
IndexNow events created.

Test 429

Mock Яндекса отвечает:

429.

Job должен перейти:

RETRY

с backoff.


Test 403

Ожидаем:

FAILED_CONFIGURATION

а не бесконечную высокочастотную retry-очередь.


Test server crash

После создания durable job убиваем worker.

После restart:

notification всё равно отправляется.

Test duplicate job

Одна revision не должна создавать бесконечные одинаковые внешние запросы.


В итоге IndexNow тоже становится «кодом»

Не ручной кнопкой.

Не CMS-плагином, о котором никто не знает.

А частью проверяемой архитектуры:

content lifecycle
↓
SEO state
↓
durable notification
↓
observable response.

Что мониторить после запуска

Полезный dashboard может показывать:

МетрикаЧто она означает
PendingУведомления ожидают отправки
AcceptedЯндекс принял сообщения
202Ключ ожидает подтверждения
RetryВременные ошибки
FailedТребуется вмешательство
Oldest pending ageКак долго SEO-очередь отстаёт
Last successful requestКогда интеграция последний раз реально работала

Особенно важен oldest pending age

Например:

Pending = 3.

На первый взгляд нормально.

Но самый старый:

4 дня.

Значит worker фактически сломан.


Ещё полезна метрика accepted/rejected ratio

Если вчера:

99.9% accepted

а после deploy:

0% accepted
403 Invalid key,

ошибка обнаруживается сразу.


Можно ли отправлять IndexNow синхронно для маленького сайта

Технически можно.

Но архитектурно даже для небольшого проекта background job обычно безопаснее.

Потому что внешний SEO-сервис:

не должен определять,
успешно ли пользователь
опубликовал статью.

Это тот же принцип, что для email

Статья опубликована.

Email-уведомление временно не ушло.

Не нужно откатывать публикацию.


IndexNow — secondary side effect

Критическое состояние:

страница опубликована.

Дополнительное:

Яндекс уведомлён.

Где проходит граница ответственности IndexNow

IndexNow может ускорить обнаружение изменения.

Но он не решает:

качество страницы;
canonical conflicts;
robots/noindex;
HTTP errors;
дубли;
плохой SSR;
слабый контент;
ранжирование.

Поэтому ожидание

Подключим IndexNow, и новые статьи сразу будут в топе.

ошибочно сразу на двух уровнях.

Первое:

уведомление ≠ индексирование.

Второе:

индексирование ≠ высокий ranking.

Реальная последовательность

IndexNow notification
↓
Yandex узнаёт об изменении
↓
crawler / processing
↓
indexing decision
↓
ranking decision

Каждый этап имеет собственные критерии.


IndexNow особенно полезен динамическим сайтам

Например:

новостным;
маркетплейсам;
каталогам;
экспертным центрам;
сайтам с часто обновляемыми услугами;
редакционным системам.

Там изменение URL — обычное событие продукта.


Для сайта из пяти почти неизменных страниц выгода меньше

Яндекс даже отдельно указывает, что для небольшого сайта с несколькими страницами можно использовать ручной инструмент переобхода в Яндекс Вебмастере.

Но если публикации автоматизированы, IndexNow всё равно хорошо ложится в инфраструктуру.


IndexNow особенно хорошо работает не сам по себе, а в связке

Например:

Editorial system
        │
        ├── Canonical URL
        ├── SSR HTML
        ├── Sitemap
        ├── Internal links
        ├── Robots policy
        └── IndexNow

Все эти элементы используют одну публикационную модель.


Тогда статья после публикации автоматически

получает URL;
появляется в /expert;
попадает в Sitemap;
имеет self-canonical;
получает structured data;
и создаёт IndexNow event.

Редактор не должен помнить:

Теперь нужно ещё отдельно сообщить Яндексу.

Это и есть зрелая редакционная система

Человек занимается:

содержанием.

Приложение занимается:

техническим SEO lifecycle.

Практический checklist перед включением IndexNow

  1. Определён единый production canonical host и генератор публичных URL.
  2. IndexNow key создан и корректно доступен на сайте.
  3. Ключ отправляется только backend-системой и не попадает в frontend.
  4. Новые URL отправляются только после успешной публикации.
  5. Draft и scheduled материалы не отправляются до фактического появления.
  6. Существенные изменения публичного контента создают новое уведомление.
  7. Внутренние изменения БД не создают SEO-события.
  8. Удалённые страницы корректно меняют HTTP-state и могут отправляться через IndexNow.
  9. Slug migration синхронизирована с redirect, canonical и Sitemap.
  10. IndexNow не блокирует основную publication transaction.
  11. Задания хранятся durable и имеют retry.
  12. 200, 202, 403, 422, 429 обрабатываются как разные состояния.
  13. Одинаковые autosave не создают поток одинаковых запросов.
  14. Sitemap остаётся полным реестром текущих indexable URL.
  15. Статус IndexNow accepted не называется в интерфейсе «страница проиндексирована».
  16. Есть метрики pending, retries, failures и времени старейшей задачи.
  17. После deployment выполняется smoke-test key-файла и IndexNow configuration.

Production-схема целиком

Хорошо спроектированная система может выглядеть так:

                 Редактор
                    │
                    ▼
             Publish article
                    │
                    ▼
             DB transaction
            /       |        \
           /        |         \
 article=PUBLISHED  |     outbox event
                    |
              public revision
                    │
                    ▼
                  COMMIT
                    │
         ┌──────────┴──────────┐
         ▼                     ▼
   Public page              SEO worker
   HTTP 200                    │
   canonical                   ├── Sitemap update
   content                     │
                               └── IndexNow job
                                      │
                                      ▼
                              Yandex IndexNow
                                      │
                         ┌────────────┼────────────┐
                         ▼            ▼            ▼
                       200           202         error
                         │            │            │
                    ACCEPTED       PENDING      retry/
                                               failed

Главное здесь — отсутствие жёсткой зависимости:

публикация страницы

от:

доступности IndexNow.

А затем работает обычный поисковый pipeline

Даже после:

IndexNow 200 OK

остаётся:

crawl
↓
HTTP
↓
robots
↓
rendering
↓
canonicalization
↓
content evaluation
↓
indexing
↓
ranking

IndexNow ускоряет вход в эту цепочку.

Не отменяет её.


Что IndexNow меняет для разработчика

Без него редакционная система говорит:

Страница опубликована. Когда поисковик её заметит — уже его дело.

С ним система может сказать:

Страница опубликована, и поисковой системе автоматически отправлен сигнал об изменении.

Это небольшая разница с точки зрения UI.

Но большая с точки зрения инженерной зрелости.


Потому что notification становится детерминированным

Мы знаем:

когда был создан;
какой URL отправлен;
почему;
какая revision;
какой ответ вернулся;
нужен ли retry.

Это уже наблюдаемая интеграция.


Вместо вывода

IndexNow полезнее всего не тогда, когда администратор вручную нажимает:

Отправить URL.

А когда протокол становится естественной частью lifecycle контента.

Новая страница:

Publish
↓
Sitemap
↓
IndexNow

Существенно изменённая:

Public revision
↓
lastmod
↓
IndexNow

Удалённая:

404/410
↓
remove from Sitemap
↓
IndexNow

Переехавшая:

old → 301 new
↓
Sitemap → new
↓
IndexNow

При этом самая важная граница остаётся прежней:

IndexNow accepted
≠
indexed

Яндекс официально описывает IndexNow именно как способ сообщить о новых, изменённых или удалённых страницах и прямо предупреждает, что протокол не гарантирует включение переданного URL в индекс.

Поэтому сильная реализация IndexNow состоит не из одного:

fetch('https://yandex.com/indexnow')

а из целой небольшой системы:

canonical URL generation
↓
content change detection
↓
durable job
↓
batching / deduplication
↓
API request
↓
response classification
↓
retry
↓
monitoring

И всё это работает рядом с:

sitemap.xml;
robots.txt;
canonical;
HTTP statuses;
SSR;
internal linking.

Тогда IndexNow перестаёт быть очередным SEO-плагином.

Он становится нормальным production-механизмом публикации:

если публичная страница действительно изменилась, сайт сам и быстро сообщает об этом поисковой системе — автоматически, наблюдаемо и без участия редактора.

Есть похожая задача?

Опишите продукт, интеграции и ограничения. До разработки зафиксируем объём, риски и критерии приёмки.

Обсудить проект →