Міграція на SPA коштувала −25% органіки. Як ми повернули зростання – і навіщо сайту «реліз-гейт»
Міграція сайту на SPA – це той випадок, коли рішення ухвалюють розробники, а наслідки першим бачить маркетолог: у звіті з органічного трафіку. Розповідаємо кейс нашого клієнта – національної мережі ремонту турбокомпресорів з інтернет-магазином на ~3000 товарів. У кейсі дві ітерації фронтенду: перша – SPA на JavaScript із самописним фреймворком, після якої органіка впала; друга – переписування на React із SSR, яке пройшло через реліз-гейт. Сюжет чесний, без «переїхали ідеально» і без «усе пропало»: просадка й зупинка зростання при втриманих топах, діагностика, програма виправлень, реліз через формальні критерії приймання – і повернення до росту.
Одразу термінологія, щоб далі говорити однією мовою. SPA (Single Page Application) – застосунок, де браузер отримує майже порожній HTML, а весь вміст домальовує JavaScript. SSR (Server-Side Rendering) – підхід, за якого сервер віддає вже готовий HTML з текстом, заголовками й посиланнями, а JavaScript лише «оживлює» сторінку. Для користувача різниця непомітна. Для пошукового бота – критична.
Акт 1. Контекст: стабільна органіка і бізнес-рішення про переїзд
Клієнт – мережа з філіями по Україні: ремонт турбокомпресорів плюс каталог запчастин на ~3000 SKU, двомовний сайт. Органіка стабільна: за SimilarWeb – близько 6 941 десктоп-візитів на місяць. Двигун каналу – категорії й картки товарів: для e-commerce саме вони збирають комерційний попит (як це працює системно – розбирали в гайді про [SEO для інтернет-магазинів → pillar-3]).
Рішення про переїзд зі старого PHP-сайту на сучасний JavaScript-стек ухвалили з міркувань продукту: швидший інтерфейс, зручність розробки, редизайн. Перша ітерація виглядала так: бекенд – Node.js, фронтенд – SPA на JavaScript із власним, самописним фреймворком. Класична ситуація, яку ми бачимо регулярно: стек обрали з погляду розробки – а SEO-наслідки не прораховував ніхто.
Акт 2. Просадка: −25% трафіку і зупинка зростання
Нову SPA-версію задеплоїли [дата деплою, 01–02.2026]. Одразу після переїзду органічний десктоп-трафік просів на 25%: з ~6 941 до 5 197 візитів на місяць.
Перше, що хочеться сказати в такій ситуації, – «ринок просів». Ми перевірили. Ринок і справді був неспокійний, але неоднорідний:
Сайт | Динаміка 02.2026 |
|---|---|
Клієнт | −25% |
Конкурент №1 | −52% |
Конкурент №2 | +26% |
Один гравець втратив половину, інший – виріс на чверть. Списати все на сезон чи ринок не вийшло. Причину треба було шукати в самому сайті.
І тут важлива чесна деталь, яка відрізняє цей кейс від історій про катастрофу. Сайт не обвалився: за ключовими запитами він загалом утримався в топах. Але він перестав рости – при живому попиті й активному ринку. Для власника така картина часто виглядає як «усе гаразд, просто період такий». Для нас стагнація на тлі збереженого попиту – симптом нездоров’я. Саме вона, а не самі лише −25%, стала сигналом іти в глибокий аудит.
Акт 3. Діагностика: що насправді побачив Googlebot
Тут почалася найважливіша частина кейсу. Ми зняли сторінки за протоколом «сирий HTML без виконання JavaScript» – тобто подивилися на сайт очима бота в момент першого запиту (окрема причина робити це власним протоколом: датацентрові запити сайт відсікав на рівні Cloudflare, тож питання «звідки бачить бот» вимагало окремої перевірки).
Одразу розставимо акценти, бо тут легко перекрутити. Googlebot не був «сліпим»: контент на сайті існував, і після рендерингу JavaScript бот його отримував. Проблема в іншому – контенту не було в HTML. Він жив у JavaScript-контейнері, і цей контейнер тягнув на кожну сторінку майже всю структуру сайту. Первинний аудит звівся до чотирьох знахідок:
- Немає HTML. У сирому HTML – нуль контенту: весь текст, посилання й заголовки сиділи всередині JS-контейнера.
- Бот отримував дані не з першого заходу. Перший запит віддавав порожній каркас; справжній вміст Google бачив лише після рендерингу JavaScript – з черги, яка живе своїм розкладом.
- Великий розмір сторінок. До 1 МБ HTML на сторінку при нормі <150 КБ.
- Відкриті дані для парсингу. JSON-контейнер з контентом і майже повною структурою сайту лежав відкритим на кожній сторінці – будь-який парсер міг зняти каталог і всі SEO-тексти одним запитом.
У цифрах перший запит бота виглядав так:
Що перевіряли (сирий HTML) | Факт після переїзду (аудит 03.2026) |
|---|---|
Посилання <a href> у <body> поза <script> | 0 (із 346 на головній для користувача) |
Теги H1 | 0 |
Текст поза скриптами | 0 символів |
Зображення | 0 |
Вага HTML сторінки | до 1 МБ при нормі <150 КБ; /site-map – 5,5 МБ |
Інлайн-payload | 727 КБ в одному скрипті |
Окрема деталь, яку люблять розробники: змінна з усім цим станом називалася ssrdata – але жодного Server-Side Rendering вона не робила.
Масштаб контейнера найкраще показує сторінка послуг: 303 теги H2, з яких по темі – лише 6. Решта – SEO-тексти інших сторінок, що «їхали» в payload меню на кожну сторінку двома мовами (~90 КБ чужого контенту, на сторінці контактів – 26 повних текстів інших розділів). 43% JSON-payload – внутрішні дублі; власний контент сторінки – 2,9%.
Чому це гальмує ріст – механіка простими словами. Google обробляє JavaScript-сайти у фази: сканування сирого HTML відбувається одразу, а рендеринг JavaScript стоїть в окремій черзі, яка може розтягуватися (Google Search Central: Understand JavaScript SEO Basics).
Ключова інженерна деталь: нові URL Google відкриває через посилання, а посилання бот знаходить лише в елементах <a> з атрибутом href. Немає їх у сирому HTML – краулер не може вчасно будувати граф зв’язків для нових і оновлених сторінок: це удар одразу по discovery і краулінговому бюджету. Старі сторінки ранжуються за збереженим історичним індексом – тому топи трималися. А нові посадкові, оновлені картки і свіжі тексти підхоплюються «другим темпом» і зависають «сиротами» – тому росту не було: все нове бот бачив пізно і дорого.
Для фахівців – врізка: у типових провальних міграціях на SPA втрати сягають −60…80% органіки. Тут просадка зупинилася на −25%, і це не везіння. При переїзді команда зберегла 100% URL-структури (нуль 404), коректні hreflang, canonical і Schema.org. Це «міграційна гігієна» – саме вона втримала позиції в топах, поки рендеринг-борг з’їдав потенціал росту. Як ми знаходимо такі речі системно – окремий матеріал: [кейс технічного SEO-аудиту → article-6].
Акт 4. Програма дій: два паралельні треки
Виправлення розклали на два треки, які йшли одночасно.
Трек А – технічний. Вимоги до розробників: впровадити SSR (H1, текст, меню, посилання на товари й зображення – у сирому HTML до виконання JS); «payload-дієта» – вичистити з пейлоада чужі SEO-тексти, дублікати й невикористовувану мовну версію з планом 727 КБ → 60–90 КБ; виправити soft-404, роздуті title, пагінацію; додати lazy loading і комерційну Schema.org (ItemList / Product / AggregateRating). Команда розробки вирішила закривати ці вимоги другою ітерацією – переписуванням фронтенду з самописного фреймворку на React із SSR.
Трек Б – контентно-структурний. Поки розробники будували SSR, працювали з тим, що не залежить від релізу: нові посадкові під вузькі послуги (актуатор, діагностика) й регіональні сторінки; переоптимізація сторінок під реальний інтент – показовий випадок: сторінка була заточена під «очистку» DPF, а частотний запит ринку – «промивка»; системна робота з відгуками в Google Business Profile.
Local SEO дало найнаочніший урок кейсу. Філія в одному з обласних центрів тримає Local Pack #1 з рейтингом 4.9 і 143 відгуками – проти конкурента з 839 відгуками, але рейтингом 4.3. Якість відгуків важить більше за кількість.
Акт 5. Реліз-гейт: чому ми не пропустили реліз розробників
Коли розробники представили другу ітерацію – фронтенд, переписаний на React із SSR, – її можна було просто випустити. Ми не випустили.
Аудит прототипу за тим самим протоколом сирого HTML показав 9 регресів проти 5 покращень: 50 битих зображень, H1 головної «прибитий» до першого слайда рекламного банера, canonical на чужий хост, відсутній sitemap, конфліктний robots.txt. Другого падіння трафіку бізнес міг і не пережити.
Розробники поспішали. Ми – ні.
Прототип повернули на доопрацювання – не з коментарем «щось не так», а з формальними критеріями приймання, які перевіряються на сирому HTML без виконання JS:
Критерій приймання релізу | Поріг |
|---|---|
Посилання меню й товарів як <a href> | ≥30 у сирому HTML |
H1 | 1, релевантний сторінці |
Текст поза скриптами | ≥1500 символів |
Вага сторінки | <150 КБ |
Биті зображення | 0 |
Sitemap | валідний |
Canonical | self-referencing |
Це і є «реліз-гейт»: страховка, яка коштує один аудит – і завжди дешевша за друге падіння трафіку. Саме тому ми вважаємо, що SEO-вимоги мають сидіти в ТЗ на розробку сайту з першого дня, а не з’являтися після релізу.
Акт 6. Реліз і цифри «до → після»
React-версію з SSR викатили на прод [точна дата SSR-релізу, 08.2026]. Контрольний аудит за критеріями приймання: 7 із 9 виконано повністю. Ключові виміри:
Метрика | Після переїзду (03.2026) | Після SSR-релізу (22.08.2026) |
|---|---|---|
Вага HTML головної | 978–1210 КБ | 108 КБ (−91%) |
<a href> у сирому HTML головної | 0 | 179 |
H1 у сирому HTML | 0 | 1 на кожній сторінці |
Текст поза скриптами (головна) | 0 символів | 11 093 |
Інлайн-payload | 727 КБ | 32 КБ (−96%) |
H2 на сторінці «Ремонт турбін» | 303 | 10 |
Чужі SEO-тексти на сторінках | ~90 КБ | 0 |
Сторінка /site-map | 5 505–5 687 КБ | 136 КБ (−98%) |
Неіснуючий URL | 200 (soft-404) | 404 |
Title пагінації | дублі на 148 сторінках | унікальні («Сторінка №2»…) |
Schema категорій | Article (нерелевантна) | ItemList + Product + Offer + BreadcrumbList + FAQPage |
Schema товару | базова | Product + Brand + Offer + AggregateRating + FAQPage |
Биті зображення (головна/категорія) | 18 / 32 (на прототипі) | 0 / 0 |
loading=”lazy” | 0 із 63 зображень | 91 із 94 (hero – eager + fetchpriority=high) |
TTFB / повне завантаження головної | FCP 1,7 с «на межі» | 206 мс / 2,0 с |
Sitemap-інфраструктура | частково | 2 індекси × 15 карт + карта зображень (10,5 тис. URL) |
А тепер – найважливіше про чесність цифр. Зростання почалося ще до SSR-релізу: за GA4 клієнта, organic + direct додали +20% за 05–08.2026 [скріншот GA4]; незалежний зріз SimilarWeb від 12.08.2026 – 37,3 тис. візитів за 3 місяці, +16,8% за останній місяць, органіка – топ-джерело з часткою 36%. Це результат контентно-структурного треку Б – не SSR. Ефект самого SSR-релізу на індексацію й позиції фіксується у Search Console окремо, через 4–6 тижнів після релізу [графік GSC – вставити]. Ми свідомо не змішуємо ці два ефекти: методологія дала результат ще до головного технічного фікса – і це сильніший аргумент, ніж «SSR усе врятував».
Що ще не закрито – говоримо прямо
Кейс не закінчений, і ми не вдаватимемо, що все ідеально. У беклозі після релізу: H1 головної досі прив’язаний до першого слайда банера (хотфікс №1); окремі важкі каталожні шаблони досі важать 210–278 КБ при цілі <150 КБ – головна вже 108 КБ, але не всі типи сторінок дотяглися до неї (і це вже точно не 1 МБ); довгі title карток товарів (140–156 символів – було 447); alt-атрибути відсутні у ~65% зображень; паралельні namespace /catalog/* і /category/*; одне внутрішнє посилання на 404 зі сторінки послуг. Це нормальний стан живого проєкту: реліз закрив критичне, далі – планова робота.
Як ми ведемо міграції в ADS group
Міграція – це завжди дві команди в одній зв’язці. У нас це влаштовано так: Dev-Unit будує застосунок, SEO-Unit формулює вимоги до сирого HTML ще на етапі ТЗ, веде діагностику за власним аудит-протоколом – і має право не пропустити реліз, поки критерії приймання не виконані. Саме ця конструкція в кейсі спрацювала двічі: спершу знайшла справжню причину падіння, потім зупинила реліз з 9 регресами. Якщо вам належить переїзд на новий фронтенд – правильний момент прийти на технічний SEO-аудит – до релізу, а не після падіння.
Чек-лист: міграція на SPA без SEO-катастрофи
До міграції: зафіксувати базлайн (трафік, позиції, повний список URL); внести SSR або пре-рендеринг у ТЗ підряднику – «потім докрутимо» не працює; зберегти 100% URL або підготувати мапу 301.
Критерії приймання релізу – перевіряються на сирому HTML, без виконання JS: посилання меню й товарів як <a href>; один релевантний H1; основний текст присутній; вага сторінки <150 КБ. Canonical – тільки self-referencing. Sitemap – валідний, без сміттєвих URL. 404 віддає 404, а не soft-200. Нуль битих зображень, lazy loading на всьому, крім hero.
Після релізу: зняти стейджинг-noindex за регламентом; прогнати ключові шаблони через GSC Live Test; поставити annotation дати релізу в аналітиці; моніторити статистику сканування (розмір відповіді має впасти, кількість сканувань – зрости); контрольний зріз позицій через 4–6 тижнів.
Окремо: WAF/Cloudflare може різати краулерів незалежно від robots.txt – виняток для Verified Bots обов’язковий.
Це критерії саме для SPA-переїзду. Повна процедура будь-якої міграції – домен, CMS, структура URL, карта редиректів, staging – у нашому окремому матеріалі: [чек-лист міграції сайту → article-5].
Міграція на SPA не вирок для органіки – вирок, коли сирий HTML порожній, а релізи виходять без критеріїв приймання. Фреймворк тут ні до чого: у цьому кейсі падіння дав самописний JavaScript-фронтенд без SSR, а відновлення закріпила React-версія, яку пропустили на прод тільки через реліз-гейт. Бізнес втратив 25% органіки через те, що SEO покликали після деплою, – і зростання стартувало ще до головного технічного фікса, коли з’явилися діагностика і два треки робіт.
Якщо ви плануєте редизайн чи зміну фронтенду – порахуйте вартість аудиту до міграції та порівняйте з ціною кількох місяців просілої органіки. Замовте аудит перед міграцією або розробку, де SEO-вимоги закладені в ТЗ – обидва шляхи дешевші за відновлення після падіння.
Часті питання
Чи шкодить React SEO?
Ні – шкодить будь-який фронтенд, що віддає порожній сирий HTML. У нашому кейсі падіння спричинив самописний JavaScript-фреймворк без SSR, а React-версія з SSR якраз закріпила відновлення. Фреймворк – самописний, React чи Vue – вторинний; первинне те, що бот бачить у HTML до виконання скриптів.
Скільки Google рендерить JavaScript?
Сканування сирого HTML відбувається одразу, а рендеринг JS стоїть в окремій черзі: Google документує, що сторінка може чекати секунди, але може й довше. Для каталогу на тисячі SKU ця затримка множиться на кожну сторінку – тому контент у сирому HTML надійніший.
У нас уже впав трафік після редизайну. Що робити спершу?
Зняти сторінки в сирому HTML без виконання JS і порівняти з тим, що бачить користувач: посилання, H1, текст, вага. Якщо бот бачить порожнечу – причина знайдена, і вона лагодиться. Паралельно перевірити, чи збереглися URL, canonical і hreflang.
Коли повернеться трафік після виправлень?
Google строків переіндексації не документує, тому чесна відповідь – залежить від масштабу сайту й глибини проблеми. У цьому кейсі контентний трек дав +20% за три місяці ще до SSR-релізу; ефект самого SSR оцінюється через 4–6 тижнів після релізу за GSC.

Час вийшов



