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

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