🎯 Бесплатно: первая проверка AI-видимости за 5 минут, затем обновление раз в 7 днейПопробовать →

13 мин чтения

SSR, SSG и ISR для AI-краулеров: почему JavaScript-only сайты теряют видимость

Почему AI-боты не рендерят JS: как SSR, SSG и ISR обеспечивают видимость в ChatGPT, Perplexity, Claude и Google AI Overviews.

Владислав Пучков
Владислав Пучков
Основатель GEO Scout, эксперт по GEO-оптимизации

Техническая архитектура сайта напрямую определяет, будет ли ваш бренд виден в 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-SearchBotOpenAIНетТолько HTML из HTTP-ответа
ClaudeBotAnthropicНетТолько HTML из HTTP-ответа
PerplexityBotPerplexityМинимальныйПреимущественно сырой HTML
Google-Extended / GooglebotGoogleЧастичный (Chromium)Может ждать JS, но не гарантировано
BingbotMicrosoftЧастичный (Chromium)Схож с Googlebot
YandexBotЯндексЧастичныйРендерит часть JS
DeepSeekBotDeepSeekНетТолько HTML из HTTP-ответа
PerplexityBotPerplexityНетТолько 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 }))
}

Сравнительная таблица фреймворков

ФреймворкSSRSSGISR/SWRHybridAI-friendliness
Next.js 16Server Components по умолчаниюgenerateStaticParams'use cache' / revalidateApp router, route segmentsВысокая
Nuxt 3Включён по умолчаниюprerender: trueswr в routeRulesrouteRulesВысокая
Astrooutput: 'server'output: 'static' (дефолт)Нет встроенногоoutput: 'hybrid'Очень высокая
SvelteKitssr: 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)
Контент, видимый GPTBottitle + 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?
Большинство AI-краулеров — нет. GPTBot, ClaudeBot и PerplexityBot получают «сырой» HTML без выполнения JavaScript. Google AI Overview и Bing AI используют тот же Chromium-рендерер, что и поисковые боты, и могут выполнять JS частично, но не гарантированно. Если ваш сайт — чистый SPA без SSR/SSG, AI-боты увидят пустой `<div id="root"></div>`.
Влияет ли SSR на видимость бренда в ChatGPT и Claude?
Да, напрямую. GPTBot и ClaudeBot читают HTML-ответ сервера. Если страница отдаёт готовый контент (SSR или SSG), боты извлекают текст, заголовки, structured data и метатеги. Если страница требует JS для рендеринга — боты видят пустой контейнер и не получают никакой информации о бренде.
Что лучше для GEO: SSR или SSG?
Для статичного маркетингового контента (лендинги, блог, документация) — SSG является оптимальным выбором: страницы полностью готовы ещё до запроса, отдаются с CDN с минимальной задержкой, и AI-боты получают максимально быстрый доступ к контенту. SSR предпочтителен для динамического контента с персонализацией. ISR — компромисс между ними для данных, которые меняются редко.
Нужно ли переписывать весь SPA-сайт под SSR?
Нет. Оптимальная стратегия — гибридный рендеринг: публичные страницы (главная, продукт, блог, pricing, о компании) переводятся на SSR/SSG, а приложение за авторизацией остаётся SPA/CSR. В Next.js это решается через app router: Server Components по умолчанию, Client Components только там, где нужна интерактивность.
Как проверить, что AI-бот видит на моём сайте?
Используйте curl без JavaScript: `curl -A "GPTBot/1.0" https://ваш-сайт.ru/` — если в ответе пустой `<div>` или минимум текста, AI-боты видят то же самое. Сравните с тем, что видит браузер. Разница — это невидимый для AI контент.
Как cache-заголовки влияют на AI-краулеры?
AI-краулеры уважают стандартные HTTP cache-заголовки. `Cache-Control: public, s-maxage=3600` позволяет CDN кэшировать страницу и отдавать ботам мгновенно. `no-store` или `private` означает, что каждый запрос будет идти к origin-серверу. Для SSG-страниц рекомендуется `s-maxage=86400, stale-while-revalidate=3600`.
Поддерживает ли Astro SSR для AI-видимости?
Да. Astro в режиме `output: "server"` или `output: "hybrid"` отдаёт готовый HTML на каждый запрос. Astro особенно хорош для контент-сайтов: по умолчанию отправляет нулевой JS на клиент (Islands Architecture), что означает максимально чистый HTML для AI-краулеров.