SEO и контент

SSR, CSR и SSG для SEO: когда JavaScript начинает мешать индексации сайта

Современный сайт может выглядеть совершенно одинаково для пользователя и при этом быть устроен принципиально по-разному. Открываем три страницы. На первой сервер сразу возвращает готовый HTML с заголовком, текстом и ссылками.

На второй приходит почти пустой документ:

<div id="root"></div>
<script src="/assets/app.js"></script>

а всё содержимое появляется после выполнения JavaScript.

На третьей HTML был сформирован ещё во время сборки проекта и лежит готовым файлом на CDN.

Для человека результат может быть одинаковым:

заголовок
текст статьи
изображения
меню
ссылки

Для поискового робота путь к этому содержимому совершенно разный.

Так появляются три часто обсуждаемых подхода:

CSR — Client-Side Rendering
SSR — Server-Side Rendering
SSG — Static Site Generation

И вокруг них возникло множество слишком простых правил:

CSR плохо для SEO.
SSR автоматически поднимает сайт в поиске.
Google умеет выполнять JavaScript, поэтому SSR больше не нужен.
SSG всегда быстрее SSR.

Каждое из этих утверждений либо неверно, либо верно только при определённых условиях.

Google действительно выполняет JavaScript с помощью Chromium и описывает обработку JavaScript-приложений как последовательность crawling → rendering → indexing. Но Google одновременно отмечает, что server-side rendering и pre-rendering остаются хорошими решениями: они быстрее делают содержимое доступным пользователям и роботам, а не все поисковые и другие боты вообще выполняют JavaScript.

Яндекс также умеет выполнять JavaScript при индексировании и даже позволяет через Вебмастер управлять этим процессом и сравнивать страницы с JavaScript и без него. При этом сама документация Яндекса предупреждает, что отложенная загрузка и дополнительные сценарии могут приводить к неполному индексированию JavaScript-сайтов.

Поэтому вопрос следует ставить не так:

Какой rendering лучше для SEO?

А так:

В какой момент поисковый робот получает основной документ и от скольких компонентов зависит успешность этого процесса?

Разберём это на уровне архитектуры.

Что вообще означает rendering

Прежде чем сравнивать SSR, CSR и SSG, нужно отделить несколько процессов друг от друга.

Когда пользователь открывает:

https://example.ru/expert/rendering

браузер сначала выполняет HTTP-запрос.

Сервер может вернуть:

HTTP/2 200 OK
Content-Type: text/html

и некоторый HTML.

Дальше браузер строит DOM, получает CSS, JavaScript, изображения и другие ресурсы.

Если JavaScript изменяет страницу, DOM продолжает формироваться уже на клиенте.

С точки зрения поискового робота важно различать как минимум два состояния:

HTML, полученный от сервера

и:

DOM после выполнения JavaScript

Иногда они практически одинаковы.

Иногда отличаются радикально.

Например, сервер вернул:

<body>
  <div id="root"></div>
  <script src="/app.js"></script>
</body>

а после выполнения JavaScript браузер получил:

<body>
  <div id="root">
    <main>
      <article>
        <h1>SSR, CSR и SSG для SEO</h1>

        <p>
          Разбираемся, как способ рендеринга влияет
          на доступность страницы поисковым роботам.
        </p>

        <a href="/expert/javascript-seo">
          JavaScript SEO
        </a>
      </article>
    </main>
  </div>
</body>

Для пользователя второй DOM является страницей.

Но при первоначальном HTTP-запросе статьи ещё не существовало.

Именно это различие лежит в основе проблемы JavaScript SEO.


CSR: сначала приложение, потом содержимое

Client-Side Rendering означает, что значительная часть интерфейса формируется непосредственно в браузере.

Условная архитектура:

Browser
   │
   │ GET /article
   ▼
Server
   │
   │ HTML shell
   ▼
Browser
   │
   │ GET app.js
   ▼
JavaScript
   │
   │ GET /api/article/123
   ▼
API
   │
   │ JSON
   ▼
JavaScript
   │
   ▼
DOM

Первоначальный HTML может выглядеть так:

<!doctype html>
<html>
<head>
  <title>Example</title>
</head>
<body>
  <div id="root"></div>
  <script src="/assets/app.js"></script>
</body>
</html>

После загрузки JavaScript приложение обращается к API:

const response =
  await fetch("/api/articles/123");

const article =
  await response.json();

render(article);

И только после этого появляется реальный документ.

