Next.js integration (Pages Router)
Two files. Grab your project ID from the dashboard
(Get your script) and replace
{YOUR_PROJECT_ID} below.
Requires v1.3.5 or later
On the App Router use the App Router guide instead — an app uses one or the other, never both.
npm install @testa-soft/next1. Middleware
middleware.ts at the project root (or under src/). Buckets the visitor,
writes the cookie, and issues split-URL redirects before any HTML is sent.
// middleware.ts
import type { NextFetchEvent, NextRequest } from "next/server";
import { createTestaProxy } from "@testa-soft/next";
const testa = createTestaProxy({
projectId: "{YOUR_PROJECT_ID}",
secureCookies: process.env.NODE_ENV === "production",
});
export function middleware(request: NextRequest, event: NextFetchEvent) {
return testa(request, event);
}Already have middleware? Put your logic in the handler option, or await the
proxy and use the response it returns.
2. Provider
// pages/_app.tsx
import type { AppProps } from "next/app";
import { TestaProvider } from "@testa-soft/next/pages";
export default function App({ Component, pageProps }: AppProps) {
return (
<TestaProvider projectId="{YOUR_PROJECT_ID}">
<Component {...pageProps} />
</TestaProvider>
);
}The client half of every experiment type: applies HTML changes, tracks goals,
reports which variation the visitor saw, re-points next/link navigations, and
hides the page until the variant is on it — anti-flicker is on by default, no
extra component. Mount it even if you only run split-URL tests; that's how their
conversions get counted.
Done. That's a working integration.
Optional: faster first paint
The page stays hidden until the config arrives. Add <TestaGuard/> to start
that download in <head> while the HTML is still parsing, instead of after
hydration:
// pages/_document.tsx
import { Head, Html, Main, NextScript } from "next/document";
import { TestaGuard } from "@testa-soft/next/pages";
export default function Document() {
return (
<Html lang="en">
<Head>
<TestaGuard projectId="{YOUR_PROJECT_ID}" />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}The provider adopts that request instead of making its own, so it's one config fetch either way.
Optional: faster publishes
By default the middleware caches the config for 60s and refreshes in the background. To pick up dashboard changes on the next page load instead:
createTestaProxy({ projectId: "{YOUR_PROJECT_ID}", cache: "per-pageload" });Goals
Create goals in the dashboard (Goals tracking). Page-view and click goals need no code. Custom-event goals fire from yours:
import { pushEvent } from "@testa-soft/next";
pushEvent("signup_completed", { plan: "pro" });Also window.testa.pushEvent(...) and window.Analytica.pushEvent(...). Each
goal counts once per visitor.
Analytics events
Identical to the App Router — testa.onVariationApplied(...), window.testa
for GTM Custom HTML, and the automatic Analytica dataLayer push. See
Analytics events.