MuroDocs
Installing Muro

Install Muro on Next.js

Add Muro to a Next.js app using either the App Router or the Pages Router. Single-page navigation is tracked automatically.

Muro works with Next.js out of the box. You add the script tag once in your root layout, and every page navigation is tracked automatically. No extra hooks, no router events to subscribe to.

Pick the section that matches your setup.

App Router (Next.js 13+)

Open app/layout.tsx (or app/layout.jsx) and add the snippet inside the <head> element of your root layout:

// app/layout.tsx
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <head>
        <script
          async
          src="https://api.muroanalytics.com/muro.js"
          data-project-id="YOUR_PROJECT_ID"
        />
      </head>
      <body>{children}</body>
    </html>
  );
}

Replace YOUR_PROJECT_ID with your project's ID. You can find it any time in Settings → Project → Tracking script.

You can also use next/script

If you prefer the next/script component for managing third-party scripts, it works too:

import Script from 'next/script';

<Script
  async
  src="https://api.muroanalytics.com/muro.js"
  data-project-id="YOUR_PROJECT_ID"
  strategy="afterInteractive"
/>

Either approach is fine. Plain <script> is simpler. next/script gives you more control over when it loads.

Pages Router (Next.js 12 and earlier)

Open pages/_document.tsx (or create it if you don't have one) and add the snippet inside <Head>:

// pages/_document.tsx
import { Html, Head, Main, NextScript } from 'next/document';

export default function Document() {
  return (
    <Html lang="en">
      <Head>
        <script
          async
          src="https://api.muroanalytics.com/muro.js"
          data-project-id="YOUR_PROJECT_ID"
        />
      </Head>
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}

_document.tsx is the right home for the snippet because it controls the HTML shell on every page.

How single-page navigation is tracked

Muro tracks every page in your Next.js app, not just the first one. Next.js's client-side router calls history.pushState under the hood whenever you navigate with <Link> or router.push(). Muro listens for that and fires a new pageview.

You don't need to wire up useRouter, subscribe to router.events, or call muro.track() yourself. It just works.

Why you won't see double pageviews

Some analytics libraries fire a pageview on Next.js's initial hydration call to replaceState, which causes inflated numbers. Muro deliberately ignores replaceState and only counts real navigations. Your bounce rate stays accurate.

Content Security Policy

If your Next.js app has a Content Security Policy header, allow the Muro domain in both script-src and connect-src:

script-src 'self' https://api.muroanalytics.com;
connect-src 'self' https://api.muroanalytics.com;

Without these, the browser will block muro.js from loading or block its events from being sent.

Verify

Run your app locally (npm run dev), open it in your browser, and check that the install is working in one of three ways:

  1. From the onboarding screen. If you're still inside the Muro onboarding flow, it will detect your first event and switch to "Data received!" within seconds.
  2. From the dashboard. Open your project, set the time range to Live, and reload your site. Your visit appears within 30 seconds.
  3. From DevTools. Open the Network tab, filter for collect, and reload your site. You should see a POST to api.muroanalytics.com/collect that returns a 204.

What's next

On this page