Для пользователя при хорошем соединении разница может составлять сотни миллисекунд.

С архитектурной точки зрения разница намного больше.

Чтобы получить статью, необходимо успешно выполнить всю цепочку:

HTML
 ↓
JavaScript bundle
 ↓
JavaScript runtime
 ↓
API request
 ↓
API response
 ↓
state update
 ↓
render

Каждый дополнительный шаг — ещё одна зависимость.

Что с CSR делает Google

Google умеет работать с такими страницами.

Его официальная документация описывает следующий процесс: Googlebot получает URL, анализирует первоначальный HTML, а затем помещает страницу в очередь rendering. Когда ресурсы доступны, headless Chromium выполняет JavaScript, после чего Google повторно анализирует уже отрендерированный HTML и использует его при индексировании.

То есть схема может выглядеть примерно так:

GET /article
      ↓
HTML shell
      ↓
первичный анализ
      ↓
render queue
      ↓
Chromium
      ↓
JavaScript
      ↓
API
      ↓
rendered DOM
      ↓
повторный анализ
      ↓
indexing

Следовательно, утверждение:

Google не видит JavaScript.

неверно.

Но из этого совершенно не следует:

Значит, способ рендеринга больше не имеет значения.

Именно здесь начинается самое интересное.

Когда JavaScript действительно начинает мешать

JavaScript становится проблемой не потому, что поисковая система принципиально его не понимает.

Проблема возникает тогда, когда критически важное содержимое страницы зависит от слишком длинной или ненадёжной клиентской цепочки.

Представим статью:

useEffect(() => {
  loadArticle();
}, []);

async function loadArticle() {
  const token = await getSession();
  const config = await fetchConfig();
  const article = await fetchArticle(config);

  setArticle(article);
}

Чтобы робот получил текст, нужно успешно выполнить:

JavaScript загрузился
        ↓
runtime запустился
        ↓
getSession()
        ↓
fetchConfig()
        ↓
fetchArticle()
        ↓
API ответило
        ↓
React обновил state
        ↓
DOM сформировался

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

Например, API один раз ответило медленнее обычного.

Пользователь обновил страницу.

Всё заработало.

Поисковый робот мог получить страницу именно во время сбоя.

И увидеть:

<div class="loader">
  Загружаем материал...
</div>

вместо статьи.

JavaScript создаёт не одну, а несколько потенциальных точек отказа

Рассмотрим простой CSR-сайт.

Серверный HTML доступен:

200 OK

Но JavaScript bundle неожиданно отдаёт:

503 Service Unavailable

Результат:

HTML есть
контента нет

Другой сценарий:

app.js → 200
API → 500

Результат тот же.

Ещё один:

HTML → 200
JS → 200
API → 200
runtime exception

Например:

Cannot read properties of undefined

Пользователь мог бы увидеть error boundary.

Робот вместо статьи тоже получает ошибочную версию DOM.

Поэтому преимущество серверного HTML состоит не в какой-либо «любви поисковиков к SSR».

Оно гораздо прозаичнее:

Чем меньше операций необходимо выполнить до появления основного содержания, тем меньше мест, в которых этот процесс может сломаться.

SSR: содержимое формируется во время запроса

Server-Side Rendering работает иначе.

Когда пользователь запрашивает:

GET /expert/rendering

сервер сам получает необходимые данные и формирует HTML.

Схема:

Browser
   │
   │ GET /article
   ▼
Server
   │
   ├── database
   │
   ├── API
   │
   └── template/render
   │
   ▼
готовый HTML
   │
   ▼
Browser

Ответ уже содержит:

<main>
  <article>
    <h1>SSR, CSR и SSG для SEO</h1>

    <p>
      Содержимое страницы уже присутствует
      в HTTP-ответе.
    </p>
  </article>
</main>

Если выполнить:

curl https://example.ru/expert/rendering

мы увидим статью без запуска браузера.

Для поискового робота это чрезвычайно удобное состояние.

Основной контент существует уже после:

HTTP request
        ↓
HTML response

JavaScript может быть нужен дальше — но уже не для существования самой статьи.

SSR не означает «сайт без JavaScript»

Это распространённое заблуждение.

Современное SSR-приложение вполне может использовать React, Vue или другой JavaScript-фреймворк.

Сервер сначала формирует HTML:

<button>
  Добавить в избранное
</button>

Браузер показывает страницу.

Затем загружается JavaScript и «оживляет» интерфейс.

