Splitworthy documentation
React & developer SDK
Packaged or source installation, native rendering, explicit exposures and current adapter limitations.
Install from a local package or source
For installable local npm archives and package imports, follow the npm packages guide. There is no public npm release or public repository URL advertised here. Obtain authorised access to this project’s source, then retain packages/sdk and packages/react next to one another: the adapter imports the SDK by relative path.
For Vite, React and Lovable codebases, copy both folders into vendor/testwell/packages and import the source directly. The consuming toolchain must transpile TypeScript/TSX and resolve the application’s React. Do not copy the adapter alone. An alternative local file dependency needs the real relative repository path and must preserve both sibling folders.
// Source tree in your app:
// vendor/testwell/packages/sdk/src/...
// vendor/testwell/packages/react/src/index.tsx
import { TestwellProvider } from "../vendor/testwell/packages/react/src";
export function AppRoot() {
return (
<TestwellProvider
siteId="YOUR_PUBLIC_SITE_ID"
api="https://wordpress-experiment-hub.lovable.app"
consentRequired={true}
>
<App />
</TestwellProvider>
);
}Render a known developer experiment
Create a developer-controlled experiment and copy its exact key. useTestwellExperiment automatically attempts exposure after a variation is available; only use it in a component that actually displays that variation. Do not mount it invisibly just to retrieve an assignment.
ready can become true after the provider’s two-second give-up even without configuration. Always check variant as well: null means unavailable, unknown key or missing consent, not arm A. Fall back to your original experience when unavailable. Reserve enough space while loading, then record custom goals only after genuine success.
import { useTestwellExperiment } from "../vendor/testwell/packages/react/src";
export function Headline() {
const { variant, ready } = useTestwellExperiment("homepage-headline");
if (!ready) return <h1 className="headline-placeholder" aria-hidden="true" />;
if (variant === null) return <h1>Explore somewhere new.</h1>;
return <h1>{variant === "B"
? "Find your kind of escape."
: "Explore somewhere new."}</h1>;
}Conditional rendering and explicit exposure
For an experience shown conditionally, use useTestwell().getVariation(key) and call recordExposure(key) from an effect only after the assigned content has actually committed to a visible view. The automatic hook has no exposure-control option.
useTestwell also exposes trackGoal, grantConsent, revokeConsent and ready. Wire consent to your real banner. Calls outside TestwellProvider throw. Do not interpret a boolean tracking return as a server receipt.
Current React adapter limitations
This adapter is an early source integration, not a production-certified drop-in. Its readiness polling stops after initial configuration or a two-second timeout; subsequent consent grants and SPA configuration updates do not reliably notify React. Revalidate or supply your own reactive wrapper around the core before using those flows.
Withdrawal stops the core, but the adapter may leave a loading placeholder and does not guarantee original native React content is restored. Its hook exposure reference is keyed by experiment key rather than revision. Do not claim revision changes, remounts or Strict Mode flows are fully validated without testing them in the consuming app.
The provider accesses browser storage during render without the core’s guarded storage accessor; restricted localStorage can throw. Plan an error boundary and original-content fallback. These limitations are documented here rather than hidden by installation examples.
SSR, Next.js and TanStack Start
Server-side assignment and initial variation rendering are not implemented. The same placeholder can render on server and initial client pass, with assignment after hydration. No cached configuration accelerates returning visitors; configuration is always uncached.
For Next.js App Router, put the adapter in a client component. For TanStack Start, initialise experimentation in the browser and keep the first render consistent. Never inject private keys into browser configuration. There is no turnkey SSR cookie-evaluation API, CDN variation cache strategy or guaranteed zero-flicker SSR in this release.
Framework-free programmatic core
Import createSdk from the SDK source entry. Supply a browser environment after hydration, await start or grantConsent, retrieve the assignment, render the exact assigned view and then record exposure. Polling or subscribing your own application state is your responsibility; no public config-change event emitter exists.
import { createSdk } from "../vendor/testwell/packages/sdk/src/public";
let storage: Storage | null = null;
try { storage = window.localStorage; } catch { /* exclude if unavailable */ }
const sdk = createSdk(
{ siteId: "YOUR_PUBLIC_SITE_ID", api: "https://wordpress-experiment-hub.lovable.app", consentRequired: true },
{ win: window, doc: document, fetch: window.fetch.bind(window), storage,
now: () => Date.now(), uuid: () => crypto.randomUUID(),
setTimeout: (fn, ms) => window.setTimeout(fn, ms),
clearTimeout: (timer) => window.clearTimeout(timer as number) }
);
await sdk.start(); // waits for config only if consent already permits it
// In your real consent callback: await sdk.grantConsent();
const variant = sdk.getVariation("homepage-headline");
// If variant is null, render the original. Otherwise render that arm.
// After the assigned view is actually visible:
if (variant) sdk.recordExposure("homepage-headline");
// On confirmed action: sdk.trackGoal("signup_completed");
// On consent withdrawal: sdk.revokeConsent();
// On integration teardown: sdk.destroy();