JavaScript SEO: как продвигать сайт на React, Vue и SPA

JavaScript SEO: как продвигать сайт на React, Vue и SPA

Красивый интерфейс на React, мгновенные переходы между экранами без перезагрузки, довольный заказчик — и ноль трафика из поиска через полгода после запуска. Это классический сценарий, с которым мы сталкиваемся в SEO ПРОГРЕСС по нескольку раз в год: сайт технически безупречен с точки зрения фронтенд-разработчика и практически невидим для поискового робота. Проблема не в самом JavaScript — на нём работает половина интернета, — а в том, что индексация JS-контента устроена принципиально иначе, чем индексация обычного HTML. В этой статье разберём механику: как Яндекс и Google рендерят JavaScript, почему часть контента теряется, как за 15 минут проверить, что реально видит робот, и какие архитектурные решения (SSR, SSG, пререндер, динамический рендеринг) применять в каждом случае.

Почему сайт на JavaScript — это отдельная SEO-дисциплина

Чтобы понять корень проблемы, нужно вспомнить, как работает поисковый робот с классическим сайтом. Робот отправляет HTTP-запрос, сервер отдаёт готовый HTML-документ, в котором уже есть заголовки, текст, ссылки, метатеги. Робот парсит этот документ, извлекает контент, находит ссылки, ставит их в очередь на обход. Один запрос — один готовый к индексации документ. Дёшево, быстро, предсказуемо.

Теперь возьмём типичное SPA (Single Page Application) на React или Vue без серверного рендеринга. Робот отправляет запрос — и получает примерно такое:

  • пустой <div id="root"></div> или <div id="app"></div>;
  • подключение бандла на 400–900 КБ;
  • иногда — прелоадер и текст «Загрузка…»;
  • один и тот же title и description на всех URL сайта.

Никакого контента. Весь текст, все ссылки, вся семантика появляются только после того, как браузер скачает JS-бандл, выполнит его, дождётся ответов от API и отрисует DOM. То есть чтобы увидеть страницу, роботу нужно не просто скачать документ, а запустить полноценный браузер. И вот здесь начинаются все сложности: и технические, и экономические.

Запуск headless-браузера для одной страницы стоит поисковой системе в десятки, а по некоторым оценкам — в сотни раз дороже, чем простое скачивание HTML. Когда речь идёт о миллиардах страниц, эта разница превращается в реальные деньги и реальные ограничения. Именно поэтому рендеринг JS в поисковых системах — это не «включено по умолчанию для всех», а отдельный процесс с очередью, приоритетами и лимитами.

Две волны индексации: как Google рендерит JavaScript

Google открыто описывал свой пайплайн обработки JS, и он состоит из двух этапов, которые в индустрии принято называть «двумя волнами индексации».

Первая волна. Googlebot скачивает исходный HTML, парсит его, извлекает всё, что есть в разметке сразу: текст, ссылки, метатеги, canonical, robots-директивы. Найденные ссылки отправляются в очередь на обход. Если в HTML ничего нет (пустой div), то и извлекать нечего — страница попадает в индекс либо как пустая, либо не попадает вовсе.

Вторая волна. Страница ставится в очередь на рендеринг (Render Queue). Когда до неё доходит очередь, специальный сервис — Web Rendering Service — запускает headless Chrome, выполняет JavaScript, ждёт стабилизации DOM и отдаёт итоговый HTML обратно в индексатор. Только после этого Google видит контент, который был отрисован скриптами, и находит ссылки, появившиеся динамически.