Этот процесс обычно называют hydration.

Упрощённо:

Server
  ↓
готовый HTML
  ↓
Browser показывает страницу
  ↓
JavaScript
  ↓
hydration
  ↓
интерактивное приложение

Для пользователя кнопка после hydration начинает выполнять действие.

Но текст статьи, H1, обычные ссылки и другие базовые элементы существовали ещё до этого.

И это принципиальное отличие от чистого CSR.

Что будет, если hydration сломается

Представим SSR-страницу.

HTML пришёл корректно:

<h1>SSR, CSR и SSG</h1>

<p>
  Полный текст статьи...
</p>

<a href="/expert/next">
  Следующая статья
</a>

Затем JavaScript получил ошибку:

Hydration failed

Для интерактивности это проблема.

Какая-нибудь кнопка может перестать работать.

Но основной документ всё ещё находится в HTML.

Поисковый робот способен получить:

H1
текст
ссылки
metadata

даже если клиентская интерактивность сломалась.

При чистом CSR аналогичная JavaScript-ошибка иногда означает отсутствие практически всей страницы.

Вот почему SSR часто делает публичный контент устойчивее к ошибкам клиентского выполнения.


А что такое SSG

Static Site Generation переносит рендеринг ещё раньше.

При SSR страница создаётся:

во время HTTP-запроса

При SSG она создаётся:

во время сборки

Например, есть 500 статей.

Во время deployment запускается генератор:

database
   ↓
build
   ↓
500 HTML-файлов

Получаются:

/expert/article-1/index.html
/expert/article-2/index.html
/expert/article-3/index.html
...

Когда пользователь приходит на сайт, приложению уже не нужно рендерить статью.

Веб-сервер или CDN просто отдаёт готовый документ:

request
  ↓
CDN
  ↓
HTML

С точки зрения поискового робота это один из самых простых сценариев.

Он запрашивает URL и сразу получает:

<title>...</title>
<meta name="description" ...>
<link rel="canonical" ...>

<h1>...</h1>
<article>...</article>

То есть по доступности базового контента SSG очень похож на SSR.

Разница находится не столько в HTML, сколько в моменте его создания.


SSR и SSG глазами поискового робота могут выглядеть одинаково

Представим запрос:

GET /expert/ssr-csr-ssg

SSR-сервер сгенерировал HTML 40 миллисекунд назад.

SSG создал тот же HTML вчера во время deployment.

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

Он получает:

HTTP/2 200 OK
Content-Type: text/html

и:

<h1>SSR, CSR и SSG для SEO</h1>
<p>...</p>

Для индексации критически важен результат:

Основное содержимое присутствует в полученном HTML.

Поэтому SSG не получает некий отдельный «SEO-бонус» только потому, что файл статический.

То же относится к SSR.

Поисковику важнее доступность и корректность документа, чем название архитектурного паттерна.


Тогда почему вообще выбирать SSG вместо SSR

Потому что SEO — только одна часть архитектуры.

Допустим, экспертный центр содержит 100 статей, которые меняются редко.

При SSR каждый запрос потенциально запускает:

HTTP request
     ↓
Node.js
     ↓
database
     ↓
render
     ↓
HTML

При SSG:

HTTP request
     ↓
CDN
     ↓
готовый HTML

Второй вариант может быть проще и дешевле в обслуживании.

Но появляется другой компромисс.

Редактор изменил статью:

10:12 — исправлен заголовок

Статический HTML был сгенерирован:

02:00 — предыдущая сборка

Если система не умеет частичную регенерацию, посетители продолжат получать старую версию до следующего build.

Поэтому SSG особенно удобен для содержимого, которое:

публично;
редко меняется;
не персонализировано;
должно быстро отдаваться;
может быть заранее известно.

Например:

документация;
экспертные статьи;
страницы услуг;
лендинги;
справочные материалы.

А вот личный кабинет:

Баланс Михаила: 14 531 ₽

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


SSR тоже имеет цену

После обсуждения JavaScript SEO легко сделать противоположную ошибку:

Значит, просто переведём всё на SSR.

Но server-side rendering не бесплатен.

Запрос:

GET /catalog/notebooks

может запускать:

database query
      ↓
API request
      ↓
permissions
      ↓
template rendering
      ↓
HTML

Если сервер перегружен, вместо красивого SSR мы получим:

TTFB = 4.8 s

или вообще:

504 Gateway Timeout

Тогда преимущество исчезает.

