Миф о слепом роботе, который не видит контент одностраничного приложения, живёт уже второе десятилетие. Реальность скучнее и интереснее: Googlebot давно исполняет JavaScript на evergreen-версии Chromium и видит почти всё, что видит пользователь. Другое дело, что видит он это второй очередью, платит за рендеринг временем и ресурсами, а заодно откладывает обнаружение ссылок. Для владельца SPA это значит, что контент рано или поздно попадёт в индекс, но "рано" и "поздно" на крупных проектах отличаются неделями трафика. Разберём, как Googlebot обрабатывает JavaScript сегодня, где клиентский рендеринг ломается предсказуемо и в каких случаях SSR через Next.js окупается.
Три этапа обработки JavaScript страницы и очередь на рендеринг
Google обрабатывает страницы на JavaScript в три шага: обход, рендеринг, индексация. На первом шаге робот запрашивает URL и читает исходный HTML, извлекая ссылки из атрибутов href. Страницы классических сайтов на этом шаге уже готовы: контент лежит в ответе сервера. У одностраничного приложения с моделью app shell в исходном HTML обычно пусто, только каркас и ссылки на бандлы. Контент появляется после рендеринга.
Все страницы с кодом 200 попадают в очередь на рендеринг, если мета robots не запрещает индексацию. По формулировке из документации Google страница может прождать в этой очереди несколько секунд, а может и дольше: гарантированного срока нет. Затем headless Chromium исполняет скрипты, и полученный HTML разбирается повторно, из него извлекаются новые ссылки, и они отправляются в очередь обхода. Отсюда главное следствие для SPA: адреса, которые существуют только после рендеринга, находятся с задержкой в целый цикл "обход, очередь, рендеринг, разбор".
Важная деталь про robots.txt: JavaScript с заблокированных файлов и на заблокированных страницах Google не исполняет. Если robots.txt закрывает каталог со скриптами или стилями, рендеринг сломается, и робот увидит пустой каркас вместо витрины.
Отдельно про очередь. Рендеринг выполняет сервис WRS на базе Chromium, и ресурс у него не бесконечный: на проектах со слабым спросом страницы ждут дольше, на живых каталогах очередь движется быстро. История вопроса объясняет живучесть мифа: до мая 2019 года Googlebot работал на древней версии Chrome 41, и вторая волна индексации на крупных сайтах растягивалась на дни и недели. После перехода на evergreen-модель рендеринг чаще завершается за секунды и минуты, но порядок "сначала обход, потом рендеринг" никуда не делся. Для краулингового бюджета рендеринг тоже не бесплатен: страницы, которые нужно отрисовывать, обходятся системе дороже простых HTML-документов, и на сайтах с миллионами URL это заметно по скорости обновления индекса.
Возможности Googlebot в современном JavaScript и рамки совместимости
Робот Google работает на evergreen-версии Chromium, той же, что и свежий Chrome, и номер версии в user agent растёт вместе с браузером. Поддержка современного синтаксиса давно не проблема: стрелочные функции, модули и async await исполняются штатно. Проблемы начинаются на стыках. Часть браузерных API Google не поддерживает, и код стоит писать с feature detection и полифиллами, ровно как для старых браузеров, у которых нет свежих возможностей.
С мета-тегами картина двоякая. Title и meta description менять скриптом можно, система читает итоговое состояние страницы. С canonical наоборот: если адрес уже прописан в исходном HTML, JavaScript не должен подменять его другим значением. Подмена каноника скриптом выглядит для поисковой системы как конфликт версий, и предсказать выбранного победителя заранее нельзя.
Отдельный класс проблем - контент, который появляется только после действий пользователя. Робот не нажимает кнопки, не прокручивает ленту до конца и не раскрывает аккордеоны: функции, привязанные к событиям пользователя, не вызываются. Всё, что важно для поиска, должно существовать без клика и скролла. Типичные кандидаты на проверку - сервис-воркеры, WebGL, IndexedDB и локальное хранилище: что-то из этого робот поддерживает частично, что-то игнорирует. Посмотреть на страницу глазами робота можно без лаборатории: инструмент проверки URL в Search Console отдаёт и исходный, и отрендеренный HTML со скриншотом. Разница между ними - готовый аудит клиентского кода: если в отрендеренной версии появились заголовки, текст и ссылки, значит рендеринг отработал. Если нет - ищите заблокированные файлы и падения скриптов.
Типичные отказы одностраничного приложения и рабочие заглушки
Самый дорогой баг SPA - soft 404. Клиентский роутинг отвечает кодом 200 на любой адрес, а на несуществующие товары приложение рисует заглушку "ничего не найдено". Для пользователя это норм, для робота - засорённый индекс и обход страниц, которых нет. Google прямо советует два рабочих приёма. Первый - перенаправлять скриптом на адрес, который отвечает честным кодом 404:
fetch("/api/products/" + productId)
.then(response => response.json())
.then(product => {
if (product.exists) {
showProductDetails(product);
} else {
window.location.href = "/not-found";
}
});
Второй - добавлять на страницу ошибки мету robots noindex:
const meta = document.createElement("meta");
meta.name = "robots";
meta.content = "noindex";
document.head.appendChild(meta);
Второй по частоте отказ - ленивая навигация. Ссылки через обработчики кликов без честных href работают для людей и невидимы для робота на первом проходе. Третий - ленты, построенные только на прокрутке: без реальных адресов у порций контента робот не найдёт хвост списка. Заголовки, собираемые скриптом, тоже опаздывают: в выдаче до рендеринга висит каркасный title, и сниппет страдает первым. Ещё две ошибки из той же серии. Мета robots и разметка JSON-LD, добавленные скриптом, учитываются: Google читает итоговый DOM, но при условии, что страница дошла до рендеринга и скрипты не упали. Проверяется это тем же инструментом проверки URL - если в отрендеренном HTML нет ни мет, ни текста, робот их тоже не увидит.
Динамический пререндеринг как временная заглушка для роботов
Когда SSR встроить нельзя - старая платформа, магазин на коробочном движке, срочный фикс на выходные, - выручает динамический пререндеринг: сервер распознаёт робота по user agent и отдаёт ему заранее собранный HTML, а людям - живое приложение. Готовые сервисы вроде Prerender.io или самописная прослойка на Express справляются за пару дней. Схема рабочая, Google её понимает и описывает как обходной путь, но с важной оговоркой из документации: это временное решение, а не архитектура. Поддерживать два контура - рендер для роботов и приложение для людей - дорого, расхождения копятся, и рано или поздно кэш пререндера перестаёт поспевать за приложением. Честный SSR или статика закрывают задачу один раз и для всех.
SSR через Next.js и что версия 16 меняет для SEO
Аргумент за SSR не в том, что Google не умеет рендерить, а в том, что готовый HTML дешевле и надёжнее. Серверный рендеринг убирает вторую очередь: робот получает контент и ссылки в первом ответе, как у классического сайта. Пользователь получает то же самое - быструю первую отрисовку без ожидания гидратации.
Линейка Next.js закрывает весь спектр задач. Next.js 16, вышедшая 21 октября 2025 года, перевернула модель кэширования: Cache Components сделали динамическое выполнение кода по умолчанию, а кэш - опциональным через директиву "use cache". Частичный пререндеринг PPR, впервые показанный в 2023 году, доведён до рабочего состояния: страница отдаёт статичную оболочку мгновенно, а динамические вставки догружаются через Suspense. Для SEO это лучшее из миров - HTML с контентом в первом ответе при живых данных внутри.
Отдельная строка в этой истории - серверные компоненты: App Router, появившийся в Next.js 13 в 2022 году, довёл идею React Server Components до продакшена. Часть компонентов вообще не попадает в клиентский бандл, они отрисовываются на сервере и приезжают в браузер готовым HTML. Для страницы товара это значит меньше кода на клиенте, быстрее гидратация и лучшие шансы уложиться в INP.
Сборка ускорилась: Turbopack стал бандлером по умолчанию и собирает проекты быстрее в 2-5 раз, Fast Refresh ускорился до 10 раз. Middleware переехал в отдельный файл-прослойку на Node.js-рантайме. React обновлён до версии 19.2, React Compiler стабилен и снимает часть ручной мемоизации. Для точечных обновлений кэша появились функции updateTag() и revalidateTag(): товар закончился, тег обновился, страница пересобралась без полного деплоя. Внутри одного проекта режимы смешиваются: лендинги и страницы брендов уходят в чистую статику, разделы с живыми ценами рендерятся на сервере, а контент между этими полюсами живёт на ISR с перепроверкой по расписанию. Выбор режима - не вопрос веры, а вопрос того, как часто меняются цифры на странице и сколько таких страниц на сайте.
Цена клиентского рендеринга в Core Web Vitals и повторном обходе
Клиентский код платит дважды: роботу - второй очередью, пользователям - гидратацией. Core Web Vitals считают по трём метрикам: LCP укладывается в 2.5 секунды, INP - в 200 миллисекунд, CLS - в 0.1. Тяжёлый бандл блокирует главный поток, и интерактивность запаздывает: INP у SPA с неоптимизированной гидратацией регулярно проваливается на мобильных. Серверный рендеринг отдаёт текст и ссылки сразу, а гидратацию можно расставить по приоритетам и растянуть во времени.
Есть и краулинговая цена. Рендеринг каждой страницы требует ресурсов у самой системы Google, и очередь на слабо востребованных проектах движется медленнее. Плюс повторные визиты: свежий контент в отрендеренном HTML робот заметит не раньше следующего цикла. Статика и SSR от чужой очереди не зависят - обновление видно при первом же обходе. Замерять себя стоит по полевым данным реальных пользователей из отчёта Core Web Vitals: лабораторные тесты годятся для отладки, но решения Google принимает по 75-му процентилю сессий на мобильных за 28 дней. SPA с тяжёлой гидратацией в лаборатории может выглядеть прилично и проваливаться в поле именно на медленных устройствах, которых в реальном трафике большинство. Третье место, где одностраничное приложение теряет метрики, - сторонние скрипты: аналитика, чаты и тег-менеджеры встают в очередь на главный поток и догружаются поверх гидратации. В панели производительности браузера такие пики видны сразу, и выносить тяжёлое в веб-воркеры или откладывать после первого взаимодействия - стандартная часть настройки SPA.
Когда клиентского кода достаточно и порядок проверки SPA
У чистого клиента остаются легальные ниши: прототипы, внутренние панели, контент за логином, сайты без амбиций в поиске. Для публичного контента Google прямо рекомендует серверный или предварительный рендеринг, и не потому что не умеет сам, а потому что так быстрее для людей и роботов, и далеко не каждый обходчик вообще исполняет JavaScript. Стоит помнить и про остальных роботов: агрегаторы товаров, парсеры цен и обходчики большинства сервисов скрипты не запускают в принципе. Сайт, живущий только на клиенте, для них - пустой каркас, и если магазин кормит партнёрские площадки готовым HTML, клиентский рендеринг ломает эти интеграции тихо и незаметно.
Проверка приложения перед выкаткой занимает пять шагов:
- открыть исходный HTML страницы без JavaScript и убедиться, что контент и ссылки видны в ответе сервера;
- сравнить исходный HTML и DOM после рендеринга в браузере с заблокированными внешними запросами;
- проверить адрес инструментом проверки URL в Search Console и изучить отрендеренный HTML;
- убедиться, что страницы ошибок отдают честный код ответа или мету robots noindex;
- свериться с логами сервера и увидеть, запрашивает ли Googlebot бандлы и приходит ли на второй визит.
Если все шаги чистые, а позиции всё равно не растут, проблема не в рендеринге - ищите её в контенте и внутренних ссылках. JavaScript перестал быть оправданием: система Google умеет почти всё, что умеет браузер, и спрашивает с одностраничных приложений по тем же правилам, что и с классических сайтов. Вопрос лишь в том, готовы ли вы ждать второй очереди или предпочитаете отдать роботу готовый HTML с первым ответом.