Next.js нужен тег в одном месте, и дальше он вас не трогает: переходы на стороне клиента считают себя сами, поэтому подписываться на события маршрутизатора не надо и вызывать при смене маршрута нечего.
Сначала возьмите сниппет в своей панели. Выглядит он так, с вашим собственным идентификатором сайта в пути:
<script src="https://t.skomi.com/s/your-site-id.js" defer></script>
App Router
В app/layout.tsx, внутри <body>:
import Script from "next/script";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="ru">
<body>
{children}
<Script
src="https://t.skomi.com/s/your-site-id.js"
strategy="afterInteractive"
/>
</body>
</html>
);
}
afterInteractive стоит по умолчанию и здесь правилен: страница должна сначала догрузиться, и ничто на ней аналитику не ждёт.
Pages Router
Тот же тег в pages/_app.tsx:
import Script from "next/script";
import type { AppProps } from "next/app";
export default function App({ Component, pageProps }: AppProps) {
return (
<>
<Component {...pageProps} />
<Script
src="https://t.skomi.com/s/your-site-id.js"
strategy="afterInteractive"
/>
</>
);
}
Именно _app, а не _document, чтобы он переживал переход на стороне клиента так же, как остальное ваше приложение.
Переходы на стороне клиента уже посчитаны
Это та часть, которую все ожидают написать, и писать здесь нечего.
Скрипт Skomi оборачивает history.pushState и history.replaceState и слушает popstate, так что каждая смена маршрута в Next — это просмотр страницы, независимо от того, нажал ли посетитель <Link>, вернулся назад или вы сами вызвали router.push.
Две детали стоит знать, потому что именно они выглядят ошибками:
- Переход, не меняющий адрес, не считается. Замена адреса на тот же самый (что иногда делает фильтр или обновление позиции прокрутки) игнорируется, а не считается вторым просмотром.
- Покидаемая страница закрывается первой. Её время на странице и глубина прокрутки сбрасываются до открытия нового просмотра, поэтому одностраничное приложение отчитывается о внимании по маршрутам, а не одним числом на всю сессию.
Не используйте strategy="worker"
next/script предлагает стратегию worker, переносящую сторонний скрипт в веб-воркер через Partytown. Для скриптов, которые только шлют события, это хорошая идея, а этот она ломает начисто: у воркера нет document, то есть страницы, которую можно прочитать, там нет.
Всему, что делает Skomi, нужна настоящая страница: тепловые карты и записи сессий — это её изображение, виджет отзывов должен на ней появиться, да и обычной аналитике нужен адрес, на который посетитель действительно смотрит. Берите afterInteractive.
beforeInteractive не неправилен, а просто не нужен: он существует для скриптов, которые обязаны выполниться до гидратации, а счёт визита к таким не относится.
Если у вас есть политика безопасности содержимого
Next.js упрощает добавление строгой CSP, и строгая CSP будет это блокировать, пока вы ей не скажете обратного. Скрипт и данные, которые он шлёт, используют один хост:
script-src https://t.skomi.com
connect-src https://t.skomi.com
Если ваша политика использует nonce, примените его к этому тегу так же, как к своим.
В разработке ничего не приходит
localhost — не тот домен, который вы зарегистрировали, поэтому обращения с него отклоняет проверка источника. Это намеренно: вашей собственной работы в ваших числах быть не должно, и это значит, что npm run dev не то место, где подтверждают установку. Выложите на настоящий домен или его поддомен и смотрите там.
Проверьте, что работает
Загрузите страницу на настоящем домене, перейдите по ссылке на другой маршрут и посмотрите в свою панель: вы должны увидеть два просмотра страниц, а не один. Если ничего не пришло, смотрите что проверить, когда сниппет не работает.