Статическая страница, отданная CDN за 40 мс, будет значительно устойчивее.

Даже хорошо оптимизированное CSR-приложение иногда окажется лучше плохо реализованного SSR.

Поэтому нельзя сравнивать:

SSR
vs
CSR

в вакууме.

Нужно сравнивать конкретные реализации.


CSR тоже вполне может индексироваться нормально

Представим небольшое приложение.

Первоначальный HTML:

<div id="app"></div>
<script src="/app.a81f.js"></script>

JavaScript:

70 KB

API:

ответ за 40 ms

После render появляются:

H1
контент
ссылки
title
description
canonical

Все ресурсы доступны роботам.

URL работают напрямую:

/products
/services
/expert/article

Маршрутизация построена на нормальных URL.

Нет авторизации перед публичным API.

Нет бесконечного loader.

Нет ошибок runtime.

Такой CSR-сайт вполне может индексироваться.

Google прямо говорит, что выполняет JavaScript, а Яндекс предоставляет собственный механизм JavaScript rendering.

Следовательно, проблема не в самом факте использования CSR.

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


Практический тест: насколько страница зависит от JavaScript

Один из самых полезных тестов можно провести вообще без специализированного SEO-сервиса.

Возьмём URL:

https://example.ru/expert/article

Сначала смотрим исходный HTTP-ответ:

curl -L https://example.ru/expert/article

Вариант 1

Получаем:

<title>SSR, CSR и SSG для SEO</title>

<h1>SSR, CSR и SSG для SEO</h1>

<article>
  Полный текст...
</article>

Основное содержимое доступно без JavaScript.

Это может быть SSR.

Может быть SSG.

Для текущего вопроса неважно.

Вариант 2

Получаем:

<title>Example</title>

<div id="root"></div>

<script src="/assets/app.js"></script>

А статья появляется только в браузере.

Значит, основной контент зависит от JavaScript rendering.

Это ещё не означает дефект.

Но теперь появляется второй вопрос:

Что произойдёт, если JavaScript или один из его API-запросов не выполнится?

Вот с этого момента начинается настоящий аудит.


Проверка с отключённым JavaScript иногда показывает больше, чем PageSpeed

Открываем страницу без JavaScript.

Если остаются:

H1
основной текст
навигация
ссылки на связанные статьи

значит, фундамент страницы относительно устойчив.

Если остаётся:

белый экран

или:

Загрузка...

мы понимаем:

Всё публичное содержимое зависит от JavaScript.

Это не автоматический SEO-приговор.

Но теперь JavaScript становится частью критической инфраструктуры индексирования.

То есть к нему нужно относиться примерно так же внимательно, как к backend.


Особая проблема CSR — маршрутизация

Single Page Application часто обслуживает все URL одним документом.

Например:

/
 /services
 /prices
 /expert
 /expert/article

сервер фактически возвращает:

index.html

а JavaScript определяет текущий маршрут.

Это может работать прекрасно.

Проблемы начинаются, если архитектура URL реализована неправильно.

Например:

/#/services
/#/expert
/#/article/123

Google рекомендует для SPA использовать нормальные URL и History API вместо fragment-based routing для загрузки различного содержимого. Поисковые ссылки должны быть обычными <a> с доступным href.

Хороший вариант:

<a href="/expert/ssr-csr">
  SSR и CSR
</a>

Гораздо менее надёжная конструкция:

<div
  onclick="openArticle(123)"
>
  SSR и CSR
</div>

Для пользователя оба элемента могут выглядеть одинаково.

Для поискового робота первый явно описывает связь между двумя URL.


Ещё одна проблема CSR — HTTP-коды

Представим SPA.

Пользователь открывает:

/product/999999

Такого товара не существует.

Но сервер всегда возвращает:

HTTP/2 200 OK

потому что любой маршрут получает:

index.html

JavaScript после загрузки API понимает:

404

и показывает:

<h1>Товар не найден</h1>

Для пользователя поведение логично.

На HTTP-уровне сервер сообщил:

Это нормальная существующая страница.

Google отдельно рассматривает такую проблему применительно к client-side SPA и рекомендует не оставлять ошибочные маршруты обычными 200 OK, чтобы не создавать soft 404.

При SSR сервер может сразу ответить:

HTTP/2 404 Not Found

и одновременно отдать красивую HTML-страницу ошибки.

Это архитектурно чище.


Metadata: почему «потом JavaScript поменяет title» не всегда лучший план

