Статьи о SEO-продвижении

SEO для JavaScript-сайта: как проверить рендеринг, индексацию и видимость контента

SEO для JavaScript-сайта: как проверить рендеринг, индексацию и видимость контента

SEOProvision

Карточка товара полностью открывается в браузере: видны название, цена, характеристики и кнопка покупки. Но если посмотреть ответ сервера до выполнения JavaScript, внутри окажутся пустой контейнер и несколько подключённых файлов. Для SEO это не приговор и не доказательство проблемы. Это повод сравнить три состояния одного URL и найти точку, где значимый контент появляется — или не появляется.

Проверка JavaScript-сайта начинается не со спора «SSR или CSR». Сначала сохраните исходный HTML, затем DOM после выполнения кода и отдельно представление страницы для поискового робота. Если текст есть во всех трёх состояниях, причина слабой видимости лежит дальше. Если он пропал на одном переходе, область поиска уже заметно сузилась.

Робот и пользователь могут получать разные документы

Браузер показывает итоговую картинку после целой цепочки действий: получает HTML от сервера, загружает код, обращается к API, строит DOM и применяет стили. Пользователь видит конец этой цепочки. Индексирующий робот тоже способен выполнять JavaScript, но доступность ресурса, время ответа и ошибки кода могут изменить результат. Успешное открытие описывает только один сеанс в одном браузере.

Официальная справка Яндекс Вебмастера об индексировании AJAX-сайтов прямо указывает: робот сканирует исходные URL и исполняет JavaScript на них. Это важная граница. Поиску не нужна отдельная тайная версия страницы, однако исходный адрес, его код ответа и ресурсы должны оставаться доступными. Ссылки на другие документы должны существовать как настоящие адреса в атрибуте href, а не только как обработчики клика.

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

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

Полезный вопрос звучит не «индексирует ли Яндекс JavaScript вообще», а «какую часть ответа конкретного URL робот получает после выполнения кода». Он заставляет проверить документ, а не обсуждать технологию в целом. Заодно становится ясно, какой контент должен быть доступен сразу, а какой динамический блок допустимо загружать позже. Для индексации важен фактический доступный документ, а не название технологии в презентации проекта.

СостояниеЧто оно доказываетЧего не доказывает
Ответ сервераКод ответа, исходный HTML, метаданные и ссылки до выполнения кодаЧто скрипты завершатся успешно
DOM браузераРезультат выполнения кода в вашей сессииЧто робот получил то же самое
Рендеринг для роботаЧто увидел выбранный робот в момент проверкиЧто страница уже находится в поиске и ранжируется

HTML до выполнения JavaScript задаёт исходную точку

Откройте проблемный URL в новой сессии и сохраните именно ответ сервера, а не дерево Elements после загрузки. В браузере это можно сделать через вкладку Network: выберите запрос типа document и откройте Response. Команда curl или серверный дамп подойдут не хуже, если запрос повторяет нужное устройство и не проходит через авторизованный кабинет.

В исходном HTML ищите не максимальный объём текста, а минимально полезный документ. У него есть понятный title, description, canonical, главный текстовый ориентир, ссылки на ключевые разделы и данные, без которых страница теряет смысл. Если сервер отдаёт корректный каркас, а второстепенные элементы достраиваются позже, риск ниже, чем у пустого div с единственным скриптом.

  • HTTP-код документа равен ожидаемому, обычно 200 для рабочей страницы;
  • title и description относятся к текущему URL, а не повторяют общий шаблон приложения;
  • canonical указывает на выбранный адрес и не меняется после загрузки;
  • основной текст не зависит от согласия на cookies, геолокации или входа в аккаунт;
  • ссылки на категории, карточки и статьи записаны в href;
  • файлы JavaScript и endpoint с данными доступны без пользовательского токена.

Особенно внимательно проверьте код ответа. Приложение может отрисовать красивую страницу «товар не найден», хотя сервер вернул 200. Бывает и обратное: пользователю показывается рабочий экран из клиентского кэша, а новый запрос к документу отвечает 500. Робот начинает с ответа сервера, поэтому визуальная оболочка не исправляет неверный статус.

Сохраните файл как «состояние A» и подпишите время проверки. Без этого команда быстро начинает сравнивать разные версии: разработчик смотрит исправленный стенд, SEO-специалист — продакшен из кэша, а Вебмастер хранит результат предыдущего обхода. Один timestamp и один полный URL снимают половину подобных споров.

