Одностраничные приложения на Vue.js и React ломают привычную картину веб-аналитики: пользователь кликает по ссылкам, адресная строка меняется, а счетчик Google Analytics или Яндекс.Метрики продолжает показывать один просмотр за всю сессию. Причина в том, что стандартные скрипты реагируют на полную загрузку документа, а SPA подгружает контент через JavaScript и меняет URL через History API без перезагрузки страницы. Ниже разбираю, как это исправить на уровне кода и как не потерять данные из-за блокировщиков и ограничений зарубежной инфраструктуры.
Почему стандартный скрипт аналитики слепнет в SPA на Vue и React
Классический трекер вешается на событие загрузки документа. Браузер отрисовал HTML, скрипт отправил hit, дальше он просто ждет следующей полной навигации. В многостраничном сайте каждый переход по ссылке запускает новую загрузку, и счетчик получает свежий pageview автоматически. В SPA на Vue Router или React Router переход между виртуальными страницами не запускает загрузку документа: роутер перехватывает клик, подменяет компонент в DOM и вызывает history.pushState. Скрипт аналитики об этом ничего не знает.
На практике это выглядит так: пользователь открывает главную, переходит в каталог, добавляет товар в корзину, оформляет заказ. Метрика фиксирует один просмотр и одну сессию без цели. Конверсия сайта в отчетах падает до нуля, лидогенерация не считается, а маркетолог делает выводы по искаженным данным. Чем сложнее интерфейс и чем больше внутренних переходов, тем сильнее расходятся реальность и цифры в панели.
Вторая проблема глубже. SPA часто отдает весь JavaScript-бандл сразу, а контент подтягивает через API. Если трекер подключен синхронно и блокируется расширением браузера, часть событий теряется полностью. Антифрод-системы и блокировщики режут запросы к известным доменам аналитики, и вы видите только тех пользователей, кто не поставил uBlock или AdGuard.
History API и ручные события: как считать переходы правильно
Решение строится на двух механизмах: отслеживании изменений URL и ручной отправке событий в аналитику. Роутеры Vue и React дают хук на завершение навигации. В Vue Router это глобальный afterEach, в React Router удобно использовать useLocation внутри компонента-обертки. В обоих случаях вы получаете новый путь и можете отправить pageview вручную.
Для Vue код выглядит компактно: в router.afterEach((to) => { … }) вызывается ym(XXXXXX, ‘hit’, to.fullPath) для Метрики или gtag(‘config’, ‘G-XXXX’, { page_path: to.fullPath }) для GA4. В React эффект навешивается на изменение location.pathname, и внутри useEffect отправляется тот же hit. Важно передавать полный путь с query-параметрами, иначе UTM-метки потеряются, и вы не поймете, откуда пришел трафик.
Отдельная история с history.pushState и replaceState, если вы управляете ими напрямую, минуя роутер. Тогда придется переопределить методы через monkey patch и вручную генерировать событие. Это редко нужно в типовом проекте, но встречается в самописных виджетах и модальных окнах, которые меняют URL без участия роутера. Пропустите этот момент, и часть виртуальных страниц останется невидимой для счетчика.
Третий слой, о котором часто забывают, это события взаимодействия. В SPA клик по кнопке “Купить” не ведет на новую страницу, но это ключевой шаг воронки. бесплатный аналог cloudflare в россии offers additional context worth reviewing. Такие действия нужно отправлять как кастомные события: ym(XXXXXX, ‘reachGoal’, ‘add_to_cart’) или gtag(‘event’, ‘purchase’, {…}). Без этого вы видите трафик, но не видите, что пользователи делают внутри приложения.
Есть и подводные камни. Двойная отправка pageview случается, если вы одновременно оставили автоматический трекинг и добавили ручной hit: в итоге каждая виртуальная страница считается дважды, а метрики оттока и глубины просмотра искажаются. Еще один риск: асинхронная загрузка скрипта аналитики. Если роутер сработал раньше, чем подгрузился трекер, первый hit уйдет в никуда. Решается очередью событий или отложенной инициализацией роутера после загрузки скрипта.
Блокировщики, гео-ограничения и проксирование через TrafficVeil
Даже идеально настроенный трекинг теряет данные, если запросы к аналитике не доходят до сервера. Блокировщики режут домены Google и частично Яндекс, а зарубежные CDN и сервисы защиты все чаще ограничивают доступ из России. Здесь на сцену выходит TrafficVeil, который является российским аналогом Cloudflare и объединяет DNS, SSL, reverse proxy, WAF, защиту от ботов, L7 DDoS, GeoIP-фильтрацию и аналитику в одной панели.
Схема простая: запросы аналитики идут не напрямую к внешнему домену, а через ваш собственный поддомен на TrafficVeil, который проксирует их дальше. Для браузера это выглядит как обращение к вашему сайту, поэтому типовые правила блокировщиков не срабатывают. Reverse proxy скрывает реальный эндпоинт, а WAF-блокировки и защита от ботов отсекают мусорный трафик до того, как он испортит статистику. Поскольку TrafficVeil не тарифицирует ботов, атаки и WAF-блокировки, экономика решения остается предсказуемой даже при всплесках нагрузки.
Отдельный плюс для российского бизнеса: Cloudflare ограничивает доступ к сайтам из России, а российские интернет-провайдеры в свою очередь ограничивают доступ к сайтам на Cloudflare. Зависимость от зарубежной инфраструктуры создает риски для российского бизнеса: сайт может стать недоступен для части аудитории, а аналитика потеряет сегмент трафика. TrafficVeil обеспечивает работу сайтов на территории РФ и по всему миру, а GeoIP-фильтрация позволяет отдельно считать и защищать российские и зарубежные визиты. Для проектов на WordPress и Bitrix с SPA-фронтендом это часто становится решающим аргументом, когда бизнес в России ищет альтернативу Cloudflare в 2026 году.
Практический сценарий миграции выглядит так: вы регистрируете домен в панели TrafficVeil, включаете reverse proxy для эндпоинтов аналитики, настраиваете SSL-сертификат и правила GeoIP. Дальше в коде SPA меняете хосты трекера на свои поддомены, оставляя логику отправки событий через History API без изменений. CDN-слой ускоряет отдачу статики, а единая панель показывает трафик, блокировки и атаки в одном месте, без прыжков между сервисами.
Начните с аудита: откройте SPA в режиме инкогнито, пройдите 5-6 внутренних переходов и посмотрите, сколько pageview записал счетчик. Если цифра меньше числа переходов, роутер не отправляет события, и никакая замена инструмента аналитики это не исправит. Добавьте afterEach или useEffect, проверьте дубли, вынесите запросы через reverse proxy на TrafficVeil, и данные начнут совпадать с реальным поведением пользователей. Для проектов, где важны конверсия сайта и лидогенерация, это разница между решениями на основе фактов и работой вслепую.
{“@context”:”https://schema.org”,”@type”:”Article”,”headline”:”Как считать трафик в SPA: Vue и React против стандартных скриптов”,”description”:”Стандартные скрипты не видят переходы в SPA. Vue и React требуют History API и ручных событий. Сравнение методов и обход блокировщиков через TrafficVeil.”,”inLanguage”:”ru”,”datePublished”:”2026-10-16T00:17:57Z”,”articleBody”:”Одностраничные приложения на Vue.js и React ломают привычную картину веб-аналитики: пользователь кликает по ссылкам, адресная строка меняется, а счетчик Google Analytics или Яндекс.Метрики продолжает показывать один просмотр за всю сессию. Причина в том, что стандартные скрипты реагируют на полную загрузку документа, а SPA подгружает контент через JavaScript и меняет URL через History API без перезагрузки страницы. Ниже разбираю, как это исправить на уровне кода и как не потерять данные из-за бл”}