Next.js Pages Router (`pages/` Directory)
Complete guide for integrating ParityEdge into Next.js 12, 13, and 14 applications using the classic **Pages Router**, including 0-CLS server-side rendering via getServerSideProps, custom _app.tsx scripts, and client-side hooks.
1. Server-Side Parity Resolution in `getServerSideProps`
Resolve visitor geolocation and PPP discount slabs directly on the Node.js server before HTML delivery. By forwarding the visitor's IP address (x-forwarded-for), the server pre-renders the exact localized price with **0 Cumulative Layout Shift (CLS)**:
// pages/pricing.tsx
import { GetServerSideProps, InferGetServerSidePropsType } from 'next';
import Head from 'next/head';
interface ParityData {
eligible: boolean;
countryCode: string;
countryName: string;
discountPercentage: number;
couponCode: string;
currency: string;
isVpn: boolean;
}
export const getServerSideProps: GetServerSideProps<{
parity: ParityData | null;
}> = async (context) => {
const rawIp = context.req.headers['x-forwarded-for'] || context.req.socket.remoteAddress;
const clientIp = Array.isArray(rawIp) ? rawIp[0] : rawIp || '';
try {
const res = await fetch(
'https://parityedge-edge-api.g-saichakri.workers.dev/v1/resolve?projectId=prj_live_YOUR_PROJECT_ID',
{
headers: {
'x-forwarded-for': clientIp,
},
}
);
if (!res.ok) throw new Error(`Edge API responded with ${res.status}`);
const parity: ParityData = await res.json();
return {
props: {
parity,
},
};
} catch (error) {
console.warn('[ParityEdge] Fallback to default USD pricing:', error);
return {
props: {
parity: null,
},
};
}
};
export default function PricingPage({
parity,
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
const baseUsdPrice = 49;
const finalPrice = parity?.eligible
? baseUsdPrice * (1 - parity.discountPercentage / 100)
: baseUsdPrice;
return (
<div className="min-h-screen bg-slate-950 text-white p-8">
<Head>
<title>Pricing | My SaaS</title>
</Head>
<div className="max-w-md mx-auto p-8 rounded-2xl bg-slate-900 border border-slate-800">
<h2 className="text-xl font-bold">Pro Subscription</h2>
{/* Pre-rendered Localized Price (0 CLS) */}
<div className="text-4xl font-extrabold mt-3 font-mono">
${finalPrice.toFixed(2)} USD <span className="text-sm font-normal text-slate-400">/ mo</span>
</div>
{parity?.eligible && (
<div className="mt-4 p-3 rounded-xl bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 text-xs">
<p className="font-bold">
{parity.discountPercentage}% Parity Discount Active for {parity.countryName}!
</p>
<p className="mt-1 text-slate-300">
Use code <span className="font-mono font-bold text-white">{parity.couponCode}</span> at checkout.
</p>
</div>
)}
<button className="w-full mt-6 py-3 rounded-xl bg-emerald-600 font-bold hover:bg-emerald-500 transition-colors">
Get Started
</button>
</div>
</div>
);
}2. Mount Global Edge Script with `next/script`
If you prefer a drop-in floating banner without modifying individual page props, add the CDN script to pages/_app.tsx using Next.js Script optimization:
// pages/_app.tsx
import type { AppProps } from 'next/app';
import Script from 'next/script';
import '@/styles/globals.css';
export default function MyApp({ Component, pageProps }: AppProps) {
return (
<>
{/* High-Performance Edge Script (Non-blocking) */}
<Script
src="https://parityedge-edge-api.g-saichakri.workers.dev/v1/parity.global.js"
data-project-id="prj_live_YOUR_PROJECT_ID"
data-theme="dark"
data-position="bottom-pill"
strategy="afterInteractive"
/>
<Component {...pageProps} />
</>
);
}3. Client-Side Resolution using `useSWR`
For statically exported pages (next export or static JAMstack setups), fetch dynamically from the edge in the browser:
import useSWR from 'swr';
const fetcher = (url: string) => fetch(url).then((res) => res.json());
export function useClientParity(projectId: string) {
const { data, error, isLoading } = useSWR(
`https://parityedge-edge-api.g-saichakri.workers.dev/v1/resolve?projectId=${projectId}`,
fetcher,
{ revalidateOnFocus: false, dedupingInterval: 300000 }
);
return {
parity: data,
isLoading,
isError: error,
};
}