Сравнение HTML и DOM локализует пропажу

Теперь дайте странице полностью загрузиться и сохраните DOM из панели Elements. Это «состояние B». Не ограничивайтесь скриншотом: картинка не показывает, существует ли текст как текст, есть ли у ссылки href и какой canonical остался в head. Сравнение должно идти по тем элементам, которые несут смысл и задают маршрут.

Трассировка одного URL: три состояния страницы

Контрольный элементИсходный HTMLDOM браузераРендеринг робота
Название товараПустой контейнерЕсть: «Кофемолка M7»Есть
ЦенаНетЕсть после запроса /api/product/77Нет
Ссылка на категориюКнопка без hrefПереход через onClickАдрес не обнаружен
Canonical/catalog/item-77/catalog/item-77/catalog/item-77
Код документа200200200

В этом примере робот получил название, поэтому утверждение «JavaScript вообще не рендерится» неверно. Пропали цена и ссылка. У них разные причины: цена зависит от отдельного запроса данных, а категория реализована не ссылкой, а событием интерфейса. Один общий тикет «починить JS SEO» только смешает две задачи.

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

Для метаданных сохраните конечные значения после выполнения кода. Так сравнение остаётся предметным и не превращается в неопределённое ощущение различий между страницами.

Третье состояние получите в Яндекс Вебмастере через проверку страницы и рендеринг JavaScript. Выберите подходящий тип устройства и тот же URL. Сохраните результат рядом с первыми двумя файлами. Если инструмент сообщает об ошибке ресурса, выпишите конкретный адрес, статус и момент возникновения вместо общего вывода о несовместимости SPA с поиском.

Трассировка полезна ещё и после исправления. Она задаёт готовый критерий приёмки: в колонке робота должны появиться цена и обычная ссылка, а значения title и canonical не должны измениться случайно. Задача закрывается не после фразы разработчика «сделали SSR», а после повторяемого совпадения важных элементов.

Сетевые запросы показывают источник содержимого

Если DOM браузера полный, а рендеринг робота пустой или обрывается, откройте сетевой журнал загрузки. Найдите запрос, который принёс исчезнувший фрагмент. Обычно это fetch или XHR к API, реже — динамически подключаемый JavaScript-файл.

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

Частая причина — различие контекста. API возвращает данные только после получения cookie, заголовка авторизации или токена из localStorage. В обычной сессии всё работает, потому что пользователь уже посещал сайт.

Чистый робот получает 401, пустой массив или региональную заглушку. Для публичного SEO-контента такой контракт ненадёжен: значимый ответ не должен зависеть от персонального состояния.

Другая причина — задержка. Приложение сначала загружает крупный bundle, затем ждёт конфигурацию, после неё делает запрос к каталогу и только в конце вставляет текст. Каждый этап может быть успешным отдельно, но вся цепочка остаётся хрупкой. Уберите необязательную последовательность: отдайте критичный контент с сервера или загрузите его прямым запросом без каскада зависимостей.

НаблюдениеВероятное место сбояЧто проверить
HTML пустой, DOM полный, робот полныйСбоя видимости не обнаруженоИндексацию, canonical, интент и качество страницы
HTML пустой, DOM полный, робот пустойВыполнение кода или запрос данныхОшибки консоли, статусы API, доступ без cookie
HTML полный, DOM теряет текстГидратация или условный рендерСовпадение серверных и клиентских данных
HTML и DOM полные, ссылки нет у роботаНавигация через событиеНастоящий элемент a с href
Документ отвечает 5xxСервер или CDNЛоги, стабильность ответа, правила защиты

Проверьте также robots.txt и защитные сервисы. Запрет ресурса, challenge от CDN или агрессивный rate limit способен оставить приложение без данных именно для автоматического клиента. Не ослабляйте защиту вслепую: сначала сопоставьте время проверки с серверными логами и убедитесь, какой запрос был заблокирован.

После нахождения запроса сформулируйте дефект одной строкой: «публичная цена карточки /catalog/item-77 появляется только после ответа /api/product/77, который без cookie возвращает 401». Такая формулировка содержит объект, условие и наблюдаемый результат. Разработчику не приходится угадывать, что именно означает «плохой рендеринг».