Ключевые следствия из этой архитектуры, о которых нужно помнить:

  1. Между волнами проходит время. Раньше речь шла о днях и неделях; сейчас для большинства сайтов задержка сократилась до часов, но она никуда не делась. Для новостного или сезонного контента это критично — актуальность к моменту рендеринга может быть потеряна.
  2. Ссылки из второй волны обходятся с задержкой. Если внутренняя перелинковка построена только на JS, обход сайта растягивается: сначала рендер главной, потом обнаружение ссылок, потом обход категорий, потом рендер категорий, потом обнаружение товаров. Каждый уровень вложенности — новый цикл. На большом каталоге это месяцы.
  3. Директивы из HTML применяются раньше JS. Если в исходном HTML стоит noindex, то до рендеринга дело может вообще не дойти — робот просто выбросит страницу. Попытка «снять noindex через JS» не работает.
  4. Рендеринг может не состояться. Ошибка в бандле, отвалившийся API, таймаут, заблокированный в robots.txt скрипт — и вторая волна возвращает пустую страницу.

Есть и приятная деталь: рендеринг-сервис Google давно работает на актуальной версии Chromium, то есть поддерживает современный синтаксис и большинство браузерных API. Но он не бесконечно терпелив: если контент подгружается через цепочку из пяти последовательных запросов с общим временем в 8 секунд, шанс, что робот дождётся, невелик. Отсюда прямая связь между скоростью сайта и Core Web Vitals и полнотой индексации JS-проектов: медленный рендер — это не только про UX, это про то, попадёт ли текст в индекс.

Почему с Яндексом сложнее, чем с Google

Для российского бизнеса главный поисковик — Яндекс, и здесь ситуация исторически была строже. Яндекс тоже умеет исполнять JavaScript: у него есть собственный рендеринг, робот поддерживает выполнение скриптов, и в Вебмастере даже есть инструменты для проверки. Но на практике мы регулярно видим следующее.

  • Рендеринг применяется избирательнее. Яндекс не гарантирует, что отрендерит каждую страницу каждого сайта. Молодой сайт с небольшим краулинговым бюджетом может месяцами висеть в индексе с пустыми страницами, тогда как Google эти же страницы отрендерит за неделю.
  • Задержка между обходом и рендерингом обычно больше. Разница между «Googlebot увидел текст на второй день» и «Яндекс увидел текст через три недели» — это реальный разрыв, который мы наблюдали на десятках проектов.
  • Сложные конструкции переносятся хуже. Контент, который появляется после пользовательского события, ленивая подгрузка через IntersectionObserver, длинные цепочки асинхронных запросов — всё это Яндекс пропускает чаще.
  • Поведенческие и коммерческие сигналы завязаны на контент. Если робот не видит цену, кнопку заказа, контакты и условия доставки, страница проигрывает по коммерческим факторам ранжирования даже при идеальной вёрстке для пользователя.

Практический вывод простой и жёсткий: для рунета нельзя проектировать сайт в расчёте на то, что поисковик отрендерит JS. Google, скорее всего, справится. Яндекс — как повезёт. А раз основной трафик идёт из Яндекса, планировать нужно по худшему сценарию: критичный контент должен быть в исходном HTML. Подробнее про различия площадок мы разбирали в материале Яндекс vs Google: где продвигаться.

Диагностика: как узнать, что реально видит робот

Прежде чем что-то менять, нужно измерить масштаб проблемы. Ниже — порядок проверок, который мы применяем на аудите любого JS-проекта. Он занимает 20–40 минут и даёт полную картину.

1. Просмотр исходного кода против DOM

Самая быстрая и самая недооценённая проверка. Откройте страницу и нажмите Ctrl+U (Cmd+Option+U) — это исходный HTML, ровно то, что сервер отдал по HTTP. Затем откройте DevTools и посмотрите вкладку Elements — это DOM после исполнения JS, то, что видит пользователь.

Дальше берём ключевые элементы страницы и ищем их в исходном коде через Ctrl+F:

  • H1 и основной текст;
  • title и description (уникальные ли они для этого URL);
  • canonical;
  • цена, характеристики, наличие — для карточки товара;
  • ссылки на другие страницы (именно как <a href>);
  • микроразметка Schema.org.

Если в Elements всё есть, а в исходном коде — пусто, значит контент рождается только в браузере. Это и есть диагноз. Разница между двумя окнами — это ровно тот объём информации, который вы отдаёте на милость рендеринг-очереди.

