Закрытый контент без клоакинга: как отдать файлы по кодовому слову
«Вся страница за паролем» — ноль органики. «Роботу полный текст, человеку гейт» — санкция на весь домен. Рабочая середина между ними.
На сайте есть материалы к видео: разбор открыт всем, а файлы — PDF-гайды, конфиги, шаблоны — открываются кодовым словом, которое я называю в ролике. Это простая воронка «видео → слово → файлы → контакт». Реализовать её так, чтобы не потерять поисковый трафик и не попасть под санкции, оказалось интереснее, чем кажется.
Два очевидных способа — оба плохие
Спрятать всю страницу за паролем. Тогда её нет в индексе. Ноль органики, воронка питается только теми, кто уже посмотрел видео.
Отдавать роботу полный текст, а человеку — гейт. Это клоакинг, и наказание за него — не отдельная страница, а весь домен.
Что работает
Один и тот же HTML для всех. Разница не в том, кому отдаём, а в том, чего в документе нет:
- Закрытая часть физически отсутствует в DOM до разблокировки. Не спрятана стилями — её там нет.
- Публичная часть — самостоятельная статья, которая имеет ценность сама по себе. Не тизер.
- Разметка
TechArticleчестно объявляетisAccessibleForFree: falseиhasPartс CSS-селектором закрытого блока. Это официально поддерживаемый способ сказать поисковику правду. - Файлы лежат вне
public/. Иначе они индексируются, качаются в обход гейта и дублируют контент своей же страницы.
Доступ — подписанная кука, а не сессия
Первая версия держала разблокировки в express-session на MemoryStore. Каждый деплой перезапускает сервис — и все, кто ввёл слово, теряли доступ.
Заменил на stateless-куку: payload + HMAC-SHA256 на серверном секрете. Переживает любой рестарт, ничего не хранит на диске и не требует базы.
И ещё одно
Гейт не должен превращать материал в читальный зал. Порядок воронки, который в итоге сложился: хук в лиде → социальное доказательство → гейт → файлы → подписка на канал → услуги. Без последних двух шагов материал приносит трафик и ноль заявок.