SSR, CSR и гидратация создают разные риски

CSR строит содержимое в браузере. Он подходит для интерфейсов, где большая часть данных персональна или не предназначена для поиска. Проблема на публичной посадочной возникает, когда без выполнения кода документ не объясняет тему и не содержит ссылочного пути. Это не запрет технологии, а требование к результату конкретного URL.

SSR формирует HTML на сервере для каждого запроса. Он сокращает разрыв между исходным документом и видимым экраном, но сам по себе не гарантирует качество. Сервер может отдать пустую версию при таймауте API, неверный canonical или статус 200 для ошибки. SSR следует принимать по содержимому ответа, а не по названию режима в конфигурации фреймворка.

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

Гидратация соединяет готовый серверный HTML с клиентской логикой. Если данные сервера и браузера расходятся, приложение может перерисовать участок и временно либо окончательно удалить текст. Симптом виден в трассировке: строка есть в состоянии A и исчезает в состоянии B. Исправление ищут в расхождении данных и условий рендера, а не в поисковой системе.

  • Если важного текста нет уже в HTML и он часто пропадает у робота, перенесите его в серверный или статический слой.
  • Если HTML полный, но DOM удаляет элементы, разберите гидратацию и условные ветви клиента.
  • Если проблема только в ссылках, сохраните интерфейс, но выдайте настоящие a href.
  • Если API нестабилен, сократите цепочку запросов и определите безопасное состояние отказа.
  • Если все три состояния совпадают, не меняйте архитектуру без другой доказанной причины.

Для крупного проекта полезно выбрать несколько эталонных URL: категорию, карточку, статью и страницу услуги. Их трассировка становится регрессионным тестом после релизов. Если выстраивается комплексное SEO-продвижение сайта, такая проверка связывает технический релиз с видимостью конкретных документов, а не с общим отчётом «JavaScript включён».

Вопросы и ответы

Достаточно ли пререндерить только основной текст?

Основной текст — хорошая отправная точка, но вместе с ним проверьте title, description, canonical, код ответа и обычные ссылки на соседние страницы. Пререндеренный абзац не компенсирует навигацию без href или ошибочный статус документа.

Учитывает ли робот ссылки, созданные обработчиком клика?

Для надёжного обнаружения адреса используйте элемент a с заполненным href. Кнопка, которая меняет экран только через onClick, удобна приложению, но не создаёт обычную HTML-ссылку для обхода.

Нужно ли отдельно проверять мобильную версию рендеринга?

Да, если сервер, CDN или приложение меняют ответ по устройству. Сравните одну и ту же контрольную фразу, ссылки и метаданные; различие интерфейса допустимо, исчезновение значимого содержания требует объяснения.

Контрольный тест одной посадочной

Выберите URL, на котором уже воспроизводится проблема. Зафиксируйте устройство, время и чистую сессию. Сохраните ответ document как HTML, затем DOM после полной загрузки и результат рендеринга в Вебмастере. В каждом файле найдите одну и ту же фразу, одну ссылку и конечный canonical.

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

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

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

На многоязычном или региональном сайте проведите тот же опыт без автоматического перенаправления по IP. Робот должен получить самостоятельный URL выбранной версии, а не общий экран выбора города. Запишите, какие заголовки запроса меняют ответ, и убедитесь, что canonical и внутренние ссылки остаются в пределах нужной версии. Иначе один сеанс покажет исправный HTML, а другой уведёт проверку на адрес с иным содержимым.

Не смешивайте кэш с рендерингом. После релиза CDN может продолжать отдавать старый HTML, в то время как JavaScript уже загружен новый. Получается несовместимая пара: серверный каркас одной версии и клиентская логика другой.

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

Для массовой проверки не требуется сохранять полный DOM тысяч страниц. Возьмите по одному представителю каждого шаблона и определите три коротких признака: обязательная фраза, ссылка и метаданные. Автоматический тест может сигнализировать об их исчезновении, но разбор причины всё равно выполняется на конкретном URL. Так мониторинг замечает регрессию, а трассировка объясняет её.

Сохранённая трассировка полезнее скриншота «до и после». По ней видно, что именно изменилось в документе, какой механизм был причиной и как проверить регрессию после следующего релиза. Так JavaScript SEO превращается из общего опасения в обычную инженерную задачу с входом, наблюдением и критерием приёмки.