SEO JavaScript-сайтов и SPA
Сайты на React, Vue, Angular и других JS-фреймворках выглядят современно и работают как приложение. Но у них есть коварная SEO-ловушка: контент рисуется JavaScript уже в браузере, а в исходном HTML — пусто. Если поисковик не выполнит этот JS, он увидит чистую страницу без текста и ничего не проиндексирует. Разберём, как сделать JS-сайт видимым для поиска.
Почему JS-сайты — проблема для SEO
Обычный сайт отдаёт готовый HTML с текстом — поисковик сразу его читает. SPA (single page application) отдаёт почти пустой HTML и пакет JavaScript, который уже в браузере подгружает данные и рисует контент. Робот должен сначала выполнить JS, чтобы увидеть текст. Яндекс и Google это умеют, но не всегда, не сразу и не идеально — рендеринг JS откладывается и тратит ресурсы, а часть контента может не попасть в индекс.
Без выполнения JS робот видит пустой <div id="root"> — ни текста, ни ссылок.
Две волны индексации: почему JS ждёт
Даже когда робот умеет выполнять JavaScript (а Googlebot умеет), он делает это не сразу. Индексация JS-сайта идёт в две волны: сначала робот забирает и индексирует то, что уже есть в HTML, а рендеринг скриптов откладывает в отдельную очередь — она может разгребаться от нескольких часов до нескольких дней. Всё, что рисует JS, попадёт в индекс только во вторую волну, и то если рендеринг прошёл успешно.
Вывод из этой картины простой: чем больше важного контента в исходном HTML, тем быстрее и надёжнее он попадёт в поиск. Полагаться на то, что «робот дорендерит», — значит ставить индексацию в зависимость от очереди, на которую вы не влияете.
Способы рендеринга: что выбрать
Главный вывод: для SEO нужно, чтобы контент был в HTML до выполнения JS. Достигается это через SSR или SSG. Если переписать архитектуру нельзя — выручает пререндер.
Как проверить, видит ли поиск ваш контент
- Код без JS. Откройте исходный код страницы (Ctrl+U) или отключите JavaScript в браузере — виден ли основной текст и ссылки. Если пусто — у вас проблема.
- Google Search Console — проверка URL показывает отрендеренный HTML, как его видит Googlebot.
- Сравните отрендеренную версию с тем, что в исходном коде.
Частые ошибки JS-сайтов
- Навигация на onClick вместо <a href>. Робот не «кликает» — переходы должны быть обычными ссылками.
- Контент по событию. Текст, который появляется только после клика/скролла, робот может не увидеть.
- Мета-теги через JS. Title и description, проставляемые скриптом, ненадёжны — лучше задавать на сервере (SSR).
- Тяжёлый бандл. Огромный JS медленно грузится и ухудшает Core Web Vitals (особенно INP).
Чек-лист SEO для JS-сайта
- Основной контент есть в HTML до выполнения JS (SSR или SSG)
- Title, description, H1 задаются на сервере, не только скриптом
- Навигация — обычные <a href>, не onClick
- Текст виден без кликов и скролла
- Проверено в Search Console (отрендеренный HTML)
- Бандл оптимизирован, Core Web Vitals в норме
- Если SSR невозможен — настроен пререндер для роботов
Яндекс и JavaScript: отдельная осторожность
Важный нюанс для Рунета: Яндекс рендерит JavaScript заметно скромнее Google. Если ваш трафик в основном из Яндекса, надеяться на то, что робот «выполнит скрипты и всё увидит», тем более не стоит. Для Яндекса SSR или SSG — это почти обязательное условие нормальной индексации JS-сайта, а не один из вариантов. Проще говоря: то, что кое-как переваривает Googlebot, Яндекс может просто не увидеть. Делайте контент в HTML — и спор о возможностях рендеринга снимается для обоих.
Гидратация: контент в HTML, интерактив на JS
SSR и SSG не означают отказ от React или Vue. Работает это через гидратацию: сервер отдаёт готовый HTML с текстом (его сразу видят и человек, и робот), а затем тот же JS-фреймворк «оживляет» страницу в браузере — навешивает обработчики, делает её интерактивной. Лучшее из двух миров: индексируемость статики и удобство приложения. Подвох — ошибки гидратации: если разметка с сервера и то, что строит JS, расходятся, в консоли сыплются предупреждения, а часть контента может «мигать» или подменяться. Следите, чтобы серверная и клиентская версии совпадали.
Что робот точно не увидит
Даже на отрендеренной странице есть зоны, в которые робот не попадает. Их стоит знать, чтобы не прятать туда важное:
- Контент за действием пользователя — то, что подгружается только по клику «Показать ещё», по наведению или после отправки формы.
- Бесконечная прокрутка без обычной пагинации — товары и материалы ниже первого экрана могут остаться вне индекса.
- Контент за авторизацией или согласием на cookie — если без логина или клика по баннеру страница пустая, робот увидит пустоту.
- Данные из сторонних API, которые иногда не успевают загрузиться к моменту рендеринга, — важный текст не должен зависеть от внешнего запроса.
Маршрутизация: чистые URL вместо хэшей
В SPA есть два способа делать «страницы». Старый — через хэш в адресе (site.ru/#/catalog): всё после # поиск обычно игнорирует, поэтому такие маршруты плохо индексируются (а древняя схема #! для AJAX давно не поддерживается). Правильный — History API с обычными чистыми URL (site.ru/catalog): каждый маршрут — отдельный адрес, который можно отдать роботу с готовым HTML. Если делаете SPA, используйте History API и настройте сервер так, чтобы каждый такой URL открывался напрямую.
Как мигрировать с CSR на SSR без потери позиций
- Начните с самых важных по трафику шаблонов (категории, карточки, статьи) — переведите на SSR/SSG их в первую очередь.
- Сохраните прежние URL один-в-один: меняется рендеринг, а не адреса страниц.
- Проверьте, что мета-теги, заголовки и микроразметка теперь в исходном HTML.
- Выкатывайте по частям и следите за индексацией и позициями в Вебмастере и Search Console пару недель.
Коротко
SPA на React/Vue рисуют контент в браузере, а в исходном HTML пусто — и поисковик может не увидеть текст. Чтобы JS-сайт индексировался, контент должен быть в HTML до выполнения JS: это даёт SSR (сервер отдаёт готовый HTML) или SSG (статическая генерация). Если переписать нельзя — спасает пререндер для роботов. Проверяйте, виден ли контент без JS и в Search Console, делайте навигацию обычными ссылками, задавайте мета на сервере и следите за весом бандла. Тогда современный JS-сайт будет и красивым, и видимым для поиска.