2. Отключение JavaScript

В DevTools: Ctrl+Shift+P → «Disable JavaScript» → перезагрузить страницу. Вы увидите сайт примерно так, как его видит робот на первой волне. Это грубая, но очень наглядная проверка: если после отключения JS остался белый экран или прелоадер — на сайт не придёт органический трафик, пока это не исправлено.

Важно правильно интерпретировать результат. Не нужно требовать, чтобы без JS работали все интерактивные элементы — фильтры, слайдеры, корзина. Нужно, чтобы без JS был читаемый контент и кликабельные ссылки. Всё остальное — бонус для пользователя, а не для робота.

3. Инструменты Яндекс.Вебмастера

В Вебмастере есть два обязательных пункта:

  • Индексирование → Страницы в поиске — смотрим, сколько страниц реально в индексе против того, сколько их в sitemap. Разрыв в разы — красный флаг.
  • Инструменты → Проверка ответа сервера — вводим URL, получаем именно тот HTML, который видит робот, без браузерной магии. Это самый честный ответ на вопрос «что мы отдаём Яндексу».

Дополнительно полезно смотреть раздел «Статистика обхода»: если робот ходит по сайту, а страницы не появляются в поиске — с высокой вероятностью он получает пустышку. Про типовые причины выпадения страниц из индекса мы подробно писали в статье почему сайт выпал из индекса.

4. Проверка через поисковый оператор

Возьмите характерную фразу из текста страницы (7–10 слов, желательно не шаблонных) и вбейте её в кавычках в поиск с оператором site:. Если фраза не находится, хотя страница в индексе — контент до индексатора не дошёл. Простой тест, который не требует никаких инструментов и сразу отвечает на главный вопрос.

5. Логи сервера

Самый недооценённый источник правды. В логах видно, ходит ли робот по JS-файлам и API-эндпоинтам, какие коды ответа он получает, сколько времени занимает отдача. Типовая находка: робот получает 403 или 429 от API, потому что на эндпоинты навешен антибот или rate limit. В браузере всё работает, у робота — пустая страница. Такие вещи находятся только в логах.

Решение №1: серверный рендеринг (SSR)

SSR — это когда сервер выполняет JS-приложение на своей стороне и отдаёт браузеру готовый HTML с контентом. Дальше на клиенте происходит гидратация: тот же React «оживляет» уже готовую разметку, навешивает обработчики, и приложение продолжает работать как SPA. Пользователь получает быстрый первый экран и интерактивность, робот — полноценный HTML с первого запроса.

Стандартные инструменты:

  • Next.js — для React. Де-факто индустриальный стандарт;
  • Nuxt — для Vue;
  • Angular Universal — для Angular;
  • SvelteKit — для Svelte;
  • Remix — альтернативный React-фреймворк с упором на веб-стандарты.

SSR — правильный выбор, когда контент часто меняется и должен быть актуален в момент запроса: интернет-магазин с ценами и остатками, маркетплейс, агрегатор, портал с пользовательским контентом. Для SEO интернет-магазина это фактически безальтернативный вариант, если каталог живой.

Что нужно учитывать при переходе на SSR:

  1. Нагрузка на сервер вырастет. Рендер каждой страницы — это работа CPU. Нужен нормальный кеш (CDN, Redis, кеш на уровне фреймворка) и запас по мощности.
  2. Код должен быть изоморфным. Обращения к window, document, localStorage на этапе серверного рендера упадут. Это самая частая ошибка миграции.
  3. Метатеги надо задавать на сервере. Если title подставляется клиентским скриптом после гидратации — в исходном HTML его нет, и вся работа над эффективными метатегами уходит в никуда.
  4. TTFB может вырасти. Сервер тратит время на рендер до первого байта. Кеширование решает, но его надо продумать заранее.

Решение №2: статическая генерация (SSG)

SSG — это генерация HTML-файлов на этапе сборки. Прогнали билд — получили набор готовых статических страниц, которые раздаются с CDN за миллисекунды. Никакой нагрузки на сервер, идеальный TTFB, максимальная надёжность.

