Docs

React

npm install https://api.3x.example/v1/sdk/3x-engine-sdk-0.1.0.tgz
// src/main.tsx
import { createRoot } from "react-dom/client";
import { X3Provider } from "@3x-engine/sdk/react";
import { App } from "./App";

createRoot(document.getElementById("root")!).render(
  <X3Provider options={{ key: import.meta.env.VITE_X3_KEY, host: "/n3" }}>
    <App />
  </X3Provider>,
);
// anywhere below the provider
import { useX3 } from "@3x-engine/sdk/react";

export function PricingToggle() {
  const x3 = useX3();
  return <button onClick={() => x3.track("pricing_toggle", { period: "yearly" })}>Yearly</button>;
}
  • X3Provider calls init once on mount. React StrictMode's unmount/remount in development does not split the pageview: stopping is deferred by a task and cancelled by the remount.
  • Routing needs no wiring: the History API patch reports React Router, TanStack Router and similar navigations as spa pageviews.
  • useX3() returns the same API as the npm package (SDK reference). Outside a provider it returns a no-op API, so components stay testable.

Without the provider

Calling init in your entry file and importing track where needed works just as well; the provider only adds lifecycle handling and the hook.

Next.js

Use the dedicated adapter: Next.js.