CSR-приложение может первоначально вернуть:

<title>Example</title>
<meta
  name="description"
  content="Example application"
>

После API-запроса JavaScript изменит их:

document.title =
  article.seoTitle;

Google способен увидеть изменения после rendering.

Но опять возникает дополнительная зависимость:

render
 ↓
API
 ↓
article loaded
 ↓
metadata update

При SSR или SSG можно сразу вернуть:

<title>
  SSR, CSR и SSG для SEO:
  когда JavaScript мешает индексации
</title>

<meta
  name="description"
  content="Разбираем..."
>

Это проще и предсказуемее.

То же относится к canonical.

Google допускает создание canonical через JavaScript, но рекомендует избегать конфликтов между исходным и добавленным после rendering значением.

Например, плохо:

<!-- server HTML -->
<link
  rel="canonical"
  href="https://example.ru/"
>

а JavaScript потом меняет его:

<link
  rel="canonical"
  href="https://example.ru/expert/article"
>

Мы искусственно отправляем поисковику два последовательных сигнала.

Намного понятнее сразу вернуть правильный canonical.


JavaScript и внутренние ссылки

Есть ещё один важный аспект.

Допустим, страница содержит блок:

Похожие материалы

Но он загружается так:

IntersectionObserver
    ↓
пользователь прокрутил страницу
    ↓
fetch recommendations
    ↓
render links

Если поисковый rendering не активирует нужное пользовательское действие, часть ссылок может вообще не появиться.

В результате пользователь видит хорошую перелинковку:

статья A
  ↓
статья B
  ↓
статья C

а первоначальный HTML может не содержать её вовсе.

Яндекс отдельно рекомендует связывать документы обычными HTML-ссылками <a href="...">, поскольку ссылки используются роботом для обнаружения страниц.

Критически важную навигацию поэтому лучше не делать зависимой только от:

scroll
hover
click
IntersectionObserver

Если ссылка важна для структуры сайта, самый надёжный вариант — чтобы она существовала как настоящая ссылка.


Lazy loading тоже бывает разным

Ленивая загрузка сама по себе не проблема.

Например, нет смысла сразу загружать большое изображение в самом конце статьи.

Но иногда lazy loading применяют уже к основному контенту.

Первоначально:

<section id="article"></section>

Текст появляется только после:

scroll 200 px

или:

IntersectionObserver callback

Это уже рискованнее.

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

Можно сформулировать простой принцип:

Ленивая загрузка подходит для оптимизации второстепенных ресурсов, но значительно хуже подходит для определения самого существования основного документа.

SSR не исправит плохую архитектуру автоматически

Теперь рассмотрим обратный случай.

Разработчики перевели сайт на SSR.

Но сервер возвращает:

<h1>Каталог</h1>

<div>
  Загрузка товаров...
</div>

а товары всё равно подтягиваются только клиентом:

useEffect(() => {
  fetchProducts();
}, []);

Формально:

SSR есть

Практически:

основной контент = CSR

Поэтому само наличие Next.js, Nuxt или другого SSR-capable framework ничего не доказывает.

Важнее посмотреть реальный HTTP-response.

Можно использовать SSR-фреймворк и фактически сделать страницу клиентской.

Можно использовать более простой стек и отдавать поисковику великолепный готовый HTML.


Частичный SSR и гибридные страницы

Современная архитектура редко ограничивается выбором:

100% SSR
или
100% CSR

Например, страница товара может быть устроена так:

SERVER / STATIC
────────────────────
H1
название товара
описание
цена
характеристики
breadcrumb
canonical
structured data
ссылки

CLIENT
────────────────────
добавление в корзину
выбор варианта
избранное
сравнение
чат
персональные рекомендации

Для поискового робота всё важное уже существует.

JavaScript отвечает в основном за интерактивность.

Такой подход часто значительно рациональнее крайностей.

То же самое можно применить к экспертной статье.

На сервере:

title
description
H1
текст
автор
дата
рубрика
ссылки
Article JSON-LD

На клиенте:

копирование кода
оглавление
голосование
комментарии
аналитика
интерактивные элементы

SEO и JavaScript здесь не конфликтуют.

Каждый выполняет свою задачу.


SSG тоже может использовать JavaScript

Статически сгенерированный сайт — не обязательно набор HTML-файлов уровня 2005 года.

При SSG сервер может отдать:

<article>
  ...
</article>

а затем JavaScript выполнит hydration и добавит:

поиск;
фильтры;
кнопки;
динамическую навигацию;
персонализацию.

Получается:

SSG
+
client JavaScript

Основной документ при этом остаётся доступным ещё до выполнения клиентского кода.

Именно поэтому правильнее говорить не:

Использует ли сайт JavaScript?

а:

Что именно перестанет существовать, если JavaScript не выполнится?

Это один из самых полезных вопросов для технического SEO-аудита.


Что выбрать для разных типов страниц

Универсального победителя нет.

Для публичной экспертной статьи требования примерно такие:

контент публичный
редко меняется
должен индексироваться
персонализация почти не нужна

Здесь SSG или SSR обычно естественнее чистого CSR.

Для страницы:

актуальные остатки товара
цена зависит от региона
частые изменения

может быть удобнее SSR или гибридная модель.

Для приложения:

внутренняя CRM
только после авторизации
поисковая индексация не нужна

CSR совершенно нормален.

Нет большого смысла усложнять систему ради поискового робота, который эту часть приложения вообще не должен индексировать.

Получается важное правило:

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

Одна система может использовать все три подхода

Представим SaaS-продукт.

Главная:

SSG

Страницы услуг:

SSG

Документация:

SSG

Новости:

SSR или SSG с регенерацией

Каталог с постоянно меняющимися данными:

SSR

Личный кабинет:

CSR

Административная панель:

CSR

И это совершенно нормальная архитектура.

Нет причины заставлять административный интерфейс работать через SSR ради SEO.

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


Что насчёт ISR и других гибридных подходов

Между классическими SSR и SSG существует множество промежуточных моделей.

Например:

страница генерируется статически
       ↓
хранится некоторое время
       ↓
после истечения срока
перегенерируется

Названия конкретных механизмов зависят от фреймворка.

С архитектурной точки зрения это попытка совместить:

готовый HTML
+
скорость CDN
+
обновляемость данных

Для поискового робота главный критерий остаётся тем же.

Если запрос получает:

200 OK
+
полный корректный HTML

не так важно, был этот HTML:

создан во время build;
сгенерирован 30 секунд назад;
взятым из cache;
сформирован прямо сейчас.

Rendering strategy имеет значение прежде всего потому, как она влияет на доступность, стабильность и актуальность итогового документа.


Когда именно CSR становится SEO-риском

Можно провести довольно чёткую границу.

Сам JavaScript — не проблема.

CSR начинает становиться рискованным, когда одновременно выполняется несколько условий:

основной контент существует только после JS;
metadata создаются после JS;
ссылки появляются после JS;
данные загружаются дополнительными API-запросами;
есть долгие loading states;
часть API требует cookies/session;
ошибки возвращаются как 200;
маршруты существуют только внутри SPA;
контент появляется после пользовательского действия.

Чем больше таких зависимостей, тем больше вероятность, что:

страница пользователя
≠
страница поискового робота

И вот это уже настоящая проблема.


Когда CSR практически не создаёт SEO-проблем

Есть и обратный сценарий.

Страница:

не должна индексироваться

Например:

/admin
/account
/dashboard
/internal-crm

Здесь вопрос SEO практически исчезает.

Можно выбирать архитектуру исходя из:

UX
скорости разработки
сложности state management
безопасности
API
поддерживаемости

Использовать SSR для внутренней админ-панели только потому, что «SSR лучше для SEO», не имеет особого смысла.

Поисковой системе там делать нечего.


Как проверить реальный проект

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

Нужно сравнить четыре состояния страницы.

Первое:

HTTP response

Что возвращает сервер?

Второе:

HTML source

Есть ли там основной контент?

Третье:

rendered DOM

Что добавилось после JavaScript?

Четвёртое:

версия поискового робота

Что реально получил Google или Яндекс?

Яндекс Вебмастер позволяет проверять страницу и отдельно анализировать JavaScript rendering, в том числе сравнивать доступное содержимое.

Google для диагностики JavaScript рекомендует использовать URL Inspection и анализировать отрендерированный HTML.

Именно сравнение этих состояний намного полезнее, чем обсуждение:

React вообще индексируется?

React здесь почти ни при чём.

Вопрос в том, какой документ создаёт конкретное приложение.


Пример дефекта, который легко пропустить

Предположим, у нас есть:

/products/monitor-4k

Пользователь получает:

Монитор 4K
79 900 ₽
характеристики
описание

Разработчик открывает DevTools.

Ошибок нет.

PageSpeed хороший.