Инструменты: тот же Next.js (Static Export, generateStaticParams), Nuxt Generate, Astro, Gatsby, Hugo, Eleventy.

Идеальные кандидаты на SSG:

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

Ограничение очевидно: если контента десятки тысяч страниц и он меняется каждый час, полная пересборка становится мучением. Частично проблему решает ISR (Incremental Static Regeneration) в Next.js — страница генерируется статически, но перегенерируется по таймеру или по запросу. Гибрид SSG + ISR закрывает большинство реальных задач среднего бизнеса. Если у вас одностраничник на JS-фреймворке — почти всегда достаточно чистой статики; нюансы такого проекта мы разбираем в услуге продвижение одностраничного сайта.

Решение №3: пререндеринг

Пререндер — компромисс для тех, у кого уже есть готовое SPA и переписывать его на SSR нет ни денег, ни времени. Логика такая: отдельный сервис (Prerender.io, Rendertron, собственный скрипт на Puppeteer) заходит на страницы вашего сайта headless-браузером, дожидается отрисовки, сохраняет итоговый HTML и отдаёт этот снапшот роботам, тогда как обычные пользователи получают привычное SPA.

Плюсы:

  • внедряется за дни, а не месяцы;
  • не требует переписывать приложение;
  • работает с любым фреймворком.

Минусы, о которых нужно знать честно:

  • Снапшоты устаревают. Цена изменилась в базе — в снапшоте она старая, пока не пройдёт следующий обход. Для каталога с динамикой это риск.
  • Ещё одна точка отказа. Упал сервис пререндера — робот получил пустую страницу или 500-ю.
  • Не помогает пользователям. SSR ускоряет первый экран для всех, пререндер — только для роботов. Метрики скорости загрузки у живых посетителей не улучшатся.
  • Требует аккуратности. Контент в снапшоте обязан совпадать с тем, что видит пользователь. Иначе это уже клоакинг.

Решение №4: динамический рендеринг и где проходит граница с клоакингом

Динамический рендеринг — это определение робота по User-Agent (и по возможности по reverse DNS) и отдача ему отрендеренной версии, а пользователю — клиентской. Формально это разрешённый обходной путь, который сами поисковики предлагали как временную меру. Но именно здесь чаще всего ломают шею.

Правило одно и оно не имеет исключений: содержимое версии для робота и версии для пользователя должно совпадать. Тот же текст, те же заголовки, те же ссылки, те же цены. Отличаться может только способ доставки. Как только в версии для робота появляется «дополнительный SEO-текст», которого не видит человек, или другие ключевые слова — это клоакинг, и это прямой путь под фильтр. Про механику санкций Яндекса мы писали в материале о поисковых фильтрах Яндекса.

Наша позиция: динамический рендеринг — временная мера на период миграции, а не архитектура. Если вы строите сайт с нуля — берите SSR или SSG сразу. Если чините существующий — используйте динамический рендеринг как костыль, пока готовится нормальное решение.

Гидратация: как не потерять всё на последнем шаге

Гидратация — момент, когда клиентский JS подхватывает серверную разметку. Здесь есть несколько ловушек, из-за которых SSR перестаёт давать SEO-эффект.

  • Ошибки гидратации. Если серверный и клиентский рендер разошлись (например, на сервере выводится дата, а на клиенте — другая), React выбрасывает предупреждение и может перерисовать поддерево с нуля. Пользователь видит мигание, метрики страдают.
  • Тяжёлая гидратация. Отдали HTML быстро, но бандл на 800 КБ блокирует поток на секунды — интерактивность не наступает. INP улетает в красную зону.
  • Контент, который «схлопывается» после гидратации. Встречается, когда на сервере рендерится полный список, а клиент после монтирования запрашивает данные заново и до ответа показывает скелетон. Робот, который дождался гидратации, может увидеть именно скелетон.

