В этом руководстве разберём, как правильно подключить Яндекс.Метрику к приложению на Next.js 16 с использованием App Router и TypeScript. Настроим инициализацию счётчика, корректное отслеживание переходов (включая UTM-метки) и избежим ошибок сборки.
Зачем нужна Яндекс.Метрика?
Яндекс.Метрика — это система веб-аналитики, которая помогает:
- отслеживать посещаемость и источники трафика;
- анализировать поведение пользователей (клики, переходы, глубину просмотров);
- измерять эффективность рекламных кампаний;
- собирать данные для улучшения конверсии.
Шаг 1. Устанавливаем библиотеку
bun add react-yandex-metrikaШаг 2. Создаём компонент для Метрики
Создадим файл components/yandex-metrika.tsx. При реализации важно учесть два момента.
Потеря GET-параметров (UTM-меток и т.д.):
Хук usePathname возвращает только путь (например, /services), но отбрасывает параметры строки запроса (например, ?utm_source=yandex). Из-за этого теряется аналитика по источникам трафика и рекламным кампаниям. Решение — добавить useSearchParams() и передавать в Метрику полный URL.
Ошибка сборки при использовании useSearchParams:
Если добавить useSearchParams напрямую в компонент, импортируемый глобально в layout.tsx, Next.js выдаст ошибку при build — useSearchParams() should be wrapped in a suspense boundary. Параметры строки запроса неизвестны на этапе статической генерации страниц, поэтому официальная рекомендация Vercel/Next.js — вынести логику трекинга в отдельный микрокомпонент и обернуть его в <Suspense>.
tsx// components/yandex-metrika.tsx "use client"; import { usePathname, useSearchParams } from "next/navigation"; import { useEffect, Suspense } from "react"; import ym, { YMInitializer } from "react-yandex-metrika"; const YM_COUNTER_ID = 12345678; // замените на ваш ID счётчика function RouterTracker() { const pathname = usePathname(); const searchParams = useSearchParams(); useEffect(() => { if (pathname) { const url = `${pathname}${searchParams.toString() ? `?${searchParams.toString()}` : ""}`; ym("hit", url); } }, [pathname, searchParams]); return null; } export const YandexMetrika = () => { return ( <> <YMInitializer accounts={[YM_COUNTER_ID]} options={{ defer: true, webvisor: true, clickmap: true, trackLinks: true, accurateTrackBounce: true, }} version="2" /> <Suspense fallback={null}> <RouterTracker /> </Suspense> </> ); };
Что делает компонент?
- YMInitializer загружает скрипт Метрики и инициализирует счётчик.
- RouterTracker — отдельный микрокомпонент, отслеживающий изменения маршрута и GET-параметров через
usePathnameиuseSearchParams. - При каждом изменении маршрута отправляется событие
hitс полным URL, включая параметры строки запроса. - Обёртка
<Suspense fallback={null}>вокруг<RouterTracker />сохраняет статическую сборку (SSG) без ошибок.
Шаг 3. Подключаем в RootLayout
Чтобы Метрика работала на всех страницах, добавляем компонент в app/layout.tsx:
tsx// app/layout.tsx import type { ReactNode } from "react"; import {YandexMetrika} from "@/components/YandexMetrika"; export default function RootLayout({ children }: { children: ReactNode }) { return ( <html lang="ru"> <body> {children} <YandexMetrika /> </body> </html> ); }
Скрипт Метрики должен выполняться в браузере, поэтому компонент размещаем внутри <body>.
Шаг 4. Проверяем работу
Запускаем проект:
bun run devЗатем проверяем сборку — ошибок, связанных с useSearchParams, быть не должно:
bun run buildПосле запуска открываем сайт в браузере и переходим по разным страницам. Чтобы проверить корректную передачу UTM-меток, откройте любую страницу с параметрами, например /page?utm_source=yandex, и убедитесь в инструментах разработчика (F12 → Network), что в запросах к mc.yandex.ru присутствует полный URL с параметрами. Визиты также должны появляться в разделе «Реальное время» в интерфейсе Яндекс.Метрики.
Дополнительные настройки (опционально)
Метрика позволяет отслеживать не только посещения, но и цели и пользовательские параметры:
tsx// Отправка события-цели ym("reachGoal", "goal_name"); // Передача пользовательских параметров ym("userParams", { userId: 123 });
Итог
Теперь счётчик Яндекс.Метрики подключён к Next.js 16 (App Router) с TypeScript и работает корректно:
✅ инициализация при загрузке сайта;
✅ отслеживание переходов между страницами;
✅ передача полного URL, включая UTM-метки и GET-параметры;
✅ корректная статическая сборка (SSG) без ошибок useSearchParams.