Но curl показывает:

<title>Каталог</title>

<div id="root"></div>

После rendering Google получает карточку товара.

Казалось бы, всё хорошо.

Но robots.txt случайно содержит:

Disallow: /api/

а данные товара клиент загружает через:

/api/products/monitor-4k

Или JS-resource закрыт для робота.

Google прямо указывает, что JavaScript из заблокированных ресурсов или страниц может не быть доступен для rendering.

Для пользователя:

работает

Для робота:

пустой shell

Такой дефект нельзя обнаружить визуальной проверкой сайта обычным браузером.


Другой дефект: сервер и клиент показывают разное

Представим SSR.

Сервер рендерит:

Цена: 10 000 ₽

После hydration клиент получает API:

Цена: 12 000 ₽

Теперь возникают два состояния одного документа.

Для динамической информации небольшое расхождение иногда неизбежно.

Но если отличаются:

H1
основной текст
canonical
robots
структурированные данные

архитектура становится непредсказуемой.

Особенно опасна ситуация:

<!-- server -->
<meta
  name="robots"
  content="noindex"
>

после чего JavaScript пытается изменить его:

<meta
  name="robots"
  content="index"
>

Google предупреждает, что при обнаружении noindex rendering может быть пропущен, поэтому рассчитывать на последующее удаление noindex JavaScript-кодом нельзя.

То есть начальный HTML действительно имеет значение.


Rendering и производительность связаны, но это не одно и то же

Есть соблазн свести разговор к:

SSG быстрый
SSR средний
CSR медленный

Так тоже нельзя.

Хорошо оптимизированный CSR может быть очень быстрым.

Плохо написанный SSG-сайт способен загрузить:

3 МБ JavaScript
20 шрифтов
40 изображений

и работать отвратительно.

SSR-приложение может иметь прекрасный frontend, но медленный backend.

Поэтому есть две отдельные задачи:

Как быстро пользователь видит страницу?

и:

Насколько надёжно поисковик получает основной документ?

Они связаны, но не идентичны.


Почему публичный контент разумно делать доступным до hydration

Для статьи, страницы услуги, категории или карточки товара полезно иметь такую базовую гарантию:

JavaScript выключен
↓
основная информация всё равно существует

Не обязательно вся функциональность.

Например:

поиск может не работать;
фильтр может не работать;
карусель может стать статичной;
кнопка избранного может не работать.

Но пользователь и робот всё ещё видят:

что это за страница;
о чём она;
какой у неё заголовок;
какой основной текст;
куда ведут основные ссылки.

Такое приложение деградирует контролируемо.

Если же при любой JavaScript-ошибке получается:

белый экран

это уже не только SEO-проблема.

Это проблема общей отказоустойчивости frontend.


JavaScript начинает мешать не тогда, когда его много

Количество JavaScript само по себе не даёт точного ответа.

Можно загрузить большой bundle, который отвечает за:

графики
редактор
drag-and-drop
чат

а основной текст уже находится в HTML.

С точки зрения индексирования всё может быть нормально.

И наоборот.

Можно загрузить всего:

30 KB JavaScript

но именно эти 30 KB делают:

fetch(article)

Без них основного документа вообще нет.

Поэтому гораздо точнее оценивать не:

Сколько JavaScript используется?

А:

Какую ответственность несёт JavaScript?

Это фундаментально разные показатели.


Что лучше для экспертного центра

Для публичного экспертного центра задача обычно понятна.

Статья должна:

иметь постоянный URL;
быть доступна без авторизации;
быстро отдаваться;
содержать полный текст;
иметь уникальные metadata;
иметь canonical;
содержать обычные ссылки;
иметь Article structured data;
стабильно индексироваться.

Для такого типа страниц чистый CSR редко даёт архитектурное преимущество, оправдывающее дополнительную зависимость от rendering.

SSG хорошо подходит, если публикации меняются нечасто и существует удобная регенерация.

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

Гибридная архитектура тоже подходит.

Главное — чтобы основная статья существовала уже в HTML.


А что лучше для интернет-магазина

Здесь ситуация сложнее.

Страница товара содержит разные типы данных.

Относительно стабильные:

название
описание
характеристики
изображения
категория

Очень динамические:

остаток
региональная цена
срок доставки
персональная скидка

Нет необходимости выбирать один rendering для всей страницы.

Сервер может отдать:

название
описание
характеристики
canonical
schema

а клиент после hydration обновить:

