Я уже пять лет совмещаю разработку Progressive Web Apps (PWA) с SEO-оптимизацией. Сегодня хочу поделиться своим опытом перехода на оффлайн-режим без потери видимости в поисковиках. Да, это возможно, но только если не наступать на те же грабли, что и я. Поехали!
По какой причине PWA и SEO это не враги, а партнеры
Примерно через месяц Яндекс.Вебмастер показал, что 30% страниц выпали из индекса. Паника. Оказалось, я забыл, что поисковые боты не пользователи. Они не ждут, пока Service Worker загрузит контент. Им нужно сразу получать HTML, а не пустой shell. Так начался мой путь к балансу между оффлайн-возможностями и SEO.
Ошибка №1: Service Worker, который «ломает» индексирование
Проблема:
Мой первый Service Worker кэшировал только статику (CSS, JS), но не HTML. Для пользователя всё работало идеально: страницы грузились из кэша. Но YandexBot видел пустой div с надписью «Loading…». Результат — контент не индексировался.
Решение:
Я переписал Service Worker, добавив стратегию Stale-While-Revalidate для HTML. Теперь бот сразу получает серверный HTML, а пользователь — актуальную версию из кэша при повторных визитах.
Пример кода:
// service-worker.js self.addEventListener('fetch', (event) => { if (event.request.mode === 'navigate') { event.respondWith( caches.match(event.request) .then((cachedResponse) => { const fetchPromise = fetch(event.request) .then((networkResponse) => { // Обновляем кэш caches.open('dynamic-cache').then((cache) => { cache.put(event.request, networkResponse.clone()); }); return networkResponse; }); return cachedResponse || fetchPromise; }) ); } else { // Для статики используем Cache First event.respondWith( caches.match(event.request) .then((response) => response || fetch(event.request)) ); } });
Ошибка №2: Дублирование контента из-за оффлайн-кэша
Проблема:
После внедрения PWA в индексе появились URL вида /post-123 и /post-123?offline=true. Это произошло из-за того, что Service Worker добавлял параметр к URL при загрузке из кэша. Яндекс воспринял это как дубли.
Решение:
Я изменил логику: вместо параметров стал использовать Cache API с ключами на основе URL. Также добавил канонические теги в <head> каждой страницы.
Пример:
<!-- В шаблоне HTML --> <link rel="canonical" href="https://site.com/post-123" />
Ошибка №3: Динамический контент не индексируется
Проблема:
На сайте был блог с лентой статей, подгружаемых через API. В оффлайне PWA показывала кэшированные данные, но бот не видел их, так как JavaScript не выполнялся.
Решение:
Я внедрил Server-Side Rendering (SSR) для критического контента + предварительное кэширование API-запросов через Workbox.
Код предварительного кэширования:
// workbox-config.js module.exports = { runtimeCaching: [{ urlPattern: /\/api\/posts/, handler: 'StaleWhileRevalidate', options: { cacheName: 'api-cache', expiration: { maxEntries: 50, maxAgeSeconds: 24 * 60 * 60, // 1 день }, }, }], };
Сравнительные тесты: PWA с SEO-оптимизацией и без
Я провел эксперимент на двух версиях сайта:
| Параметр | PWA без SEO-оптимизации | PWA с SEO-оптимизацией |
|---|---|---|
| Скорость загрузки (Lighthouse) | 98 | 96 |
| Индексируемые страницы | 45% | 100% |
| Ошибки дублирования | 12 | 0 |
| Позиции в ТОП-10 | ↓ на 30% | ↑ на 15% |
Вывод: Небольшая потеря в скорости (из-за SSR) компенсируется ростом видимости.
Как проверить, видит ли Google ваш оффлайн-контент
- Используйте Mobile-Friendly Test:
Загрузите URL в инструмент. Если видите контент — всё ок. Если нет, бот не получил HTML. - Эмуляция оффлайна в Lighthouse:
В Chrome DevTools откройте вкладку Lighthouse → установите галочку «Simulate offline». Запустите тест. Если в отчете есть контент — PWA работает. - Проверка через curl:
Запустите в терминале:curl -A "Googlebot" https://ваш-сайт/страница
Убедитесь, что в ответе есть HTML-контент, а не только тег
<app-root></app-root>.
Главные правила PWA для SEO, которые я вывел
- Не доверяйте Service Worker боту. Всегда отдавайте серверный HTML при первом посещении.
- Кэшируйте API-запросы, но не полагайтесь только на них. Используйте SSR или Prerendering.
- Тестируйте как пользователь и как бот. Инструменты вроде Screaming Frog помогут найти «слепые зоны».
- Workbox — ваш друг. Готовые стратегии кэширования спасут от велосипедов.
Что в итоге?
После полугода проб и ошибок мой PWA-сайт стабильно держится в ТОП-3 по высокочастотным запросам. Да, оффлайн-режим требует жертв: чуть больше кода, чуть сложнее архитектура. Но когда пользователь пишет «Ваш сайт загрузился в метро без интернета — это волшепство!», я понимаю, что игра стоила свеч.
Если хотите копипастнуть мой код, то пожалуйста! Но не забудьте адаптировать его под ваш стек. И да, при переходе на оффлайн-режим всегда держите в уме SEO. Иначе рискуете провести ночь с Яндекс.Вебмастер и чашкой холодного кофе 🙂
Поддержка автора осуществляется с помощью специальной формы ниже, предоставленной сервисом «ЮMoney». Все платёжные операции выполняются на защищённой странице сервиса, что обеспечивает их корректность и полную безопасность.


