@clakta/nextjs
The official Clakta SDK for Next.js.
Clakta is a modern sales and ads tracking platform built for modern businesses. Get accurate data and know which ads perform best, which influencer sells the most, with a modern and powerful platform.
Website
Wraps @clakta/javascript with a <ClaktaProvider> component that initializes the SDK once on mount. Works with both the App Router and the Pages Router.
Requires Next.js 13+ and React 18+.
Installation
npm install @clakta/nextjs
pnpm add @clakta/nextjs
yarn add @clakta/nextjs
Usage
Render <ClaktaProvider> once near the root of your app and pass your script id. It renders nothing, and initialization runs exactly once for the lifetime of the page.
App Router
// app/layout.tsx
import { ClaktaProvider } from "@clakta/nextjs"
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<ClaktaProvider id="YOUR_SCRIPT_ID" />
{children}
</body>
</html>
)
}
The provider is already a client component, so you don't need "use client" in your layout.
Pages Router
// pages/_app.tsx
import { ClaktaProvider } from "@clakta/nextjs"
import type { AppProps } from "next/app"
export default function App({ Component, pageProps }: AppProps) {
return (
<>
<ClaktaProvider id="YOUR_SCRIPT_ID" />
<Component {...pageProps} />
</>
)
}
Props
<ClaktaProvider> takes the same options as init:
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | — | Required. Your Clakta script id. |
apiHost | string | https://api.clakta.com | Override the API host. Tracking/config use https://t.clakta.com by default; Stripe stays on api.clakta.com. |
debug | boolean | false | Verbose console logging. |
consent | boolean | by visitor location | Whether the visitor has consented to first-party identifiers. See Consent. |
Because initialization happens once per page lifetime, prop changes after the first mount are ignored — except consent, which is applied as updateConsent would. Pass the id from an env var rather than from state:
<ClaktaProvider id={process.env.NEXT_PUBLIC_CLAKTA_ID!} />
Tracking events
Page views are handled for you when they're enabled for your project — App Router and Pages Router navigations both go through the History API, which the SDK listens to. Everything else you call directly.
Tracking functions touch window, so call them from client components — in an event handler or an effect, never during a server render.
"use client"
import { trackEvent } from "@clakta/nextjs"
export function BuyButton() {
return (
<button onClick={() => trackEvent("hero-cta", "click", { variant: "A" })}>
Buy now
</button>
)
}
Identifying customers
"use client"
import { identify } from "@clakta/nextjs"
import { useEffect } from "react"
export function IdentifyUser({
user,
}: {
user: { id: string; email: string }
}) {
useEffect(() => {
identify({ externalId: user.id, email: user.email })
}, [user])
return null
}
At least one of externalId, claktaCustomerId, or email is required.
Ecommerce
Three funnel events cover the path to a sale. They touch window, so call them from client components.
"use client"
import { addToCart, initiateCheckout, purchase } from "@clakta/nextjs"
// Add to cart — no order exists yet
addToCart({
products: [{ id: "42", name: "Tee", price: 29.99, quantity: 2 }],
totalPrice: 59.98,
currency: "USD",
})
// Checkout started
initiateCheckout({
orderId: "1001",
totalPrice: 59.98,
currency: "USD",
products: [{ id: "42", name: "Tee", price: 29.99, quantity: 2 }],
customer: { email: "[email protected]" },
})
// Purchase completed
purchase({
orderId: "1001",
totalPrice: 59.98,
currency: "USD",
paymentMethod: "credit_card",
products: [{ id: "42", name: "Tee", price: 29.99, quantity: 2 }],
customer: { email: "[email protected]" },
// Optional — clkt is read from the URL when you don't pass one
tracking: { utm_source: "facebook", utm_medium: "cpc" },
})
initiateCheckout and purchase require orderId — the order's id in your own database, and the same value your server sends to the Orders API. Calls without one are dropped with a console warning.
Clakta reconciles the browser event against the order your server posts, and the server's order stays the source of truth for status, totals and contents — so a visitor who closes the tab before your thank-you page renders costs you nothing. Everything besides orderId is a small identifying subset of that payload (totalPrice, currency, paymentMethod, products, customer, tracking); fields the server owns aren't accepted from the client.
customer is personal data and is sent only under full_attribution with consent granted. See the @clakta/javascript README for the full field reference.
Both events also take an optional tracking block — clkt plus utm_source, utm_medium, utm_campaign and utm_content — that credits the order to a click. Omit clkt and the SDK resolves it from the current URL, falling back to the URL the visit landed on, which matters in the App Router: the confirmation page you redirect to no longer carries the ad's query string.
A common shape in the App Router — fire the purchase event from the confirmation page, once, with the order id you already have server-side:
// app/orders/[orderId]/confirmation/page.tsx
import { PurchaseTracker } from "./purchase-tracker"
export default async function ConfirmationPage({
params,
}: {
params: Promise<{ orderId: string }>
}) {
const { orderId } = await params
const order = await getOrder(orderId) // your own data layer
return (
<>
<PurchaseTracker order={order} />
<OrderSummary order={order} />
</>
)
}
// app/orders/[orderId]/confirmation/purchase-tracker.tsx
"use client"
import { purchase } from "@clakta/nextjs"
import { useEffect, useRef } from "react"
export function PurchaseTracker({ order }: { order: Order }) {
const tracked = useRef(false)
useEffect(() => {
if (tracked.current) return
tracked.current = true
purchase({
orderId: order.id,
totalPrice: order.total,
currency: order.currency,
paymentMethod: "credit_card",
products: order.items.map((item) => ({
id: item.productId,
name: item.name,
quantity: item.quantity,
price: item.price,
})),
customer: { email: order.customerEmail },
})
}, [order])
return null
}
Consent
Consent only has an effect when your project runs in full_attribution mode; in privacy_friendly mode no first-party identifiers are ever used.
Unless you set it, consent follows where the visitor is: visitors in the EU, the EEA, the UK and Switzerland — and any visitor whose location is unknown — start without it and are only identified once your cookie banner grants it. Everyone else starts with it. A visitor without consent is still counted, anonymously. See the @clakta/javascript README for exactly what is and isn't collected.
Set it on the provider — false to keep every visitor anonymous until they accept on the page, wherever they are and whatever they answered before, or true if the provider only renders once the visitor has accepted:
<ClaktaProvider id="YOUR_SCRIPT_ID" consent={false} />
The prop stays live after mount, so you can drive it from your banner's state. Or update it directly when the visitor answers:
"use client"
import { updateConsent } from "@clakta/nextjs"
export function CookieBanner() {
return <button onClick={() => updateConsent(true)}>Accept</button>
}
Read the current state with getConsent, which reports false until a choice is made:
import { getConsent } from "@clakta/nextjs"
getConsent() // => true
The answer is remembered — in a cookie for a year, and in localStorage with no expiry — so later pages apply it from their first event, and a visitor who accepts mid-visit starts an identified session right away that keeps the ad source they arrived with. Revoking consent immediately clears every identifier the SDK stored, and subsequent events are recorded anonymously.
API
Re-exported from @clakta/javascript, so you only need one dependency for the common cases:
init · pageView · trackEvent · identify · pageViewWithProduct · addToCart · initiateCheckout · purchase · getConsent · updateConsent
Plus the types: ClaktaCartDetails, ClaktaConfig, ClaktaOptions, ClaktaOrderCustomer, ClaktaOrderDetails, ClaktaPaymentMethod, ClaktaProduct, ClaktaTrackingParams, CustomerData, ResolvedConfig, TrackingMode.
See the @clakta/javascript README for the full API reference, tracking modes, and automatic-tracking behavior.
Links
- Website
@clakta/javascript— the underlying browser SDK- Issues
License
MIT