остаток
доставку
персональную цену

Так поисковая доступность и динамичность не конфликтуют.


А для SaaS

Маркетинговые страницы SaaS:

/
 /features
 /prices
 /use-cases
 /docs

имеет смысл проектировать как публичные индексируемые документы.

SSG или SSR здесь естественны.

Но:

/app
/dashboard
/projects/123
/settings

находятся за авторизацией.

Их можно спокойно строить как клиентское приложение.

В результате:

публичная часть
→ SSR / SSG

продуктовая часть
→ CSR

часто оказывается очень рациональной архитектурой.


Ошибка — выбирать rendering по моде

Технологический цикл повторяется.

Сначала:

SPA — современно, всё делаем CSR.

Потом:

CSR плохо, теперь всё должно быть SSR.

Затем:

SSR слишком дорого, всё делаем static.

Архитектура не должна строиться вокруг текущего лозунга.

Для каждой группы URL лучше определить:

нужна ли индексация;
как часто меняются данные;
нужна ли персонализация;
должен ли документ существовать без JS;
какова допустимая задержка;
можно ли кэшировать страницу;
какой HTTP-status нужен;
как быстро должны публиковаться изменения.

После этого выбор SSR, CSR или SSG становится намного менее эмоциональным.


Удобная модель выбора

Можно представить три стратегии следующим образом:

СвойствоCSRSSRSSG
Основной HTML создаётсяв браузерепри запросезаранее
Требуется JS для базового контентачасто даобычно нетобычно нет
Хорошо подходит для публичного контентавозможнодада
Подходит для персонализированного приложениядадаограниченно
Нагрузка на сервер при каждом запросеобычно небольшаявышеминимальная
Актуальность динамических данныхвысокаявысокаязависит от регенерации
Устойчивость контента без JSзависит от реализацииобычно вышеобычно выше
Простота CDN-кэшированиявысокая для shellзависит от страницыочень высокая

Но даже эта таблица — только ориентир.

Реальный проект почти всегда сложнее.


Самый важный тест

Если нужно быстро оценить страницу, можно задать один вопрос:

Что останется на этой странице, если прямо сейчас JavaScript вообще не выполнится?

Если ответ:

полный документ,
основной текст,
H1,
metadata,
ссылки

значит, JavaScript в основном улучшает страницу.

Если ответ:

loading spinner

значит, JavaScript создаёт сам документ.

Оба подхода могут работать.

Но во втором случае JavaScript уже находится непосредственно на критическом пути индексирования.

И это нужно учитывать при проектировании, тестировании и мониторинге.


Вместо заключения

SSR, CSR и SSG — не SEO-технологии.

Это способы формирования веб-документа.

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

При CSR путь может выглядеть так:

HTTP
 ↓
HTML shell
 ↓
JavaScript
 ↓
API
 ↓
state
 ↓
render
 ↓
content
 ↓
indexing

При SSR:

HTTP
 ↓
server rendering
 ↓
HTML + content
 ↓
indexing

При SSG:

build
 ↓
готовый HTML
 ↓
HTTP
 ↓
content
 ↓
indexing

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

Но отсюда не следует, что CSR нельзя использовать.

Он прекрасно подходит для личных кабинетов, административных интерфейсов, внутренних систем и множества приложений, где поисковая индексация вообще не является задачей.

И он способен работать на публичных страницах — при условии, что rendering стабилен, ресурсы доступны, URL корректны, ссылки обнаружимы, metadata формируются правильно, HTTP-состояния не маскируются и поисковый робот действительно получает полный документ.

SSR и SSG решают эту задачу иначе.

Они позволяют отдать значительную часть содержимого раньше — непосредственно в HTML.

Это не магический фактор ранжирования.

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

Поэтому вопрос:

Что лучше для SEO — SSR, CSR или SSG?

слишком общий.

Гораздо полезнее спросить:

Какая часть этой конкретной страницы должна существовать ещё до выполнения JavaScript?

Для экспертной статьи — почти вся.

Для страницы услуги — основная информация и навигация.

Для товара — индексируемое описание и структура.

Для личного кабинета — возможно, ничего.

Для административной панели поисковой индексации вообще не должно быть.

Именно такое разделение позволяет не воевать с JavaScript ради SEO, а использовать его там, где он действительно нужен.

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

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

Есть похожая задача?

Опишите продукт, интеграции и ограничения. До разработки зафиксируем объём, риски и критерии приёмки.

Обсудить проект →