See which campaign brings your Next.js customers
One provider in the root layout counts every route change, and your route handlers report the orders that paid.
Package @mirafive/sdk-next
Set up in 5 steps
Install the packages
@mirafive/sdk-nextbrings the provider and a server entry. It works with Next.js 15.1 and 16, React 18.3 and 19, and Node.js 20 or later.Code for step 1 of the Next.js setup: Install the packages. npm install @mirafive/sdk-next @mirafive/sdk-react @mirafive/sdk-browser @mirafive/sdk-server
Set the two keys
The website key of your website source goes to the browser. The secret key of a server source stays on the server, so never give it a
NEXT_PUBLIC_prefix. Both are under Data → Sources.Code for step 2 of the Next.js setup: Set the two keys. NEXT_PUBLIC_MIRAFIVE_KEY=mf_… MIRAFIVE_SECRET_KEY=mf_…
Wrap the root layout
The provider creates the browser client once and counts the first page and every navigation, in the App Router and the Pages Router. You add no
usePathnameeffect and no Suspense boundary.Code for step 3 of the Next.js setup: Wrap the root layout. import { MiraProvider } from '@mirafive/sdk-next' import type { ReactNode } from 'react' export default function RootLayout({ children }: { children: ReactNode }) { return ( <html lang="en"> <body> <MiraProvider>{children}</MiraProvider> </body> </html> ) }
Record what matters
Call
trackfrom any client component inside the provider. Event names that start with$are reserved.Code for step 4 of the Next.js setup: Record what matters. 'use client' import { useMira } from '@mirafive/sdk-next' export function AddToCart() { const mira = useMira() return <button onClick={() => mira.track('added_to_cart', { product: 'merino-crew' })}>Add to cart</button> }
Send the paid order from the server
mira()from@mirafive/sdk-next/serveris the server SDK'sMira, one client per process, made fromMIRAFIVE_SECRET_KEY. Inside a request it sends the events after the response, so nothing waits for analytics.Code for step 5 of the Next.js setup: Send the paid order from the server. import { mira } from '@mirafive/sdk-next/server' // In the route handler that confirms the payment mira().track('order_paid', { userId: order.customerId, properties: { revenue: 328, currency: 'EUR' }, })
MIRA FIVE is analytics built around the person. In a Next.js app one package covers both sides: a provider for the browser, and a server entry for route handlers, server actions and Server Components.
What will I see after installing?
The first three questions the dashboard answers, from the default setup:
- Which channels and campaigns send visitors? Acquisition › Channels splits visits into nine channels, and each channel opens to its campaigns from your UTM tags. In the sample shop, Direct sent 525 visits, Organic search 438 and Paid search 240 over 30 days.
- Which pages do they land on? Journeys › Pages lists every route with pageviews, entries, bounce rate, exits and time on page. Sort by entries to see your landing pages.
- Which goals do they reach? Goals counts every conversion of the events you send, such as a sign-up or a paid order.
The default setup sets no cookies, stores nothing on the device and sends no identifier.
How does a paid order reach its channel?
Through the person who paid. With their consent, the browser keeps an id for the visitor, and
identify ties it to your own user id when they sign in. The route handler sends the order with the
same user id, so MIRA FIVE puts the purchase on that person, next to the campaign that first brought
them.
Create a purchase goal for order_paid, and Acquisition shows buyers and revenue per channel and
campaign. With Google Ads connected, it adds cost per buyer for
each campaign.
How do I collect with consent?
Switch the website source to Full under Data → Sources. Plugins are functions, so set full mode in a client providers file and render it in the root layout instead of the plain provider:
'use client'
import { identity } from '@mirafive/sdk-browser/identity'
import { MiraProvider } from '@mirafive/sdk-next'
import type { ReactNode } from 'react'
export function Providers({ children }: { children: ReactNode }) {
return (
<MiraProvider mode="full" plugins={[identity()]}>
{children}
</MiraProvider>
)
}Then, in client components, pass your banner’s answer and the signed-in user:
const mira = useMira()
// From your consent banner's callback
mira.consent({ statistics: true, experiments: true, targeting: false })
// After sign-in, with your own user id
mira.identify(user.id, { plan: user.plan })
// After sign-out
mira.reset()Before an answer, full mode stores and sends nothing. Ids live in localStorage, never in cookies. The consent guide explains the three scopes.
How do I make a webhook count once?
Payment providers sometimes deliver a webhook twice. send delivers at once and takes an idempotency
key, so a repeat is stored once:
await mira().send(
[{ name: 'order_paid', userId: order.customerId, properties: { revenue: 328, currency: 'EUR' } }],
{ idempotencyKey: `order-${order.id}` },
)The server-side guide covers retries and idempotency.
Can I render feature flags without a flicker?
Yes. flagsFor() from @mirafive/sdk-next/server reads the visitor’s
feature flags in the root layout, and the provider hands the answers to the
browser, so the first paint shows the right variant. Client components read them with useFlag and
useFlagConfig. A code A/B test is a flag read the same way. The
Next.js SDK docs show the three pieces and the caching rules.
Other setups
The same numbers, whichever way your site is built.