Лечится это стандартно: частичная гидратация и island-архитектура (Astro, Qwik), streaming SSR, React Server Components, разумный code splitting и вынос всего некритичного в динамический импорт.

Семь ошибок, которые убивают JS-сайт в поиске

1. Ссылки без href

Самая массовая и самая дорогая ошибка. Конструкции вида <div onclick="navigate('/catalog')"> или <a onclick="..."> без href — для робота не ссылки вообще. Он их не видит, по ним не переходит, вес по ним не передаётся. Разработчику удобно, потому что роутер и так перехватит клик. SEO при этом умирает: сайт превращается в набор несвязанных страниц.

Правильно: всегда реальный <a href="/catalog"> с настоящим URL, а роутер перехватывает клик через preventDefault. В React Router — компонент Link, в Vue Router — router-link. Оба рендерят нормальный тег <a> с href. Это база для любой внутренней перелинковки сайта.

2. Роутинг на хэшах

URL вида /#/catalog/tovar — наследие раннего SPA. Всё, что после решётки, на сервер не передаётся вообще; для поисковика такие адреса — одна и та же страница. Схема «AJAX-crawling» с #! официально мертва много лет. Решение: History API, режим history в роутере, отдельные полноценные URL на каждую сущность.

3. Контент, который появляется только по клику

Табы «Описание / Характеристики / Отзывы», где содержимое вкладки подгружается при клике на неё. Робот не кликает. Он видит только первую вкладку. Всё описание товара, все характеристики, все отзывы — вне индекса.

Решение: рендерить весь контент в DOM сразу, а переключение вкладок делать через CSS (display: none). Скрытый CSS-ом контент индексируется — да, с потенциально меньшим весом, но индексируется. Контента, которого нет в DOM, для робота не существует. Это же касается аккордеонов и кнопок «Показать полностью».

4. Бесконечный скролл без пагинации

Товары подгружаются при прокрутке. Робот не скроллит — он получает первые 12 позиций из 500 и уходит. Остальной каталог недоступен.

Решение — гибрид: бесконечный скролл для пользователя плюс реальные страницы пагинации с href (?page=2, /page/2), доступные роботу. Плюс кнопка «Показать ещё», обёрнутая в ссылку. Плюс полный sitemap.xml со всеми товарами. Правильно построенная структура сайта для SEO здесь спасает больше, чем любые технические трюки.

5. Метатеги, которые проставляются на клиенте

Библиотеки вроде react-helmet в чистом SPA меняют title и description после исполнения JS. В исходном HTML на всех URL сайта висит одно и то же «Мой магазин». Google, скорее всего, обновит title после рендера. Яндекс — далеко не всегда. В выдаче получаем одинаковые сниппеты на сотнях страниц и провал по CTR.

6. Заблокированные в robots.txt скрипты

Наследие эпохи, когда «/static/ и /assets/ надо закрыть, чтобы не тратить краулинговый бюджет». Если робот не может скачать бандл — он не может отрендерить страницу. Ни один JS-файл, участвующий в отрисовке контента, не должен быть закрыт. То же касается API-эндпоинтов, к которым ходит фронтенд.

7. Soft 404 и подмена статусов

В SPA сервер на любой URL отдаёт index.html с кодом 200, а «страница не найдена» рисуется клиентским скриптом. Робот видит 200 и индексирует несуществующие страницы. То же с редиректами: JS-редирект через window.location робот отработает не всегда и с задержкой. Статусы и редиректы должны быть серверными. Эту и смежные проблемы мы разбираем в гайде по техническим ошибкам сайта.

Микроразметка и структурированные данные в JS-проектах

Отдельная боль. JSON-LD, вставленный скриптом после загрузки, — это разметка второй волны. Google её подхватит, Яндекс может проигнорировать. А расширенные сниппеты, рейтинги, хлебные крошки и цены в выдаче напрямую влияют на кликабельность.

