Добавление аналитики с приоритетом конфиденциальности на сайт Astro
View Transitions в Astro молча ломают стандартные скрипты аналитики. Вот правильный шаблон для отслеживания каждого изменения маршрута без cookie или баннера согласия.
View Transitions в Astro подменяют содержимое страницы на месте без полной перезагрузки браузера — это означает, что любой скрипт аналитики, полагающийся на DOMContentLoaded или load, сработает только один раз, при начальном посещении. Каждая последующая клиентская навигация остаётся невидимой. Это не ошибка конфигурации с вашей стороны; это фундаментальное следствие того, как работает ClientRouter.
Та же проблема молчаливого отслеживания существует в SvelteKit 2 и Remix, но решение в каждом фреймворке своё. В Astro ответом является событие жизненного цикла astro:page-load.
Почему обычный тег script не работает
Когда <ClientRouter /> активен (включается через astro:transitions в Astro 4, по умолчанию в Astro 5), навигация не выгружает страницу. Astro загружает следующую страницу в фоновом режиме, подменяет DOM и обновляет URL — всё это без уничтожения текущего контекста JavaScript.
Скрипт трекера, загруженный через обычный тег <script>, обрабатывается конвейером сборки Astro как связанный модульный скрипт. Связанные модульные скрипты выполняются ровно один раз за сессию страницы. Трекер инициализируется, фиксирует просмотр страницы для целевой страницы, а затем никогда больше не запускается, когда пользователь перемещается по сайту.
Чтобы срабатывать при каждой навигации, логика инициализации должна быть подключена к жизненному циклу навигации Astro. Правильный хук — astro:page-load, который срабатывает после того, как новая страница становится видна и все блокирующие скрипты загружены — как при начальной загрузке, так и при каждом последующем переходе.
Правильная интеграция
Добавьте скрипт трекера один раз в ваш корневой макет (src/layouts/Layout.astro или эквивалент), затем прикрепите слушатель для astro:page-load:
---
// Layout.astro
---
<html lang="en">
<head>
<!-- your head content -->
</head>
<body>
<slot />
<script
is:inline
src="https://api.monoid.website/tracker.min.js"
data-site-id="YOUR_SITE_ID"
async
></script>
</body>
</html>
Директива is:inline сообщает сборщику Astro оставить этот скрипт ровно таким, какой он есть. Без неё Astro обработал бы скрипт как модуль, дедуплицировал бы его и подавил повторное выполнение. С is:inline тег скрипта выводится дословно в HTML-выводе каждой страницы.
Для сайтов, не использующих View Transitions, этого достаточно. Трекер срабатывает один раз при загрузке, и вы закончили.
Обработка навигации View Transitions
Если ваш сайт использует <ClientRouter />, дополнительная настройка не требуется — но стоит точно понимать почему, потому что обычное объяснение неверно.
Трекер не слушает astro:page-load или любое другое событие жизненного цикла Astro. При загрузке он патчит history.pushState. Роутер Astro обновляет URL через этот же вызов History API, поэтому пропатченная функция выполняется при каждом переходе и отправляет просмотр страницы. Хук находится под слоем событий Astro, а не слушает его.
Чтобы проверить, откройте вкладку Network в DevTools и отфильтруйте по collect. Перейдите между двумя страницами. Вы должны увидеть один POST-запрос на каждую навигацию, включая первую загрузку.
Важная оговорка: хук покрывает pushState, но не popstate. Нажатие кнопки «Назад» или «Вперёд» меняет маршрут без вызова pushState, поэтому сейчас это не создаёт новый просмотр страницы.
Трекер не предоставляет ручного метода для отправки просмотра страницы. Глобальный объект принимает только пользовательские события:
<script>
// Только пользовательские события — вызова trackPageview() не существует.
// Имя должно соответствовать [a-z0-9_][a-z0-9_-]{0,63}.
window.monoid('event', 'signup_started');
</script>
Разделение окружений
Проекты Astro обычно имеют локальную разработку, предпросмотр и продакшен. Используйте переменную окружения для хранения site_id и подавления отслеживания в разработке:
---
const siteId = import.meta.env.PUBLIC_MONOID_SITE_ID
---
{siteId && (
<script
is:inline
src="https://api.monoid.website/tracker.min.js"
data-site-id={siteId}
async
></script>
)}
Установите PUBLIC_MONOID_SITE_ID в .env для продакшена и оставьте её неустановленной локально. Astro предоставляет клиенту переменные с префиксом PUBLIC_; серверные переменные (без префикса) не видны в коде, выполняемом в браузере.
Что вам не нужно
Никакого баннера согласия на cookie. Никакой интеграции CMP. Конечная точка сбора вычисляет ежедневный хэш посетителя из IP-адреса, User-Agent, серверного секрета и текущей даты:
visitor_hash = SHA-256(IP + UA + SALT_SECRET + YYYY-MM-DD)
Хэш сбрасывается каждые 24 часа. На устройстве посетителя ничего не сохраняется. Общее семейство браузеров и тип устройства определяются на стороне сервера из User-Agent запроса для агрегированной отчётности — полные строки User-Agent, версии браузеров и постоянные идентификаторы никогда не сохраняются.
Сайты Astro часто полностью статичны или отрендерены на краю с минимальным JavaScript. Добавление скрипта аналитики менее 2 КБ без cookie и без требования согласия естественно вписывается в эту философию. Не нужно поддерживать npm-пакет, обновлять SDK или документировать правовое основание GDPR для обработки аналитики.
Comments
Loading comments…