O Next.js precisa da etiqueta num sítio e depois deixa-te em paz: as navegações do lado do cliente contam-se sozinhas, portanto não há evento de encaminhador a que te subscrever nem nada para chamar quando a rota muda.

Vai buscar primeiro o fragmento ao teu painel. Tem este aspeto, com o teu próprio identificador de sítio no caminho:

<script src="https://t.skomi.com/s/your-site-id.js" defer></script>

App Router

No app/layout.tsx, dentro do <body>:

import Script from "next/script";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <Script
          src="https://t.skomi.com/s/your-site-id.js"
          strategy="afterInteractive"
        />
      </body>
    </html>
  );
}

afterInteractive é o valor de origem e é o certo aqui: a página deve acabar de carregar primeiro, e não há nada nela que espere pela analítica.

Pages Router

A mesma etiqueta no 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"
      />
    </>
  );
}

No _app e não no _document, para sobreviver a uma navegação do lado do cliente da mesma maneira que o resto da tua aplicação.

A navegação do lado do cliente já está contada

Esta é a parte que as pessoas contam ter de escrever, e não há nada para escrever.

O script da Skomi embrulha o history.pushState e o history.replaceState e escuta o popstate, portanto todas as mudanças de rota que o Next faz são uma página vista, quer o visitante tenha clicado num <Link>, tenha recuado, ou tenhas chamado tu mesmo o router.push.

Há dois pormenores que vale a pena conhecer, porque são os que parecem defeitos:

  • Uma navegação que não muda o endereço não é contada. Substituir o endereço pelo mesmo endereço (coisa que um filtro ou uma atualização da posição de deslocamento às vezes faz) é ignorado em vez de contado como uma segunda vista.
  • A página que se está a deixar é fechada primeiro. O tempo nela e a profundidade de leitura são despejados antes de a nova vista abrir, portanto uma aplicação de página única reporta a atenção por rota em vez de um único número para a sessão inteira.

Não uses strategy="worker"

O next/script oferece uma estratégia worker que muda um script de terceiros para dentro de um web worker através do Partytown. É boa ideia para scripts que só enviam eventos, e parte este por completo: um worker não tem document, portanto não há página nenhuma para ler.

Tudo o que a Skomi faz precisa da página verdadeira: os mapas de calor e as gravações de sessão são um retrato dela, o widget de opiniões tem de aparecer nela, e até a analítica simples precisa do endereço para onde o visitante está mesmo a olhar. Usa afterInteractive.

O beforeInteractive não está errado, é só desnecessário: existe para scripts que têm de correr antes da hidratação, e contar uma visita não é um desses casos.

Se tens uma Política de Segurança de Conteúdo

O Next.js torna fácil acrescentar uma CSP estrita, e uma CSP estrita bloqueia isto enquanto não lhe disseres que não. O script e os dados que ele envia usam ambos um único anfitrião:

script-src  https://t.skomi.com
connect-src https://t.skomi.com

Se a tua política usa um nonce, aplica-o a esta etiqueta como o aplicas às tuas.

Não chega nada em desenvolvimento

O localhost não é o domínio que registaste, portanto os registos vindos dali são recusados pela verificação de origem. É de propósito (o teu próprio trabalho não devia estar nos teus números) e quer mesmo dizer que o npm run dev não é onde confirmas a instalação. Publica no domínio verdadeiro, ou num subdomínio dele, e olha lá.

Confirma que está a funcionar

Carrega uma página no domínio verdadeiro, clica para outra rota, e olha para o teu painel: devias ver duas páginas vistas em vez de uma. Se não chegar nada, vê o que verificar quando o fragmento não funciona.