Правило: JSON-LD должен присутствовать в исходном HTML. В Next.js это делается тривиально — вставкой script-тега с типом application/ld+json прямо в серверный рендер компонента. В Nuxt — через useHead. Проверять — всегда через «Проверку ответа сервера» в Вебмастере, а не через валидатор, который работает с отрендеренным DOM. Подробнее о том, какие типы разметки дают эффект, — в статье про микроразметку и SEO.

Краулинговый бюджет: почему JS-сайты обходятся хуже

Краулинговый бюджет — количество страниц, которые робот готов обойти за единицу времени. Для JS-сайта он расходуется в разы быстрее, потому что:

  • каждая страница требует не одного запроса, а десятков (HTML + бандлы + чанки + API + шрифты + картинки);
  • рендеринг — отдельная дорогая операция с собственной очередью;
  • ошибки и таймауты заставляют робота возвращаться повторно.

На каталоге в 50 тысяч товаров разница между SSR и клиентским рендерингом — это разница между «весь ассортимент в индексе за месяц» и «половина каталога не проиндексирована за год». Что делать:

  1. отдавать HTML с контентом сразу (SSR/SSG) — снимает потребность в рендеринге;
  2. агрессивно кешировать статику с длинными Cache-Control и хешами в именах файлов;
  3. резать бандл: code splitting по маршрутам, tree shaking, вынос вендоров;
  4. убирать мусорные URL из индекса — бесконечные комбинации фильтров, сортировки, UTM;
  5. держать актуальный sitemap.xml с lastmod;
  6. чинить 404 и цепочки редиректов.

Мобильная версия и JS: двойной риск

Индексация давно mobile-first: робот смотрит на мобильную версию. У JS-приложений на мобильных устройствах JS-бандл исполняется на слабом процессоре, по медленной сети, с ограниченной памятью. Если на десктопе гидратация занимает 300 мс, на бюджетном Android это может быть 3 секунды. Плюс частая ошибка: на мобильной версии часть контента прячут «чтобы не грузить» — и он выпадает из индекса вместе с ключевыми словами. Проверять мобильную версию нужно отдельно и с теми же процедурами, что и десктоп; общие принципы — в материале про мобильную оптимизацию сайта.

Как выбрать решение: короткая матрица

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

  • Контент меняется редко, страниц до нескольких тысяч (корпоративный сайт, блог, сайт услуг) → SSG. Дёшево, быстро, надёжно.
  • Контент динамический, важна актуальность (магазин, агрегатор, каталог с остатками) → SSR или SSR + ISR.
  • Есть готовое SPA, переписывать нельзя, трафик нужен вчерапререндер / динамический рендеринг как временная мера.
  • Личный кабинет, админка, интерфейсы под авторизациейчистый CSR. Эти страницы не должны индексироваться вообще, и SSR им не нужен.
  • Смешанный сайт (витрина + кабинет) → гибрид: публичная часть на SSR/SSG, приватная на CSR.

И главное правило, которое экономит бюджеты: дешевле заложить SSR на старте, чем мигрировать через год. Переезд работающего SPA на Next.js — это, по нашему опыту, от полутора до четырёх месяцев работы команды. Выбор фреймворка с SSR на этапе проектирования стоит ноль дополнительных часов.

Чек-лист внедрения и приёмки

Проходите по нему перед запуском и после каждого крупного релиза.

  1. В исходном HTML (Ctrl+U, не DevTools) присутствуют: H1, основной текст, цена/оффер, ссылки как <a href>.
  2. Title, description, canonical уникальны для каждого URL и присутствуют в серверном ответе.
  3. JSON-LD отдаётся сервером, а не вставляется скриптом.
  4. Роутинг на History API, без хэшей. Каждая сущность — свой URL.
  5. Все внутренние ссылки — теги <a> с реальным href, а не onclick на div.
  6. Контент табов, аккордеонов и спойлеров есть в DOM сразу, скрытие — через CSS.
  7. Пагинация существует и доступна роботу параллельно с бесконечным скроллом.
  8. 404 отдаёт код 404, редиректы — 301/302 на уровне сервера.
  9. robots.txt не блокирует ни один JS/CSS-файл и ни один API-эндпоинт, участвующий в отрисовке.
  10. API не отдаёт роботам 403/429 — проверено по логам.
  11. Сайт с отключённым JS показывает читаемый текст и рабочие ссылки.
  12. «Проверка ответа сервера» в Яндекс.Вебмастере возвращает полный контент.
  13. Точная фраза со страницы находится через site: в Яндексе и Google.
  14. Число страниц в индексе сопоставимо с числом URL в sitemap.xml.
  15. LCP, INP и CLS в зелёной зоне на мобильных, по полевым данным.
  16. Версия для робота и для пользователя идентичны по содержанию.

