Docs
Next.js
Next.js App Router should load the snippet once in app/layout.tsx. afterInteractive is enough. Do not invent pageviews in getServerSideProps — the browser sends them.
Root layout
Use next/script. Point src at your Cashline origin. The data-site attribute is your site ID.
import Script from "next/script";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en-ZA">
<body>
<Script id="cashline-queue" strategy="beforeInteractive">
{`window.cashline=window.cashline||function(){(window.cashline.q=window.cashline.q||[]).push(arguments)}`}
</Script>
<Script
src="https://YOUR_ORIGIN/cashline.js"
data-site="cl_your_site_id"
strategy="afterInteractive"
onLoad={() => {
if (typeof window.cashline === "function") window.cashline("pageview");
}}
/>
{children}
</body>
</html>
);
}Purchase after the processor confirms
Amount is rand, not cents. Call this from a client handler after Paystack (or your own webhook) says the charge succeeded. Do not fire it from a Server Component.
"use client";
function onPaid(reference: string) {
window.cashline?.("purchase", {
amount: 199,
currency: "ZAR",
reference,
});
}Client-side goals
After a real signup on the client, fire a goal. Do not fire it from a Server Component.
"use client";
function onSignedUp() {
window.cashline?.("goal", { name: "signup" });
}