Next.js quiere la etiqueta en un solo sitio y luego te deja en paz: las navegaciones del lado del cliente se cuentan solas, así que no hay ningún evento de enrutador al que suscribirse ni nada que llamar al cambiar de ruta.

Consigue primero el fragmento desde tu panel. Tiene esta pinta, con tu propio identificador de sitio en la ruta:

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

App Router

En app/layout.tsx, dentro del <body>:

import Script from "next/script";

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

afterInteractive es el valor por defecto y el correcto aquí: la página debería terminar de cargar primero, y nada en ella espera a la analítica.

Pages Router

La misma etiqueta en 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 y no _document, para que sobreviva a una navegación del lado del cliente igual que el resto de tu aplicación.

La navegación del lado del cliente ya se cuenta

Esta es la parte que la gente espera tener que escribir, y no hay nada que escribir.

El script de Skomi envuelve history.pushState y history.replaceState y escucha popstate, así que cada cambio de ruta que hace Next es una página vista, tanto si el visitante hizo clic en un <Link>, como si volvió atrás, como si llamaste tú a router.push.

Dos detalles que conviene conocer, porque son los que parecen bugs:

  • Una navegación que no cambia la dirección no se cuenta. Sustituir la URL por la misma URL (cosa que hacen a veces un filtro o una actualización de la posición de desplazamiento) se ignora en vez de contarse como una segunda vista.
  • La página que se deja se termina primero. Su tiempo en la página y su profundidad de desplazamiento se vacían antes de que se abra la vista nueva, así que una aplicación de una sola página informa de la atención por ruta y no con un solo número para toda la sesión.

No uses strategy="worker"

next/script ofrece una estrategia worker que mueve un script de terceros a un web worker mediante Partytown. Es buena idea para scripts que solo mandan eventos, y rompe este por completo: un worker no tiene document, así que no hay ninguna página que leer.

Todo lo que hace Skomi necesita la página de verdad: los mapas de calor y las grabaciones de sesión son una imagen de ella, el widget de opiniones tiene que aparecer encima, e incluso la analítica simple necesita la dirección que el visitante está mirando de verdad. Usa afterInteractive.

beforeInteractive no está mal, solo es innecesario: existe para scripts que tienen que ejecutarse antes de la hidratación, y contar una visita no es uno de esos.

Si tienes una política de seguridad de contenido

Next.js hace fácil añadir una política estricta, y una política estricta va a bloquear esto hasta que le digas que no. El script y los datos que manda usan los dos un solo host:

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

Si tu política usa un nonce, aplícaselo a esta etiqueta como se lo aplicas a las tuyas.

No llega nada en desarrollo

localhost no es el dominio que registraste, así que los registros que vengan de ahí los rechaza la comprobación de origen. Es deliberado (tu propio trabajo no debería estar en tus números) y sí significa que npm run dev no es donde confirmas la instalación. Despliega en el dominio real, o en un subdominio suyo, y mira ahí.

Comprobar que funciona

Carga una página en el dominio real, entra en otra ruta, y mira tu panel: deberías ver dos páginas vistas en vez de una. Si no llega nada, véase qué comprobar cuando el fragmento no funciona.