Отдельно рекомендую поставить этот чек-лист в регламент релизов. JS-проекты имеют неприятное свойство: SEO-регрессии приезжают вместе с обычными фичами, и рефакторинг роутинга может тихо выбить сайт из индекса. Регулярный SEO-аудит сайта ловит такие вещи до того, как просядет трафик.

Что делать, если сайт уже запущен и не индексируется

Порядок действий по приоритету — от самого дешёвого к самому дорогому:

  1. Неделя 1. Диагностика: исходный код против DOM, Вебмастер, логи, оператор site:. Фиксируем, какая доля страниц реально в индексе.
  2. Неделя 1–2. Быстрые победы, не требующие переписывания: открыть JS в robots.txt, заменить onclick-навигацию на <a href>, добавить пагинацию, вытащить контент табов в DOM, починить статусы ответов. Часто это даёт +20–40% страниц в индексе без единой строчки в архитектуре.
  3. Неделя 2–4. Пререндер или динамический рендеринг как временное решение. Трафик начинает восстанавливаться, пока готовится основное.
  4. Месяц 2–4. Миграция на SSR/SSG. Поэтапно: сначала шаблоны с наибольшим потенциалом трафика (категории, карточки), потом остальное.
  5. Постоянно. Мониторинг индексации в Вебмастере, контроль скорости, регламент проверки перед релизом.

Параллельно с технической частью имеет смысл заниматься внутренней оптимизацией сайта — семантикой, текстами, структурой. Технический фундамент без контента даёт индексацию, но не даёт позиций. А если сайт на JS уже собрал шлейф технических проблем, разумнее подключить техподдержку и доработку сайта, где правки вносит команда, понимающая и фронтенд, и требования поиска.

Вывод

JavaScript не мешает продвижению — мешает архитектура, спроектированная без учёта того, как работают роботы. React, Vue и Next.js прекрасно живут в топе Яндекса, если критичный контент приходит в исходном HTML, ссылки — это настоящие теги <a href>, метатеги задаются на сервере, а не в браузере, и каждый релиз проверяется по чек-листу. Это не вопрос выбора «SPA или SEO» — это вопрос выбора правильного режима рендеринга под конкретную задачу.

Сложность в том, что решение лежит на стыке компетенций: SEO-специалист обычно не знает, чем ISR отличается от streaming SSR, а фронтенд-разработчик не подозревает, что Яндекс может месяц не рендерить страницу. Именно на этом стыке теряются проекты. В SEO ПРОГРЕСС мы выводили в топ сайты на React, Vue и Angular — от лендингов до каталогов на десятки тысяч товаров — и умеем разговаривать с разработчиками на их языке, ставя задачи в терминах кода, а не пожеланий. Как это выглядит в цифрах, видно в наших кейсах. Если у вас сайт на JS-фреймворке и органика не растёт — напишите нам: проведём диагностику, покажем, что именно видит робот на ваших страницах, и составим план работ с понятными сроками и приоритетами.

Закажите SEO-продвижение в SEO ПРОГРЕСС

20 лет опыта, 250+ успешных кейсов. Бесплатный аудит и консультация.

Получить консультацию

Комментарии

dev_anton

