Zarstat

Docs

Next.js

Next.js App Router should load the snippet once in app/layout.tsx. Prefer a first-party /cashline.js on the measured origin (copy public/cashline.js, or point at your Zarstat deploy). afterInteractive is enough. Do not invent pageviews in getServerSideProps — the browser sends them. localStorage visitor IDs do not cross subdomains.

Markdown · same page for crawlers. index, follow.

Root layout

Use next/script in the root layout. Point src at first-party /cashline.js on this origin, or at your Zarstat host. data-site is the site you already use. zarstat() is an alias for cashline(). The snippet also fires a pageview on SPA href changes.

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="YOUR_SITE"
          strategy="afterInteractive"
          onLoad={() => {
            const track = window.zarstat || window.cashline;
            if (typeof track === "function") track("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" });
}