Install Muro on Next.js
Add the Muro script to a Next.js app with the App Router or the Pages Router. Client-side navigation is tracked automatically.
In Next.js, the Muro script goes in your root layout (App Router) or your custom document (Pages Router), so it loads on every route. Client-side navigation with <Link> and router.push() is tracked without any extra code.
Steps
Copy your snippet
In Muro, go to Settings → Project → Tracking script and click Copy script. You need the project ID from it, the value of data-project-id.
Add the script to your root layout
Use a plain <script async> tag inside <head>.
Open app/layout.tsx (or app/layout.js) and add the script to the <head> 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>
);
}If your layout has no <head> element yet, add one as shown.
Open pages/_document.tsx (or pages/_document.js). If the file doesn't exist, create it. Add the script 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>
);
}Use Head from next/document here, not next/head.
Why not next/script?
Don't use next/script with strategy="afterInteractive" for Muro. That strategy waits until React has hydrated, which on a JavaScript-heavy page can be several seconds after load. Visitors who leave before then are never counted, so your visitor and bounce numbers come out wrong. A plain <script async> in <head> starts downloading straight away without blocking rendering, the same way Google Analytics, Plausible and Fathom load.
Deploy
Commit and deploy as usual, for example by pushing to the branch Vercel deploys from.
Verify it works
- Open your deployed site.
- Open DevTools, go to the Network tab, filter by
collectand reload. You should see aPOSTtocdn.muroanalytics.com/collectwith status202. - Click a
<Link>to another page. A secondcollectrequest appears for the new route. - Or, in Muro, set the time picker to Live. Your visit appears within about 30 seconds.
Good to know
- No router code needed. Muro records a pageview each time Next.js calls
history.pushState, and on back and forward. Don't add auseEffecton route changes that callswindow.muro.track, or every page is counted twice. - No double count on load. Next.js calls
history.replaceStateduring hydration. Muro ignoresreplaceStateon purpose, so the first page is counted once. See Single-page apps. - Content Security Policy. If you set a CSP in
next.config.js, middleware orvercel.json, allowhttps://api.muroanalytics.cominscript-srcandhttps://cdn.muroanalytics.cominconnect-src. See Fix Content Security Policy errors. - Keep previews and localhost out. Muro counts every page that loads the script, including
next devand preview deployments. See Keep staging and localhost out of your data. - Calling
window.muroin TypeScript. Usewindow.muro?.track(...)from Client Components only, and add a type declaration once. See Track custom events.