@dumbledor/sdk
Typed analytics for React and Next.js using your project website ID.
@dumbledor/sdk is the npm package for React, Next.js, and server runtimes. Use the CDN script tag for static sites — one line, no build step.
Install
pnpm add @dumbledor/sdk
# or: npm install @dumbledor/sdkWebsite ID
Copy your website ID from project settings under Tracking. This is the same UUID used in the CDN script tag's data-website-id attribute.
Browser
Initialize once, then call track, page, or identify anywhere in your app.
import { init, track, identify } from "@dumbledor/sdk";
init({
websiteId: "YOUR_PROJECT_ID",
honorDoNotTrack: true,
});
track("signup", { plan: "pro" });
identify("user_123", { plan: "pro" });Initialization
One global client backs getClient(), track / page / identify, hooks, and DumbledorProvider. The provider calls init() internally — you do not need a separate init() when using the provider.
| Field | Type | Description |
|---|---|---|
| init() + track / page / identify | pattern | Vanilla JS or module-level calls after init(). |
| init() + hooks | pattern | useTrack, useIdentify, usePage without a provider wrapper. |
| DumbledorProvider | pattern | React / Next.js. Registers the global client and supplies context for hooks. |
| createClient() | pattern | Isolated instance for tests or multiple projects. Does not set the global client. |
One config
init() and DumbledorProvider with different options. The last initialization wins.Identify
identify(userId, traits?) links a stable user ID to the current visitor session. Dumbledor does not set cookies. Ingest derives the session from your project ID, IP address, user agent, and a daily salt.
- Browser: call identify after login in the same session where you track events.
- Retroactive: events earlier in that session also show the linked user ID once identify runs.
- Daily boundary: the session salt rotates at UTC midnight — call identify again for returning users on a new day.
- Traits: accepted in the payload but not stored yet.
- Server: pass the user’s ip and userAgent in context so ingest resolves the same session as their browser.
// Browser — after login
identify("user_123", { plan: "pro" });
track("purchase", { amount: 99 });
// Server — forward request headers to match the browser session
await dumbledor.identify("user_123", { plan: "pro" }, {
ip: request.headers.get("x-forwarded-for") ?? undefined,
userAgent: request.headers.get("user-agent") ?? undefined,
});React
DumbledorProvider calls init() internally. Wrap your app, add PageView for automatic pageviews on mount and route changes.
import { DumbledorProvider, PageView, useTrack } from "@dumbledor/sdk/react";
export function App() {
return (
<DumbledorProvider websiteId="YOUR_PROJECT_ID" honorDoNotTrack>
<PageView />
<CheckoutButton />
</DumbledorProvider>
);
}
function CheckoutButton() {
const track = useTrack();
return <button onClick={() => track("checkout_clicked")}>Checkout</button>;
}| Field | Type | Description |
|---|---|---|
| DumbledorProvider | component | Provides a client instance to child components. |
| PageView | component | Sends pageviews when pathname changes. Pass trackInitialView={false} to skip the first render. |
| useTrack() | hook | Returns a typed track() function. |
| useIdentify() | hook | Returns a typed identify() function. |
| usePage() | hook | Returns a manual page() function for custom navigation handling. |
Next.js App Router
Import from @dumbledor/sdk/next.AppRouterPageView listens to usePathname() and useSearchParams() so client navigations are tracked without calling page() yourself.
import { Suspense } from "react";
import { DumbledorProvider, AppRouterPageView } from "@dumbledor/sdk/next";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<DumbledorProvider websiteId={process.env.NEXT_PUBLIC_DUMBLEDOR_WEBSITE_ID!}>
<Suspense fallback={null}>
<AppRouterPageView />
</Suspense>
{children}
</DumbledorProvider>
</body>
</html>
);
}Pageviews and SSR
Server
Use @dumbledor/sdk/server in route handlers, webhooks, or background jobs for events that never touch the browser.
import { createServerClient } from "@dumbledor/sdk/server";
const dumbledor = createServerClient({
websiteId: process.env.DUMBLEDOR_WEBSITE_ID!,
});
await dumbledor.track(
"subscription_created",
{ plan: "pro" },
{
url: "https://app.example.com/billing",
userAgent: request.headers.get("user-agent") ?? undefined,
ip: request.headers.get("x-forwarded-for") ?? undefined,
},
);Server pageviews
Configuration
| Field | Type | Description |
|---|---|---|
| websiteId | uuid | Project website ID from tracking settings. Required. |
| ingestUrl | string | Ingest API origin. Default: https://ingest.dumbledor.com. |
| honorDoNotTrack | boolean | Skip tracking when the browser sends Do Not Track. Default: false. |
| disabled | boolean | Disable all tracking. Useful for local development. |
init({
websiteId: "YOUR_PROJECT_ID",
ingestUrl: "http://localhost:3001",
disabled: process.env.NODE_ENV === "development",
});Package exports
| Field | Type | Description |
|---|---|---|
| @dumbledor/sdk | entry | Core client: init, createClient, page, track, identify. |
| @dumbledor/sdk/react | entry | DumbledorProvider, PageView, useTrack, useIdentify, usePage. |
| @dumbledor/sdk/next | entry | AppRouterPageView for Next.js App Router. |
| @dumbledor/sdk/server | entry | createServerClient for route handlers and webhooks. |
Open the dashboard after wiring the SDK to confirm events are flowing.