SEO одностраничных приложений: почему SPA не ранжируются, как это исправляют SSR, статическая генерация и пререндеринг и как сделать приложение читаемым для AI-краулеров.

Коротко
одностраничное приложение (SPA) загружает одну HTML-оболочку и строит каждое представление с помощью JavaScript в браузере. Google умеет рендерить JavaScript, но рендеринг откладывается и ненадежен, а краулеры ChatGPT, Claude и Perplexity не выполняют его вовсе. Чтобы ранжироваться и цитироваться, каждому представлению SPA нужны собственный URL, настоящая ссылка с href, уникальные title и описание, правильный код статуса и, главное, основной контент в HTML, который отправляет сервер, через серверный рендеринг, статическую генерацию или пререндеринг.
Хотите узнать больше? Спросите
SEO одностраничных приложений это набор приемов, которые делают приложение на JavaScript, написанное на React, Vue, Angular или Svelte, таким же простым для сканирования, как классический сайт. Проблема хорошо задокументирована: в своих основах JavaScript SEO Google объясняет, что обрабатывает страницы на JavaScript в три этапа (сканирование, рендеринг, индексация), и каждая слабость SPA находится где-то в этом конвейере. Это руководство посвящено SPA, а о JavaScript-сайтах в целом читайте наше руководство по JavaScript SEO.
Традиционный сайт возвращает полный HTML-документ для каждого URL. SPA возвращает почти один и тот же документ для каждого URL: пустой <div id="root">, несколько мета-тегов и большой пакет JavaScript. Браузер загружает пакет, обращается к API, а затем рисует страницу. Когда посетитель нажимает ссылку, JavaScript подменяет контент без перезагрузки.
Для человека с быстрым телефоном результат ощущается мгновенным. Для краулера первый ответ это пустая оболочка: ни заголовка, ни текста, ни ссылок. Все зависит от того, выполняет ли бот JavaScript и когда. Этот единственный факт объясняет большинство проблем SEO у SPA:
/#/pricing), а часть после # никогда не отправляется на сервер, поэтому все представления сливаются в один URL.<title>, и если маршрутизатор его не обновляет, он общий для всех страниц.href: кнопки и обработчики onClick переходят для пользователей, но не дают краулерам ничего, по чему можно идти.Googlebot сначала загружает необработанный HTML и читает найденные там ссылки и директивы. Страницы со статусом 200 затем попадают в очередь Web Rendering Service, то есть headless Chromium. Google заявляет, что страница «может оставаться в этой очереди несколько секунд, но может и дольше». После рендеринга полученный HTML снова разбирается на предмет контента и ссылок, а затем индексируется.
Четыре детали из документации Google важны для SPA:
<a> с href. Ссылки, добавленные через JavaScript, подходят, если они соответствуют этому формату.pushState) вместо маршрутов с #. Старую схему сканирования AJAX (URL с #!) он признал устаревшей в октябре 2015 года.noindex в исходном HTML имеет приоритет. Google может пропустить рендеринг, увидев noindex, поэтому последующее удаление тега через JavaScript не работает.Практический вывод: Google может проиндексировать SPA с клиентским рендерингом, но вы добавляете для каждой страницы второй шаг, задержку и точку отказа. Тайм-аут, заблокированный вызов API или ошибка JavaScript во время рендеринга оставляют проиндексированную версию пустой. Проверьте, что видит Google, с помощью инструмента проверки URL в Search Console и прочитайте наше руководство о том, как работает индексация Google, если страницы остаются вне индекса.
В основном нет. В исследовании, опубликованном в декабре 2024 года по трафику своей сети, Vercel и MERJ обнаружили, что «ни один из крупных AI-краулеров сейчас не рендерит JavaScript»: GPTBot, OAI-SearchBot и ChatGPT-User (OpenAI), ClaudeBot (Anthropic), PerplexityBot, Meta-ExternalAgent и Bytespider читают только необработанный HTML. Они действительно загружают файлы JavaScript (около 11.5% запросов ChatGPT и 23.8% запросов Claude), но не выполняют их. Исключения это Gemini, который опирается на инфраструктуру рендеринга Google, и AppleBot, использующий краулер на основе браузера.
Для SPA с клиентским рендерингом это означает, что AI-краулеры, питающие ChatGPT, Claude и Perplexity, видят пустую страницу. Ваш продукт может ранжироваться в Google и все равно оставаться невидимым в ответах AI, потому что ассистент не прочитал о нем ни слова. То же относится к большинству ботов предпросмотра ссылок в социальных сетях и мессенджерах, которые читают теги Open Graph в необработанном HTML. Когда контент окажется в HTML, проверьте также, что ваш robots.txt разрешает нужные AI-краулеры.
Решение: отправлять настоящий HTML в первом ответе. В своей документации по динамическому рендерингу Google называет динамический рендеринг (выдачу предварительно отрендеренной версии только ботам) «обходным путем, а не рекомендуемым решением» и указывает вместо него на серверный рендеринг, статический рендеринг или гидратацию. Определения ниже следуют справочнику Rendering on the Web на web.dev.
| Стратегия | Как работает | Контент в первом HTML | Лучше всего подходит для | Ограничения |
|---|---|---|---|---|
| Рендеринг на стороне клиента (CSR) | Браузер строит страницу из JavaScript и API | Нет | Панелей управления и страниц за авторизацией | Отложенная индексация в Google, невидим для большинства AI-краулеров |
| Рендеринг на стороне сервера (SSR) | Сервер рендерит HTML при каждом запросе, затем JavaScript гидратирует его | Да | Каталогов, листингов, часто меняющегося или персонализированного контента | Затраты на сервер, более медленный ответ без кэширования |
| Статическая генерация (SSG) | HTML создается на этапе сборки для каждого URL и отдается из CDN | Да | Маркетинговых страниц, блога, документации, посадочных страниц | Нужна пересборка при изменении контента (есть инкрементальные варианты) |
| Пререндеринг на этапе сборки | Headless-браузер сохраняет начальное состояние каждого маршрута как статический HTML | Да | Существующих SPA с ограниченным числом публичных маршрутов | Данные замораживаются на момент сборки, маршруты нужно перечислять |
| Динамический рендеринг | Боты получают предварительно отрендеренный снимок, пользователи получают SPA | Да, только для ботов из списка | Временного решения для устаревшего приложения | Официально это обходной путь, затраты на поддержку, риск показывать ботам другой контент |
Большинство современных фреймворков позволяют смешивать стратегии по маршрутам: статика для маркетинговых страниц, серверный рендеринг для каталога, клиентский рендеринг для приложения после авторизации. Такая гибридная схема дает краулерам полный HTML там, где приходит поисковый трафик, и сохраняет опыт SPA там, где он приносит пользу.
| Библиотека | Фреймворк или функция для HTML при первой загрузке |
|---|---|
| React | Next.js (серверные компоненты, SSR и статическая генерация), React Router в режиме фреймворка, Gatsby |
| Vue | Nuxt (универсальный рендеринг по умолчанию, доступна статическая генерация) |
| Angular | Angular SSR (серверный рендеринг и пререндеринг на этапе сборки) |
| Svelte | SvelteKit (серверный рендеринг по умолчанию, пререндеринг по маршрутам) |
| Любая из них | Astro (статический HTML по умолчанию, интерактивные острова загружаются только там, где нужны) |
Сайты, созданные AI-конструкторами сайтов, заслуживают особого упоминания: многие из них экспортируют приложение на React с клиентским рендерингом. Если вы построили сайт с помощью такого конструктора, прочитайте наши заметки о SEO и GEO для Lovable, прежде чем считать, что Google и ChatGPT смогут его прочитать.
Используйте History API (/pricing, никогда не /#/pricing), один URL на единицу контента и один и тот же URL, независимо от того, приходит ли посетитель напрямую или через навигацию внутри приложения. Каждый URL должен загружать правильный контент при открытии в новой вкладке: именно такой тест проводит краулер.
Каждый элемент навигации, ведущий на индексируемую страницу, должен быть <a href="/path">. Компоненты ссылок фреймворков (Link, NuxtLink, routerLink) выдают такую разметку, а собственные обработчики кликов на элементах div или button нет. Хорошие ссылки также несут архитектуру вашего сайта: если на страницу нет ссылок, краулеры редко ее находят.
Каждому маршруту нужны собственные title, мета-описание, canonical и теги Open Graph, по возможности генерируемые на сервере. Наша страница о мета-тегах перечисляет, что нужно задать. Оставляйте один канонический тег: Google рекомендует задавать его в HTML, а если JavaScript его меняет, результат не должен противоречить исходному.
Отсутствующие товары и удаленные статьи не должны отвечать 200 с сообщением об ошибке. При SSR возвращайте настоящий 404 или 410 с сервера. В чистом SPA Google допускает два запасных варианта: перенаправить с помощью JavaScript на URL, возвращающий 404, или добавить в представление ошибки мета-тег robots с noindex.
Заголовки, основной текст, цены, FAQ и структурированные данные JSON-LD должны быть в ответе сервера, а не загружаться после клика или прокрутки. Контент во вкладках, которые рендерятся по требованию, или за кнопками «показать еще» часто пропускается.
Разделяйте пакет по маршрутам, откладывайте то, что не нужно для первого представления, и избегайте повторного рендеринга всей страницы во время гидратации. Учтите, что полевые данные Chrome (CrUX) относят метрики переходов внутри приложения к URL, который посетитель загрузил первым, поэтому тестируйте свои ключевые шаблоны по отдельности.
Сравните три версии каждого ключевого шаблона: необработанный HTML (просмотр исходного кода или загрузка страницы через инструмент командной строки), отрендеренный HTML Google (проверка URL, затем «Посмотреть просканированную страницу») и страницу с отключенным JavaScript. Если основной текст появляется только во второй версии, AI-краулеры его не видят. Наш бесплатный аудит доступности для сканирования для AI и проверщик индексируемости выполняют эти проверки для любого URL.
| Симптом | Вероятная причина | Решение |
|---|---|---|
| Search Console показывает много страниц со статусом «Просканировано, но пока не проиндексировано» | Пустой или почти одинаковый HTML до рендеринга | SSR, SSG или пререндеринг для публичных маршрутов |
Все результаты поиска через site: показывают одинаковый title | Title не обновляется по маршрутам | Управление head на уровне маршрута на сервере |
| Индексируется только главная страница | Маршрутизация через хэш или ссылки без href | History API и настоящие ссылки <a> |
| Страницы ошибок попадают в индекс | Мягкие 404 (статус 200 везде) | 404 на сервере, или перенаправление через JavaScript на URL с 404, или noindex |
| Ранжируется в Google, но ChatGPT и Perplexity никогда не цитируют | Контент виден только после выполнения JavaScript | Контент в первом ответе HTML |
| В отрендеренном виде Google показан старый контент | Кэшированные файлы JavaScript или CSS | Имена файлов с отпечатком |
Годами клиентский рендеринг был управляемым риском, потому что Google в конце концов рендерил JavaScript. Теперь, когда часть поиска происходит в ChatGPT, Claude, Gemini и Perplexity, цена изменилась: страница, существующая только после выполнения JavaScript, отсутствует в источниках, которые способно прочитать большинство ассистентов. Доступность для сканирования в необработанном HTML стала первым условием оптимизации для генеративных движков.
Когда HTML становится полным, остальное подчиняется обычным правилам: ассистенты цитируют страницы, которые четко отвечают на один вопрос, с проверяемыми фактами и структурированными данными. Функции GEO-оптимизации Sorank помогают писать и публиковать такой контент, а отслеживание упоминаний в ИИ показывает, цитируют ли ChatGPT, Claude и Gemini ваш бренд после исправления рендеринга.
Главное правило SEO одностраничных приложений умещается в одно предложение: все, что вы хотите видеть в ранжировании Google и в цитатах AI, должно быть в HTML, который отправляет сервер. Оставьте SPA для опыта после авторизации, рендерите публичные страницы на сервере или на этапе сборки, а затем проверяйте, что получают боты, до и после каждого релиза.
Google не наказывает одностраничные приложения, но их настройка по умолчанию, клиентский рендеринг с одной HTML-оболочкой, делает индексацию медленнее и менее надежной. Большинство AI-краулеров не выполняют JavaScript, поэтому видят пустую страницу. С серверным рендерингом, статической генерацией или пререндерингом на публичных маршрутах SPA может ранжироваться так же хорошо, как любой классический сайт.
Сам React нейтрален: важно, где создается HTML. Приложение на React, рендерящееся только в браузере, имеет обычные проблемы SPA, а те же компоненты, отрендеренные на сервере с помощью Next.js или React Router в режиме фреймворка, отдают краулерам полный HTML. Выбирайте фреймворк, поддерживающий серверный или статический рендеринг для страниц, которые вы хотите индексировать.
Только как временную меру. Google описывает динамический рендеринг как обходной путь, а не рекомендуемое решение, потому что поддержка отдельной версии для ботов добавляет затраты и риски. Серверный рендеринг, статическая генерация или пререндеринг на этапе сборки отдают один и тот же HTML каждому посетителю и являются долгосрочными решениями.
ОНИ ПОПРОБОВАЛИ SORANK ДО ВАС
