React bindings
Use DripProvider and all Apex SDK React hooks for assignments, variations, flags, tracking, revenue, and loading state.
Import React bindings from @drip-apex/sdk/react. The provider dynamically imports the browser SDK so React apps can avoid server-side DOM access during module evaluation.
DripProvider
tsx
import { DripProvider } from "@drip-apex/sdk/react";
export function StorefrontApp({ children }: { children: React.ReactNode }) {
return (
<DripProvider
shopId="demo-shop"
endpoint="https://events.drip-apex.com"
platformHint="spa"
spa={{ routerMode: "auto", domChangeTrigger: true }}
onExperimentViewed={(assignment) => {
console.log("Apex assignment", assignment.experimentId, assignment.variationId);
}}
>
{children}
</DripProvider>
);
}DripProvider accepts all InitConfig fields except it redefines onExperimentViewed as a React prop and requires children.
Assignment hooks
tsx
import { useAssignments, useExperiment, useLoading, useVariation } from "@drip-apex/sdk/react";
export function ProductHero() {
const loading = useLoading();
const allAssignments = useAssignments();
const heroAssignment = useExperiment("product-hero-layout");
const heroVariation = useVariation("product-hero-layout");
if (loading) return null;
return (
<section data-active-apex={allAssignments.length > 0 ? "yes" : "no"}>
<h1>
{heroVariation?.id === "proof-led"
? "Built for confident purchase decisions"
: "A better way to buy"}
</h1>
{heroAssignment ? <small>Variant: {heroAssignment.variationId}</small> : null}
</section>
);
}| Hook | Returns | Use |
|---|---|---|
useExperiment(experimentId) | Assignment or null | Read the assignment for an experiment ID or slug. |
useVariation(experimentId) | Variation summary or null | Render based on assigned variation ID and control state. |
useAssignments() | Assignment[] | Inspect all active assignments. |
useLoading() | boolean | Hide assignment-dependent UI until provider initialization completes. |
Feature flag hooks
tsx
import { useFeatureFlag, useFeatureFlagValue } from "@drip-apex/sdk/react";
export function CheckoutButton() {
const progressUiEnabled = useFeatureFlag("checkout-progress-ui");
const copy = useFeatureFlagValue("checkout-cta-copy", "Continue to checkout");
return (
<button data-progress-ui={progressUiEnabled ? "enabled" : "disabled"}>
{String(copy)}
</button>
);
}| Hook | Returns | Use |
|---|---|---|
useFeatureFlag(flagId) | boolean | Returns true for non-control flag assignments. |
useFeatureFlagValue(flagId, fallback) | Assigned value or fallback | Returns the assigned variation value or fallback. |
Tracking hooks
tsx
import { useTrack, useTrackGoal, useTrackRevenue } from "@drip-apex/sdk/react";
export function AddToCartButton() {
const track = useTrack();
const trackGoal = useTrackGoal();
const trackRevenue = useTrackRevenue();
return (
<button
onClick={() => {
track("add_to_cart", { product_id: "example-product" });
trackGoal("add-to-cart-click", { surface: "product-card" });
trackRevenue(49, { currency: "EUR", orderId: "order-preview" });
}}
>
Add to cart
</button>
);
}| Hook | Returns | Use |
|---|---|---|
useTrackGoal() | (goalId, data?) => void | Track a configured Apex goal. |
useTrack() | (type, data?) => void | Track a custom event. |
useTrackRevenue() | (revenue, data?) => void | Track revenue through the SDK. |
Provider boundary
Every hook throws if used outside <DripProvider>. Keep the provider in your app shell so route-level components share one SDK initialization.