На второй приходит почти пустой документ:
<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 responseJavaScript может быть нужен дальше — но уже не для существования самой статьи.
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-ssgSSR-сервер сгенерировал 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 KBAPI:
ответ за 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/123Google рекомендует для 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.htmlJavaScript после загрузки 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 становится намного менее эмоциональным.
Удобная модель выбора
Можно представить три стратегии следующим образом:
| Свойство | CSR | SSR | SSG |
|---|---|---|---|
| Основной 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.
Она начинается тогда, когда для получения обычного публичного документа поисковику приходится успешно запустить всё приложение целиком.