Single Page Application (SPA) — веб-приложение, которое после первой загрузки подменяет контент в браузере через JavaScript, не запрашивая у сервера новые HTML-страницы. Архитектура удобна для пользователя, но конфликтует с тем, как поисковые роботы видят сайт: в исходном HTML часто нет ни текста, ни ссылок, ни мета-тегов. Этот материал — практическое руководство о том, как сделать SPA индексируемым в Яндексе и Google.
В чём суть проблемы SPA для поиска
Классический сайт отдаёт роботу готовый HTML — он сразу видит весь контент. SPA на React, Vue или Angular отдаёт почти пустой <div id="root"></div> и бандл JavaScript; контент появляется лишь после того, как браузер выполнит скрипты и отрисует DOM. Это и есть client-side rendering (CSR). Краулер же не работает как браузер: он скачивает HTML по коду 200, ставит страницу в очередь на рендеринг и только потом выполняет JavaScript. Если контент не отрисовался или скрипт упал, в индекс попадёт пустая страница.
Различие двух систем принципиально. Google умеет рендерить JavaScript на движке Chromium, но рендеринг — отложенная фаза индексации: тратит crawl budget и не гарантирует полноты. Яндекс рендерит JS хуже и менее предсказуемо: для коммерческого проекта ставка на «робот сам всё отрендерит» — риск выпадения из индекса. Вывод: контент, важный для ранжирования, должен приходить роботу уже в HTML.
Способы рендеринга: что выбрать
Есть четыре базовых подхода — выбор зависит от динамичности контента и ресурсов на бэкенд.
| Подход | Что отдаётся роботу | Кому подходит | Минусы |
|---|---|---|---|
| CSR (клиентский) | Пустой HTML + JS | Закрытые админки, кабинеты | Плохая индексация, не для SEO |
| SSR (серверный) | Готовый HTML с сервера | Каталоги, маркетплейсы, динамика | Нужен Node-сервер, нагрузка |
| SSG (статика) | Заранее собранный HTML | Блог, лендинги, документация | Не подходит для частых обновлений |
| Prerendering | Снимок HTML для ботов | Готовый SPA без переписывания | Контент «замораживается» на момент снимка |
Для коммерческого SPA выбирают SSR (Next.js, Nuxt, Angular Universal) на динамичных каталогах и SSG (с гибридом ISR в Next.js) на редко меняющемся контенте. Prerendering (Prerender.io, Rendertron, Puppeteer) спасает без переписывания приложения: роботам по User-Agent отдаётся заранее снятый HTML, пользователям — обычный SPA.
⚠️ РИСК: предрендеринг по User-Agent — пограничная техника. Если боту и человеку отдаётся разный по смыслу контент, это клоакинг, за который Яндекс и Google накладывают санкции. Безопасно — когда HTML для бота и DOM для человека идентичны по содержанию.
Маршрутизация и URL: каждое состояние — отдельный адрес
Главная SEO-ошибка ранних SPA — навигация через хэш: site.ru/#/catalog/divany. Всё, что после #, поиск игнорирует, и весь сайт схлопывается в один URL. Современные фреймворки используют History API (pushState) и дают настоящие ЧПУ-адреса site.ru/catalog/divany. Требования для индексации:
- Каждая значимая «страница» SPA = уникальный URL с кодом 200; прямой заход на
/catalog/divany(без перехода с главной) отдаёт корректный HTML, а не 404. - Несуществующий маршрут возвращает честный код 404 или 410, а не «мягкую» 404 со статусом 200.
- Канонический адрес каждой страницы зафиксирован в
rel=canonical.
Подробно о требованиях к адресам — в материале про структуру URL и SEO-friendly адреса.
Мета-теги, которые меняются вместе с маршрутом
В SPA <title>, <meta name="description"> и Open Graph должны переписываться при каждой смене маршрута — иначе все страницы унаследуют мета-теги главной и получат одинаковые сниппеты, что ломает релевантность. В React это решает react-helmet или Metadata API в Next.js, в Vue — useHead. Чек-лист on-page для каждого маршрута:
- Уникальный Title (50–65 символов, главный запрос в начале).
- Уникальный Description (140–160 символов с призывом к действию).
- Один H1 на страницу с главным запросом.
- Канонический URL и Open Graph для соцсетей.
- Schema.org через JSON-LD (Product, Article, BreadcrumbList) — обязательно в серверном HTML или предрендере, иначе робот её не увидит. Подробнее — в руководстве по structured data и Schema.org.
Скорость, Core Web Vitals и crawl budget
SPA грузит крупный JS-бандл, и без оптимизации страдают метрики ранжирования. Целевые значения Core Web Vitals: LCP < 2,5 с, INP < 200 мс, CLS < 0,1. JS-нагрузка бьёт по INP и LCP сильнее всего. Помогают code splitting, tree shaking, отказ от тяжёлых библиотек, ленивая загрузка изображений вне первого экрана. SSR/SSG сами по себе улучшают LCP, потому что контент виден до выполнения JS. Глубже — в материале про Core Web Vitals.
Отдельная тема — crawl budget: чем больше страниц робот получает готовым HTML, тем эффективнее тратится бюджет сканирования. Это критично для каталогов на десятки тысяч URL.
Мини-пример: каталог мебели на React
Интернет-магазин на чистом CSR-React: в коде только <div id="root">, весь каталог рисуется в браузере. В Яндекс.Вебмастере карточки висели как «малоценные/пустые», в индекс попадала только главная. Что сделали:
- Перевели проект на Next.js с SSR для карточек и SSG для статических разделов.
- Заменили хэш-роутинг на History API — каждая категория и карточка получили ЧПУ с кодом 200.
- Подключили динамические мета-теги и JSON-LD (Product, BreadcrumbList) в серверный HTML.
- Сгенерировали
sitemap.xmlи отправили в Яндекс.Вебмастер и Google Search Console. - Проверили рендеринг инструментами «Проверка страницы» в Вебмастере и «Проверка URL» в GSC.
После проверки страницы каталога стали отдаваться роботу с полным контентом, статус «пустая страница» ушёл. Цифры роста трафика не приводим — они зависят от семантики и конкуренции ниши, а не только от внедрения SSR.
Типичные ошибки
- Хэш-роутинг (
/#/page) — поиск не видит маршруты после#. Нужен History API. - Soft 404 — несуществующий маршрут отдаёт код 200 вместо 404/410.
- Один комплект мета-тегов на всё приложение — дубли Title и Description.
- JSON-LD только на клиенте — разметка не попадает в HTML, рич-сниппеты не работают.
- Блокировка JS и CSS в robots.txt — робот не отрендерит страницу даже там, где мог бы.
О настройке доступа роботов — в материале про robots.txt.
FAQ
Индексирует ли Яндекс JavaScript-сайты?
Частично и непредсказуемо — хуже, чем Google. Для коммерческих SPA нужен серверный рендеринг или предрендеринг, а не расчёт на робота.
SSR или SSG — что выбрать?
SSG — для редко меняющегося контента (блог, лендинги, документация). SSR — для динамики (каталоги, маркетплейсы). Гибрид ISR в Next.js закрывает промежуточные случаи.
Является ли предрендеринг для ботов клоакингом?
Нет, если боту и пользователю отдаётся одинаковый по смыслу контент. Клоакинг — это подмена смысла ради манипуляции выдачей, за это следуют санкции.
Как проверить, что робот видит контент SPA?
«Проверка страницы» в Яндекс.Вебмастере и «Проверка URL» в Google Search Console показывают отрендеренный HTML глазами робота. Дополнительно — просмотр исходного кода (Ctrl+U): если текста там нет, его не видит и краулер без рендеринга.
Материал подготовлен экспертами Chrome Media — агентства SEO-продвижения и технической оптимизации сайтов в Яндексе и Google.

Добавить комментарий