Мы фронтендеры, нам всегда говорили «Google всё рендерит, не парься». Прочитал про вторую волну индексации и полез в логи — реально страницы висят по неделе до рендера. Спасибо, теперь есть чем аргументировать переезд на Next.js перед менеджментом.

Марина_К

А Яндекс сейчас вообще научился JS рендерить или всё ещё нет? Информация везде разная, кто-то пишет что научился, кто-то что нет.

Сергей

Пункт про ссылки без href — это боль. У нас вся навигация была на onClick с router.push. Робот видел ровно главную и больше ничего.

Admin

Сергей, классическая история. onClick + router.push визуально работает одинаково, но краулер по такому переходу не пойдёт — ему нужен href в разметке. В React-роутерах решается компонентом Link, который сам рендерит настоящий . Проверить просто: отключите JS в браузере и посмотрите, кликается ли меню.

Виктор

Отличный разбор, забрал чек-лист.

Ольга П.

Вопрос про динамический рендеринг. Если мы отдаём роботу пререндеренный HTML, а пользователю SPA — контент же по факту один и тот же. Где здесь клоакинг? Или его определяют формально по факту разной отдачи?

Иван_SEO

История провала. Внедрили SSR на Nuxt, обрадовались, а трафик не вырос. Оказалось, гидратация ломала часть блоков и в консоли сыпались ошибки — контент из HTML перетирался пустым. Полгода искали, нашли случайно.

Артём

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

maks_88

У нас интернет-магазин на Vue, 40к товаров. SSR не потянем по бюджету, SSG на таком объёме собирается вечность. Пререндеринг реально спасёт или это костыль на год?

Admin

maks_88, для 40 тысяч страниц пререндеринг — рабочее решение, а не костыль, если у вас карточки меняются не каждый час. Проблема будет одна: актуальность кэша при смене цен и наличия. Смотрите в сторону ISR в Nuxt/Next — это фактически SSG с фоновой перегенерацией по таймеру, и он закрывает ровно ваш кейс без полного пересбора.

Екатерина

Про метатеги на клиенте: у нас title проставлялся через vue-meta, в исходном коде везде был одинаковый. В выдаче — каша из одинаковых сниппетов. Убрали на сервер, за месяц выправилось.

Роман

Новичок. А как вообще посмотреть «исходный код против DOM»? Это Ctrl+U и F12 или есть что-то более взрослое?

Admin

Роман, да, для быстрой проверки ровно это: Ctrl+U — то, что пришло с сервера, F12 → Elements — то, что собрал JS. Если контент есть только во втором, робот его может не увидеть. Для массовой проверки запустите Screaming Frog в двух режимах, с рендерингом и без, и сравните выгрузки — сразу видно, какие страницы «пустые» без JS.

Наталья

Бесконечный скролл без пагинации — прямо про наш каталог. Товары с 30-го и дальше вообще никогда не индексировались, а мы искали причину в текстах.

Павел

Про robots.txt и заблокированные скрипты — до сих пор встречаю сайты, где /assets/ закрыт целиком «чтобы не тратить бюджет». Люди сами себе рендер ломают.

Юлия

Спасибо за матрицу выбора решения, наконец-то без «это зависит». Утащила в презентацию для разработчиков.

Дмитрий

Спорный момент про краулинговый бюджет на JS-сайтах. Если сайт небольшой, страниц 200, бюджет ведь не проблема? Или рендер всё равно всё замедляет настолько, что это чувствуется?

Admin

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

Анна

А что делать с soft 404? У нас несуществующий товар отдаёт 200 и пустой шаблон, разработчик говорит «в SPA иначе никак».

Admin

Анна, «иначе никак» — это неправда. При SSR сервер прекрасно отдаёт 404 до рендера страницы. В Next.js это notFound(), в Nuxt — createError со statusCode 404. Если у вас чистый клиентский SPA, то да, статус придётся выставлять на уровне сервера/прокси по списку валидных URL — но это и есть аргумент за SSR.

Оставить комментарий

Спасибо! Ваш комментарий отправлен на модерацию и появится после проверки.