Runtime API
Reference the Apex SDK runtime functions for initialization, tracking, consent, flags, diagnostics, and assignment state.
Import runtime functions from @drip-apex/sdk, or call the browser globals after the hosted script has loaded. The globals are compatibility surfaces, but they do not all have the same shape.
Browser global surfaces
| Surface | Shape and function names |
|---|---|
window.Drip | The hosted IIFE's module namespace. It exposes the named SDK exports, including init, track, trackStep, trackGoal, trackRevenue, setConsent, flush, getAssignments, getExperiments, getRuntimeTools, and the flag and diagnostics functions documented below. |
window.drip | The callable queue-compatible runtime API. It exposes init, track, step and its additive alias trackStep, goal/revenue/consent/lifecycle methods, flush, assignment/cart/experiment helpers, getTools and its additive alias getRuntimeTools, get, flag evaluation, signals, diagnostics, and push. |
window.Apex | The same callable runtime API object as window.drip, with the same function names. |
window.apexTools | The runtime-tools object itself, not the callable API. It exposes custom-JS and page-trigger helpers such as waitForElement, elementInView, and domChanged; do not call getRuntimeTools on this object. |
The tables below use the npm/window.Drip export names. On window.drip and window.Apex, trackStep/step and getRuntimeTools/getTools are equivalent aliases.
Initialization and state
| Function | Signature | Use |
|---|---|---|
init | (config: InitConfig) => Assignment[] | Initialize the SDK with inline experiments or fetched config. |
reInit | (forceReapply?: boolean) => Assignment[] | Re-evaluate assignments manually, optionally forcing mutations to reapply. |
recheckPrerequisites | () => void | Re-run project prerequisite gates and start or stop analytics if consent or state changed. |
getAssignments | () => Assignment[] | Read current active assignments. |
getExperiments | () => Experiment[] | Read loaded experiment configs. |
getRuntimeTools | () => ApexRuntimeTools | Get the runtime tools object used by custom JS and page triggers. |
getDiagnostics | () => SdkDiagnostics | Read public diagnostics; debug-only fields appear only when debug mode is enabled. |
getCartAttributes | () => CartAttributeEntry[] | Build the authoritative cart-attribute attribution stamp for a headless Shopify cart. |
getCartMetafields | (options?: { namespace?: string }) => Array<{ key: string; type: string; value: string }> | Build an optional BI mirror for cartMetafieldsSet. key is composite (namespace.attributeKey); namespaces accept 2–255 ASCII letters, digits, _, or -, and invalid values fall back to apex. See the headless integration guide. |
getCartMetafieldStaleKeys | (options?: { namespace?: string }) => string[] | Return every mirrorable composite key missing from the current getCartMetafields() output. Pass these keys to cartMetafieldDelete to clear stale optional mirror values. Use the same namespace option for both helpers. |
Tracking
| Function | Signature | Use |
|---|---|---|
track | (type: string, data?: Record<string, unknown>, experimentId?: string, variationId?: string) => void | Send a custom event and trigger matching custom goals. Defaults to the first active assignment when IDs are omitted. |
trackStep | (name: string, data?: Record<string, unknown>) => void | Send a virtual funnel step as funnel_step; dedupes once per session unless data.oncePerSession is false. |
trackGoal | (goalId: string, data?: Record<string, unknown>) => void | Trigger a configured Apex goal by ID for current assignments. |
trackRevenue | (revenue: number, data?: RevenueEventData) => void | Record each purchase at shop scope and attribute it to every running test assigned to the visitor. |
flush | () => Promise<void> | Start analytics if ready and flush queued events. Resolves immediately when no tracker exists. |
import { flush, track, trackGoal, trackRevenue, trackStep } from "@drip-apex/sdk";
track("add_to_cart", { product_id: "example-product", value: 49 });
trackStep("postcode_submitted");
trackGoal("checkout-started");
trackRevenue(119, { orderId: "order-example-1002", currency: "EUR" });
await flush();Consent
| Function | Signature | Use |
|---|---|---|
setConsent | (granted: boolean) => void | Persist consent state, clear storage when denied, and recheck assignment/tracking prerequisites. |
Feature flags
| Function | Signature | Use |
|---|---|---|
evaluateFlag | (flagId: string, context?) => boolean | Return true when the visitor is assigned to a non-control variation. |
evaluateFlagValue | evaluateFlagValue<T>(flagId, fallback?, context?) | Return the assigned variation value, or the fallback when unavailable. |
import { evaluateFlag, evaluateFlagValue } from "@drip-apex/sdk";
const enabled = evaluateFlag("checkout-progress-ui");
const ctaCopy = evaluateFlagValue("checkout-cta-copy", "Continue to checkout");Diagnostics
import { getDiagnostics } from "@drip-apex/sdk";
const diagnostics = getDiagnostics();
console.log({
initialized: diagnostics.initialized,
assignments: diagnostics.assignments,
configSource: diagnostics.configSource,
runtime: diagnostics.runtime
});getDiagnostics() is safe for support tooling because it redacts consent and tracking-block details unless SDK debug mode is enabled.
All builds expose customEventsHeld and tracking. The latter reports whether the tracker is
started, whether calls are blocked, the reason (consent_required, dnt, screenshot_mode, or
not_started), how many events are waiting behind an activation gate, and whether sent events
are QA-tagged. This lets QA distinguish a console call from an event that reached the wire.
Related pages
Decision timing
Read window.drip.getDiagnostics().load.timing (or the imported
getDiagnostics().load.timing) in any build, including a forced preview. The same
values are page-readable on window.__dripPerf without enabling debug or analytics.
| Diagnostics field | window.__dripPerf field | Meaning |
|---|---|---|
navigationStartAt | navigation_start_at | Navigation origin, epoch milliseconds from performance.timeOrigin, with a Date.now() - performance.now() fallback. |
configFetchedAt | config_fetched_at | Config fetch resolved, epoch milliseconds. Absent when no successful fetch occurred. |
decisionAt | decision_at | Assignment ready, the existing assignment_ready_at mark, in epoch milliseconds. |
firstMutationAt | first_mutation_at | First DOM mutation, epoch milliseconds, when one occurred. |
revealAt | reveal_at | Anti-flicker reveal, epoch milliseconds, when recorded. |
decisionLatencyMs | decision_latency_ms | decisionAt - navigationStartAt, milliseconds since navigation. |
forcedExperimentIds | forced_experiment_ids | Experiment IDs in the active force map. Empty for natural loads. |
The initial page's decisionAt, decisionLatencyMs, and load.assignmentReadyAt
remain unchanged on SPA route changes. timing.lastRouteChange is null until a
route evaluation completes, then contains { startedAt, decisionAt, decisionLatencyMs }.
Both timestamps are epoch milliseconds; its latency is decisionAt - startedAt
for that route evaluation, independent of how long the page has been open.
The matching window.__dripPerf fields are last_route_change_started_at,
last_route_change_decision_at, and last_route_change_decision_latency_ms
(all null before the first route evaluation). A route_change sdk_perf event
uses this route-local latency; an init event uses navigation-relative latency.
window.__dripPerf.qa_session_id identifies the QA session (also available as
getDiagnostics().qaSessionId). Unreached timestamps are absent, not zero.
Timing diagnostics do not change consent or telemetry gates. The sdk_perf event
includes decision_latency_ms and forced_experiment_ids when telemetry is allowed.
const timing = window.drip.getDiagnostics().load.timing;
console.table(timing);
console.log(window.__dripPerf.decision_latency_ms);The runtime remains unchanged. Natural runtime decides within tens of milliseconds
of SDK start when config ships inline with the snippet (measured p50 12 ms /
p95 54 ms on a large storefront). QA previews, screenshot-mode previews and
cookie-forced sessions take the QA config lane and fetch fresh config over the
network (measured p50 1.3 s / p95 7 s); they are not representative of launch
behaviour. URL-forced sessions without a qa parameter keep the inline or cached
config, so these measurements do not describe them. No config preload or
anti-flicker hold is planned.