Почему сайт на React не индексируется и как это исправить
Почему SPA на React плохо индексируются в Яндексе и Google: пустой HTML, одинаковые мета-теги, коды 200 для несуществующих страниц. Как проверить сайт, SSR, статическая генерация и предрендеринг, что делать с уже запущенным сайтом.
Сайт сделали на React: быстрый интерфейс, плавные переходы, современный стек. Через два месяца после запуска в поиске видна одна главная страница, у остальных в выдаче одинаковый заголовок, а в панели вебмастера — сотни страниц с пометкой «обнаружена, не проиндексирована». Ситуация типичная, и почти всегда она не связана ни с качеством контента, ни с санкциями поисковых систем. Причина в том, как сайт отдаёт страницы роботу. Ниже — почему одностраничные приложения на React и других JavaScript-фреймворках плохо индексируются, как быстро проверить, видит ли поисковый робот ваш контент, какие есть способы решения и чем они отличаются по стоимости и последствиям. Материал полезен и при запуске нового сайта, и когда уже работающий сайт на React не набирает поисковый трафик. Почему JavaScript-сайт может быть невидим для поиска Как устроено одностраничное приложение Классический сайт на каждый запрос отдаёт готовый HTML: заголовок, текст, ссылки уже есть в ответе сервера. Одностраничное приложение (SPA) в базовом варианте устроено иначе. Сервер на любой адрес отдаёт почти пустой HTML с одним контейнером и подключённым скриптом. Всё остальное — текст, заголовки, ссылки, мета-теги — создаёт JavaScript уже в браузере пользователя. Человек этого не замечает: браузер выполняет скрипт за доли секунды. Поисковому роботу, чтобы увидеть то же самое, нужно тоже выполнить JavaScript. И здесь начинаются проблемы. Рендеринг стоит поисковику ресурсов Загрузить HTML дёшево. Выполнить JavaScript, дождаться загрузки данных и построить страницу — в разы дороже. Поэтому поисковые системы обрабатывают JavaScript-страницы в два этапа: сначала получают исходный HTML, затем, когда появляются ресурсы, ставят страницу в очередь на рендеринг. Между этапами может пройти заметное время, а часть страниц может так и не дойти до рендеринга. Google официально описывает такую двухэтапную обработку и умеет выполнять современный JavaScript. Яндекс также умеет рендерить JavaScript, а в Вебмастере есть настройка, позволяющая управлять рендерингом страниц сайта. Но «умеет» не значит «гарантированно и быстро для каждой страницы». Сайт, который показывает контент только после выполнения скриптов, всегда индексируется медленнее и менее надёжно, чем сайт с готовым HTML. Типичные проблемы SPA с точки зрения поиска Пустой исходный HTML Главная проблема. Если в ответе сервера нет текста страницы, робот до рендеринга видит пустую страницу, а после неудачного или отложенного рендеринга — тоже пустую. Одинаковые мета-теги на всех страницах Заголовок и описание в исходном HTML общие для всего приложения, а конкретные значения подставляются скриптом. В результате в выдаче у разных страниц одинаковые сниппеты, а поисковая система может счесть страницы дублями. Код ответа 200 для несуществующих страниц Сервер на любой адрес отдаёт одну и ту же оболочку с кодом 200, а «страница не найдена» рисует уже приложение. Для робота такие адреса выглядят как настоящие страницы. Это засоряет индекс и расходует лимит обхода на мусор. Правильно — отдавать код 404 для несуществующих адресов на уровне сервера. Навигация без ссылок Переходы сделаны через обработчики нажатий на элементах, которые не являются ссылками. Пользователь переходит, робот — нет: он находит страницы по атрибуту href у ссылок. Если ссылок нет, страницы, на которые не ведёт карта сайта, не будут найдены вовсе. Адреса с решёткой Маршрутизация через фрагмент адреса вида /#/catalog/item. Часть адреса после решётки поисковые системы не считают отдельной страницей, и весь сайт индексируется как одна страница. Контент только после действия пользователя Текст загружается при прокрутке, по клику на вкладку или раскрытию блока. Робот не прокручивает и не кликает. Если важный контент появляется только после взаимодействия, для поиска его нет. Заблокированные ресурсы Скрипты, стили или адреса API закрыты в robots.txt. Робот не может загрузить то, что нужно для построения страницы, и видит её сломанной. Медленная загрузка данных Приложение сначала загружается, затем делает несколько последовательных запросов к API и только потом показывает контент. Робот при рендеринге ждёт ограниченное время. То, что не успело появиться, в индекс не попадает. Та же задержка ухудшает и показатели скорости для пользователей. Как проверить, видит ли поиск ваш контент Исходный код страницы Самая быстрая проверка. Откройте страницу, вызовите просмотр исходного кода — не инспектор элементов, а именно исходный код, который пришёл с сервера. Найдите поиском уникальную фразу из текста страницы. Если её нет, контент создаётся скриптом, и индексация зависит от рендеринга. То же самое можно проверить запросом к адресу без выполнения JavaScript — например, консольной утилитой. Посмотрите, что в ответе: текст страницы или пустой контейнер, уникальный заголовок или общий для всех. Инструменты вебмастеров В Google Search Console инструмент проверки адреса показывает, как Googlebot получил и отрисовал страницу, какой HTML увидел после рендеринга и какие ресурсы не загрузились. В Яндекс Вебмастере есть проверка ответа сервера и отчёты о статусе страниц в поиске. Сравните увиденное роботом с тем, что видит пользователь. Поиск по сайту Запрос с оператором поиска по сайту и уникальной фразой из глубокой страницы показывает, проиндексирован ли её текст. Если в выдаче страница есть, а по фразе из текста её не находит, в индекс попала оболочка без контента. Отчёты об индексации Большое число страниц в статусах «обнаружена, не проиндексирована», «дубль», «малоценная страница» на сайте с уникальным контентом — характерный признак проблем с рендерингом или одинаковыми мета-тегами. Способы решения Серверный рендеринг (SSR) Сервер на каждый запрос выполняет приложение и отдаёт готовый HTML с контентом, после чего в браузере приложение «оживает» и продолжает работать как SPA. Для React это обычно фреймворк Next.js или аналоги. Плюсы: полный HTML для любой страницы, включая страницы с часто меняющимися данными — каталог с остатками, персональные подборки. Минусы: нужен серверный процесс, который выполняет код на каждый запрос, растёт сложность инфраструктуры и нагрузка на сервер; существующее SPA часто требует заметной переработки, потому что код, рассчитанный только на браузер, на сервере не работает. О том, как современные подходы к рендерингу меняют архитектуру React-приложений, — в статье о React Server Components . Статическая генерация и предрендеринг HTML страниц генерируется заранее — при сборке сайта — и раздаётся как обычные файлы. Пользователь и робот сразу получают готовый контент, а приложение подключается поверх. Плюсы: максимальная скорость и надёжность, раздача с обычного веб-сервера или CDN, минимальная нагрузка. Минусы: данные в HTML актуальны на момент сборки, поэтому для часто меняющегося контента нужна пересборка или гибридный подход; при десятках тысяч страниц время сборки растёт. Этот вариант подходит для большинства сайтов компаний: услуги, кейсы, статьи, страницы команды и контакты меняются не каждую минуту. Именно так устроен и сайт, который вы сейчас читаете: интерфейс работает как одностраничное приложение, а при сборке для каждого маршрута — услуг, кейсов, статей, страниц команды — генерируется статический HTML с уникальными заголовком, описанием, текстом и микроразметкой. Там же автоматически собирается карта сайта, поэтому новая страница попадает в неё без ручных правок. Гибридный подход Часть страниц генерируется статически, часть рендерится на сервере по запросу, часть — с периодическим обновлением статического HTML. Современные фреймворки позволяют выбирать режим для каждого маршрута. Например, статьи и описания услуг — статически, каталог с наличием — на сервере, личный кабинет — только в браузере, потому что индексировать его не нужно. Динамический рендеринг Сервер определяет, что пришёл поисковый робот, и отдаёт ему заранее отрендеренную версию, а пользователям — обычное SPA. Раньше этот способ предлагался как временное решение. Сегодня Google прямо называет его обходным путём, который не рекомендуется для новых проектов: две версии сайта сложно поддерживать одинаковыми, а расхождение между тем, что видит робот и пользователь, создаёт риски. Допустим как временная мера для существующего сайта, пока идёт переход на полноценное решение. Как выбрать Сайт компании, блог, лендинги, каталог с редко меняющимися данными — статическая генерация или предрендеринг. Крупный каталог или маркетплейс с часто меняющимися ценами и наличием — серверный или гибридный рендеринг. Веб-приложение за авторизацией — индексировать нечего, достаточно статических публичных страниц: главной, описания продукта, тарифов, документации. Существующее SPA, которое срочно нужно в индекс — предрендеринг ключевых маршрутов как первый шаг, затем решение о полном переходе. Подводные камни предрендеринга Предрендеринг выглядит простым решением, но у него есть детали, которые легко упустить и которые проявляются уже после запуска. Расхождение HTML и приложения Приложение, подключаясь к готовому HTML, должно получить ту же разметку, что была сгенерирована. Если в браузере оно строит страницу иначе — другие данные, другой порядок блоков, зависимость от размера окна или текущего времени, — React перерисует страницу целиком. Пользователь увидит мерцание и сдвиг вёрстки, а преимущество в скорости исчезнет. Всё, что зависит от браузера, нужно отделять и отрисовывать после подключения приложения. Актуальность данных HTML отражает состояние на момент сборки. Если цена услуги изменилась в данных, а сайт не пересобран, робот увидит старую цену, а пользователь после загрузки приложения — новую. Решение — пересборка при каждом изменении контента, автоматически запускаемая из системы управления контентом или репозитория данных. Коды ответа для сгенерированных страниц Статическая страница «не найдено» должна отдаваться с кодом 404, а не 200. При раздаче статических файлов это настраивается на веб-сервере или CDN отдельно, и об этом часто забывают. Единообразие адресов Файлы, сгенерированные как папка с index.html, могут открываться и со слешем на конце, и без него. Для поиска это два адреса одной страницы. Нужно выбрать один вариант, настроить перенаправление со второго и указывать выбранный в canonical и карте сайта. Кэширование Готовый HTML удобно кэшировать на CDN, но после пересборки кэш нужно сбрасывать. Иначе исправления неделями не доходят ни до пользователей, ни до роботов. Контроль при сборке Разумно встроить в сборку проверку: у каждой сгенерированной страницы есть уникальный title и description, основной заголовок, текст не пустой, все маршруты из данных попали в карту сайта. Такая проверка ловит ошибку в момент, когда её дёшево исправить, а не когда страница выпала из индекса. Что нужно сделать независимо от способа рендеринга Уникальные мета-теги в HTML Title, description, canonical и Open Graph должны быть в HTML, который отдаёт сервер, а не только подставляться скриптом. Для каждой страницы — свои. Абсолютный адрес изображения для Open Graph, иначе превью ссылки в мессенджерах и соцсетях не соберётся. Настоящие ссылки Навигация через элемент ссылки с атрибутом href и нормальным адресом. Маршрутизатор перехватывает клик и выполняет переход без перезагрузки, но ссылка остаётся ссылкой для робота, для открытия в новой вкладке и для программ чтения с экрана. Чистые адреса Маршрутизация через History API с адресами без решётки, одна страница — один адрес, единообразие в завершающем слеше и регистре. Правильные коды ответа 404 для несуществующих страниц на уровне сервера, 301 для перенесённых адресов. При переделке сайта — карта перенаправлений со всех старых адресов, иначе накопленные позиции теряются. Карта сайта и robots.txt Карта сайта с актуальными адресами, генерируемая автоматически из тех же данных, что и маршруты приложения. В robots.txt — не закрывать скрипты, стили и ресурсы, нужные для отрисовки страниц. Микроразметка Структурированные данные schema.org в формате JSON-LD — организация, хлебные крошки, статьи, услуги, вопросы и о