SSR, SSG и ISR для AI-краулеров: почему JavaScript-only сайты теряют видимость
Почему AI-боты не рендерят JS: как SSR, SSG и ISR обеспечивают видимость в ChatGPT, Perplexity, Claude и Google AI Overviews.
Техническая архитектура сайта напрямую определяет, будет ли ваш бренд виден в ChatGPT, Perplexity, Claude и Google AI Overviews. Это не теоретическое утверждение — это факт, который можно проверить за пять минут с помощью curl. Сайты на JavaScript-only рендеринге систематически проигрывают конкурентам с SSR и SSG в AI-видимости, и разрыв продолжает расти по мере того, как доля AI-трафика увеличивается. GEO Scout фиксирует эту разницу ежедневно: после технической миграции на SSR команды наблюдают рост Mention Rate уже в первые 2-4 недели.
Как AI-краулеры получают контент
Прежде чем говорить об архитектурных решениях, нужно понять, что именно делает AI-бот, когда посещает сайт.
AI-краулер отправляет HTTP-запрос к URL с конкретным User-Agent (например, GPTBot/1.0). Сервер возвращает HTTP-ответ. Краулер читает тело ответа. На этом всё.
Никакого выполнения JavaScript. Никакого ожидания DOMContentLoaded. Никакого puppeteer под капотом. Бот получает ровно то, что сервер отдаёт в первом HTTP-ответе — и именно с этим контентом работает языковая модель при формировании ответов пользователям.
Что видят разные боты
| Краулер | Компания | Рендеринг JS | Поведение |
|---|---|---|---|
| GPTBot / OAI-SearchBot | OpenAI | Нет | Только HTML из HTTP-ответа |
| ClaudeBot | Anthropic | Нет | Только HTML из HTTP-ответа |
| PerplexityBot | Perplexity | Минимальный | Преимущественно сырой HTML |
| Google-Extended / Googlebot | Частичный (Chromium) | Может ждать JS, но не гарантировано | |
| Bingbot | Microsoft | Частичный (Chromium) | Схож с Googlebot |
| YandexBot | Яндекс | Частичный | Рендерит часть JS |
| DeepSeekBot | DeepSeek | Нет | Только HTML из HTTP-ответа |
| PerplexityBot | Perplexity | Нет | Только HTML из HTTP-ответа |
Ключевой вывод: из 10 AI-провайдеров, которые мониторит GEO Scout, большинство используют краулеров без поддержки JavaScript. Google и Яндекс — частичное исключение, но и они не гарантируют полный рендеринг клиентских SPA.
Практическая проверка: что видит бот
Не верьте на слово — проверьте сами. Откройте терминал:
# Имитация GPTBot запроса к вашему сайту
curl -A "GPTBot/1.0" -s https://ваш-сайт.ru/ | grep -c "<p\|<h[1-6]\|<li"
# Сравните с тем, что реально содержит страница в браузере
# Если разница большая — AI-боты видят пустотуДля чистого React SPA ответ будет выглядеть примерно так:
<!DOCTYPE html>
<html lang="ru">
<head>
<title>Название компании</title>
<meta name="description" content="...">
</head>
<body>
<div id="root"></div>
<script src="/static/js/main.chunk.js"></script>
</body>
</html>AI-бот получает этот HTML, извлекает из него title и description, и не находит ничего больше. Весь контент — кто вы, что делаете, почему вам стоит доверять — существует только после выполнения JavaScript, которое бот не запускает.
Четыре подхода к рендерингу и их AI-friendliness
Server-Side Rendering (SSR)
SSR означает, что каждый HTTP-запрос обрабатывается сервером, который генерирует готовый HTML с контентом и возвращает его клиенту. AI-бот получает полностраничный HTML с первого запроса.
Плюсы для GEO: свежий контент при каждом запросе, персонализация, работа с авторизованными данными на стороне сервера.
Минусы: нагрузка на сервер при высоком трафике, чуть медленнее первый байт по сравнению с CDN-кэшем SSG.
Лучше использовать: для страниц с динамическим контентом — новости, цены из базы данных в реальном времени, персонализированные лендинги.
Static Site Generation (SSG)
SSG генерирует HTML во время сборки (build time). Готовые HTML-файлы раздаются с CDN. Любой бот, включая GPTBot, получает полный HTML мгновенно.
Плюсы для GEO: максимальная скорость (TTFB < 50 мс с CDN), стабильность, минимальная нагрузка на сервер. AI-бот получает контент ещё быстрее, чем при SSR.
Минусы: контент актуален на момент последней сборки. При частых изменениях нужно перезапускать build.
Лучше использовать: блог, документация, маркетинговые лендинги, страницы тарифов — всё, что меняется редко.
Incremental Static Regeneration (ISR)
ISR — промежуточный вариант между SSR и SSG. Страницы генерируются статически, но с заданным временем устаревания. При запросе после истечения TTL Next.js регенерирует страницу в фоне.
Плюсы для GEO: скорость CDN + свежесть контента. AI-бот всегда получает готовый HTML, который обновляется автоматически по расписанию.
Лучше использовать: страницы с часто обновляемыми данными — рейтинги, агрегированная статистика, публичные дашборды.
Client-Side Rendering (CSR / SPA)
CSR — это то, от чего нужно уходить на публичных страницах. HTML-заготовка, JavaScript загружается, выполняется и рендерит контент в браузере. AI-боты видят только заготовку.
Допустимое применение: защищённые части приложения за авторизацией. Dashboard пользователя, личный кабинет, внутренние инструменты — туда AI-краулеры всё равно не попадут (и не должны). Поэтому CSR для этих частей абсолютно оправдан.
Next.js 16: SSR и RSC как стандарт для GEO
Next.js 16 с app router делает правильный выбор архитектуры максимально простым: Server Components — это дефолт. Вам не нужно ничего настраивать специально — любой компонент без 'use client' является серверным и рендерится на сервере в HTML.
Серверные компоненты: базовый паттерн
// app/page.tsx — Server Component по умолчанию
// Никакого 'use client' — рендерится на сервере
// AI-бот получает готовый HTML с контентом
import { getTranslations } from 'next-intl/server'
export default async function HomePage() {
// Запросы к БД выполняются на сервере
const features = await getFeatures()
const t = await getTranslations('HomePage')
return (
<main>
<h1>{t('hero.title')}</h1>
<p>{t('hero.description')}</p>
<ul>
{features.map(feature => (
<li key={feature.id}>
<h2>{feature.name}</h2>
<p>{feature.description}</p>
</li>
))}
</ul>
</main>
)
}ISR в Next.js 16: новый синтаксис 'use cache'
Next.js 16 вводит директиву 'use cache' — декларативный способ управлять кэшированием на уровне компонента:
// app/blog/[slug]/page.tsx
'use cache'
import { cacheLife } from 'next/dist/server/use-cache/cache-life'
import { cacheTag } from 'next/dist/server/use-cache/cache-tag'
export default async function BlogPost({
params,
}: {
params: Promise<{ slug: string }>
}) {
const { slug } = await params
// Кэш живёт 1 час, обновляется в фоне
cacheLife({ stale: 3600, revalidate: 3600, expire: 86400 })
cacheTag(`blog-${slug}`)
const post = await getPost(slug)
return (
<article>
{/* Полный HTML с контентом отдаётся AI-ботам мгновенно */}
<h1>{post.title}</h1>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</article>
)
}Гибридная архитектура: публичное SSR + приватное CSR
/ → SSR/SSG (Server Components)
/pricing → SSG с ISR (статика, обновляется раз в день)
/blog/[slug] → SSG (статика, пересборка при публикации)
/about → SSG (статика)
/docs/[...slug] → SSG (статика)
/app/dashboard → CSR (Client Components, за авторизацией)
/app/settings → CSR (Client Components, за авторизацией)
/app/reports → CSR (Client Components, за авторизацией)
Cache-заголовки для AI-краулеров
AI-краулеры соблюдают HTTP cache-заголовки. Настройте их явно в next.config.ts:
// next.config.ts
const nextConfig = {
async headers() {
return [
{
// Публичные страницы: кэш на CDN на 24 часа
source: '/(about|pricing|blog/:slug*)',
headers: [
{
key: 'Cache-Control',
value: 'public, s-maxage=86400, stale-while-revalidate=3600',
},
],
},
{
// API и приватные страницы: без кэша
source: '/api/:path*',
headers: [
{
key: 'Cache-Control',
value: 'no-store',
},
],
},
]
},
}public, s-maxage=86400 — CDN кэширует страницу на сутки. GPTBot при повторном визите получит ответ от CDN за миллисекунды, а не ждёт origin-сервер.
Nuxt 3, Astro и SvelteKit: альтернативы для GEO
Если проект не на Next.js, выбор SSR/SSG решается в других фреймворках аналогичными инструментами.
Nuxt 3: универсальный рендеринг
Nuxt 3 по умолчанию использует Universal Rendering (SSR) — сервер рендерит первый HTML, затем клиент гидратирует. AI-боты получают полный контент с первого запроса.
// nuxt.config.ts
export default defineNuxtConfig({
// SSR включён по умолчанию — ничего настраивать не нужно
ssr: true,
// Для статических сайтов
nitro: {
prerender: {
routes: ['/', '/about', '/pricing', '/blog'],
crawlLinks: true, // автоматически обходит ссылки и пререндерит
},
},
// Hybrid rendering: некоторые маршруты — статика, другие — SSR
routeRules: {
'/': { prerender: true },
'/pricing': { swr: 86400 }, // ISR аналог
'/blog/**': { prerender: true },
'/app/**': { ssr: false }, // CSR для приложения за авторизацией
},
})Astro: Islands Architecture для максимально чистого HTML
Astro — идеальный выбор для контент-сайтов. По умолчанию отправляет нулевой JavaScript на клиент. HTML получается максимально чистым, что AI-краулерам только на руку.
// astro.config.mjs
import { defineConfig } from 'astro/config'
import node from '@astrojs/node'
export default defineConfig({
// SSR режим для динамических страниц
output: 'hybrid', // статика по умолчанию, SSR по запросу
adapter: node({ mode: 'standalone' }),
// Для статического сайта:
// output: 'static'
})---
// src/pages/blog/[slug].astro
// export const prerender = true — эта страница будет SSG
export const prerender = true
const { slug } = Astro.params
const post = await getPost(slug)
---
<html lang="ru">
<head>
<title>{post.title}</title>
<meta name="description" content={post.description} />
</head>
<body>
<!-- Чистый HTML без JS — AI-бот получает весь контент -->
<article>
<h1>{post.title}</h1>
<div set:html={post.content} />
</article>
</body>
</html>SvelteKit: гибкий рендеринг по маршруту
// src/routes/+layout.ts
// Настройка рендеринга на уровне маршрута
export const prerender = false // SSR по умолчанию
export const ssr = true// src/routes/blog/[slug]/+page.ts
// Статическая генерация для блога
export const prerender = true
export async function entries() {
const posts = await getAllPosts()
return posts.map(post => ({ slug: post.slug }))
}Сравнительная таблица фреймворков
| Фреймворк | SSR | SSG | ISR/SWR | Hybrid | AI-friendliness |
|---|---|---|---|---|---|
| Next.js 16 | Server Components по умолчанию | generateStaticParams | 'use cache' / revalidate | App router, route segments | Высокая |
| Nuxt 3 | Включён по умолчанию | prerender: true | swr в routeRules | routeRules | Высокая |
| Astro | output: 'server' | output: 'static' (дефолт) | Нет встроенного | output: 'hybrid' | Очень высокая |
| SvelteKit | ssr: true (дефолт) | prerender: true | Через CDN | По маршруту | Высокая |
| React SPA | Нет | Нет | Нет | Нет | Очень низкая |
| Vue SPA | Нет | Нет | Нет | Нет | Очень низкая |
Когда CSR всё-таки уместен
Не всё нужно рендерить на сервере. Client-Side Rendering абсолютно оправдан для:
Dashboard за авторизацией. Личный кабинет, аналитика, настройки профиля — всё это находится за логином. AI-краулеры туда не попадут, потому что вы правильно настроили robots.txt и закрыли /app/*, /dashboard/*, /account/*. CSR здесь оптимален: богатая интерактивность, отсутствие лишних серверных запросов.
Интерактивные виджеты внутри SSR-страниц. Фильтры, калькуляторы, интерактивные таблицы — можно оборачивать в Client Components внутри общей SSR-оболочки. AI-бот получит статическую часть страницы (заголовки, описания, основной контент), а интерактивность будет работать для пользователей после гидратации.
Внутренние инструменты. Административные панели, инструменты команды, developer tools — там AI-краулерам не место в принципе.
Как быстро мигрировать SPA-сайт
Полная переписка с нуля редко бывает необходима. Практический план миграции за 2-4 недели:
Шаг 1: аудит страниц (день 1-2)
Составьте список всех публичных URL. Для каждого ответьте: нужен ли этот контент AI-краулерам? Обычно это:
- Главная страница
- Страницы продуктов и услуг
- Блог и статьи
- Документация
- О компании
- Pricing / тарифы
- FAQ
Всё остальное (личный кабинет, настройки, дашборды) остаётся SPA.
Шаг 2: проверка текущего состояния (день 2-3)
# Проверяем, что видит GPTBot на каждой ключевой странице
for url in "/" "/pricing" "/about" "/blog"; do
echo "=== $url ==="
curl -A "GPTBot/1.0" -s "https://ваш-сайт.ru$url" \
| python3 -c "
import sys
from html.parser import HTMLParser
class TextExtractor(HTMLParser):
def __init__(self):
super().__init__()
self.text_count = 0
self.in_body = False
def handle_starttag(self, tag, attrs):
if tag == 'body':
self.in_body = True
def handle_data(self, data):
if self.in_body and data.strip():
self.text_count += len(data.strip())
parser = TextExtractor()
parser.feed(sys.stdin.read())
print(f'Символов контента: {parser.text_count}')
"
doneЕсли для ключевых страниц результат — менее 200 символов, ваш SPA невидим для AI-краулеров.
Шаг 3: поэтапный перевод на SSR/SSG
Для Next.js проектов переход от Pages Router с CSR к App Router с Server Components:
// Было: pages/about.tsx (CSR с useEffect)
import { useState, useEffect } from 'react'
export default function AboutPage() {
const [company, setCompany] = useState(null)
useEffect(() => {
fetch('/api/company').then(r => r.json()).then(setCompany)
}, [])
if (!company) return <div>Loading...</div>
return <div>{company.description}</div> // AI-боты видят только Loading...
}// Стало: app/about/page.tsx (Server Component)
// AI-боты получают полный HTML сразу
async function getCompanyData() {
// Прямой запрос к БД на сервере, без API-roundtrip
const supabase = await createClient()
const { data } = await supabase.from('company').select('*').single()
return data
}
export default async function AboutPage() {
const company = await getCompanyData()
return (
<div>
<h1>{company.name}</h1>
<p>{company.description}</p>
</div>
)
}Шаг 4: prerender и schema
После перевода на SSR/SSG добавьте JSON-LD разметку прямо в серверный компонент — она гарантированно попадёт в HTML, который видят AI-боты:
// app/pricing/page.tsx
export default async function PricingPage() {
const plans = await getPlans()
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'SoftwareApplication',
name: 'GEO Scout',
offers: plans.map(plan => ({
'@type': 'Offer',
name: plan.name,
price: plan.price,
priceCurrency: 'RUB',
})),
}
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<main>
{/* Контент страницы */}
</main>
</>
)
}CDN и edge rendering: последний уровень оптимизации
После перехода на SSR/SSG AI-боты уже получают контент. Следующий уровень — скорость доставки этого контента.
Edge rendering означает, что SSR выполняется не на центральном сервере, а на ближайшем к боту edge-узле CDN. Для GPTBot, который обходит тысячи сайтов в секунду, скорость ответа влияет на глубину краулинга.
// app/page.tsx — edge runtime для минимального TTFB
export const runtime = 'edge'
export default async function HomePage() {
// Выполняется на edge-узле CDN, ближайшем к краулеру
return <main>/* контент */</main>
}Для статического контента (SSG) преимущества CDN очевидны: HTML уже сгенерирован, CDN отдаёт его с кэша за миллисекунды. Vercel, Cloudflare Pages, AWS CloudFront автоматически кэшируют SSG-страницы на глобальной сети.
Измерение эффекта: до и после миграции в GEO Scout
После технической миграции важно убедиться, что AI-боты действительно начали получать контент — и что это влияет на упоминаемость бренда.
Команда GEO Scout предоставляет ежедневный мониторинг Mention Rate и Share of Voice в 10 AI-провайдерах. Паттерн после правильной миграции на SSR/SSG выглядит так:
- Неделя 1-2: GPTBot и ClaudeBot начинают индексировать полный контент страниц
- Неделя 2-4: ChatGPT и Claude обновляют свои знания о бренде на основе проиндексированного контента
- Месяц 2+: стабильный рост Mention Rate по промптам, где ранее бренд отсутствовал
Это верифицируется через мониторинг: та же выборка промптов отправляется ежедневно в 10 AI-провайдеров, и динамика становится видна в истории. Инструменты платформы — GEO-аудит сайта, анализ логов AI-ботов и Командный центр — помогают связать технические изменения с изменением видимости.
Типичные результаты после миграции
| Метрика | До миграции (SPA) | После миграции (SSR/SSG) |
|---|---|---|
| Контент, видимый GPTBot | title + description | Полный текст страниц |
| Mention Rate в ChatGPT | Низкий или нулевой | Рост на 30-80% за 4-8 недель |
| Скорость индексации | Зависит от рендеринга JS | Мгновенно после деплоя |
| TTFB для краулера | 500-2000 мс (SSR на сервере) | 20-50 мс (SSG на CDN) |
| Работа JSON-LD в AI | Не гарантирована (JS-зависима) | 100% гарантирована (в HTML) |
Чек-лист: технический аудит рендеринга для GEO
Диагностика
- Проверить curl-тестом:
curl -A "GPTBot/1.0" https://сайт.ru/ | wc -c— если менее 5 000 байт, скорее всего SPA - Сравнить HTML в curl vs HTML в браузере (view-source) — разница = невидимый для AI контент
- Проверить robots.txt: публичные страницы доступны GPTBot, ClaudeBot, PerplexityBot
- Проверить логи сервера: приходят ли запросы от AI-краулеров, и какой TTFB они получают
Архитектура
- Публичные страницы (главная, продукт, блог, about, pricing) — SSR или SSG
- Блог и документация — SSG с автопересборкой при публикации
- Динамический контент с редкими обновлениями — ISR / SWR
- Dashboard и личный кабинет — CSR (за авторизацией, боты не заходят)
- Нет
useEffectдля загрузки основного контента на публичных страницах
Cache-заголовки
- Публичные страницы:
Cache-Control: public, s-maxage=86400, stale-while-revalidate=3600 - API endpoints:
Cache-Control: no-store - Приватные страницы:
Cache-Control: private, no-store - CDN настроен для кэширования SSG-страниц
Контент в HTML
- JSON-LD разметка рендерится на сервере (не через
useEffect) - Основной текст страницы присутствует в серверном HTML
- Мета-теги (title, description, og:*) генерируются на сервере
- Заголовки H1-H3 присутствуют в серверном HTML
- FAQ-блоки с разметкой FAQPage рендерятся на сервере
Мониторинг эффекта
- Настроен ежедневный мониторинг Mention Rate в GEO Scout
- Зафиксирован baseline до миграции
- Отслеживается динамика по ключевым AI-провайдерам после деплоя
- Логи сервера анализируются на предмет изменения поведения AI-краулеров
Переход с клиентского рендеринга на SSR или SSG — одно из немногих технических изменений, которое напрямую и измеримо влияет на AI-видимость бренда. Это не оптимизация «про запас», это фундаментальное требование для присутствия в ответах ChatGPT, Claude, Perplexity и Google AI. Если GEO-аудит вашего сайта показывает, что AI-боты видят пустую страницу — это первое, что нужно исправить, прежде чем заниматься контентной оптимизацией.
Зарегистрируйтесь на geoscout.pro бесплатно и проверьте, как GPTBot, ClaudeBot и PerplexityBot видят ваш бренд прямо сейчас. Бесплатный тариф включает мониторинг 3 промптов в нескольких AI-провайдерах без привязки карты.
Частые вопросы
Рендерят ли AI-боты JavaScript?
Влияет ли SSR на видимость бренда в ChatGPT и Claude?
Что лучше для GEO: SSR или SSG?
Нужно ли переписывать весь SPA-сайт под SSR?
Как проверить, что AI-бот видит на моём сайте?
Как cache-заголовки влияют на AI-краулеры?
Поддерживает ли Astro SSR для AI-видимости?
Похожие статьи
Лог-анализ AI-ботов: GPTBot, ClaudeBot, PerplexityBot и OAI-SearchBot
Полный разбор AI-ботов в логах сайта: user-agent, IP-диапазоны, частота обхода, что индексируется и как управлять через robots.txt и firewall.
OAI-SearchBot, GPTBot и robots.txt: как управлять доступом AI к сайту
Чем отличаются OAI-SearchBot, GPTBot и ChatGPT-User, как настраивать robots.txt без путаницы и как не закрыть сайт от поиска ChatGPT случайно.
Документация для GEO: как оформить docs-сайт SaaS для ChatGPT, Алисы и Perplexity
Как устроить документацию SaaS под GEO: docs hub, getting started, API reference, FAQ, limits, migration notes, локальные сценарии для СНГ и контент, который AI чаще всего цитирует.