API Reference
Complete reference for every method on the CADENCE SDK.
Constructor
import { CadenceClient } from '@cadence/sdk'
// Using Project ID (recommended)
const cadence = new CadenceClient({
projectId: 'proj_Ax8mK2pQr4nB',
userId: 'optional_user_id',
})
// Using SDK key (legacy)
const cadence = new CadenceClient({
sdkKey: 'your_64_char_hex_key',
userId: 'optional_user_id',
apiUrl: 'https://your-cadence-instance.com',
attributes: { plan: 'pro' },
})
Configuration options
| Option | Type | Required | Default | Description |
|--------|------|----------|---------|-------------|
| sdkKey | string | One of sdkKey or projectId | — | Your project's 64-char hex SDK key |
| projectId | string | One of sdkKey or projectId | — | Your Project ID (e.g., proj_Ax8mK2pQr4nB) |
| userId | string | No | Auto-generated | Stable user identifier. Persisted in localStorage if not provided |
| apiUrl | string | No | window.location.origin | Base URL for the CADENCE API |
| attributes | Record<string, unknown> | No | {} | User attributes (reserved for future use) |
| autoRun | boolean | No | true when using projectId | Auto-run visual experiments on matching pages |
| autoDiscover | boolean | No | false | Scan the DOM for data-cadence-experiment and data-cadence-variant attributes and show/hide elements based on variant assignment. Useful for no-code platforms like Webflow. |
Project ID vs SDK key
Use projectId for new integrations. It's shorter, works with the one-line script tag, and automatically enables visual experiment auto-run. The 64-char sdkKey is still supported for backward compatibility.
Methods
ready()
await cadence.ready()
Waits for the SDK to finish fetching experiment configuration from the server. Must be called before getVariant(), isFeatureEnabled(), or getFeatureValue().
- Returns a
Promise<void>that resolves when config is loaded - Safe to call multiple times (returns the same promise)
- If the config fetch fails, the promise still resolves (methods return safe defaults)
getVariant(experimentName)
const variant: string = cadence.getVariant('button-color-test')
Returns the variant name assigned to the current user for the given experiment.
Parameters:
| Name | Type | Description |
|------|------|-------------|
| experimentName | string | The name of the experiment (as created in the dashboard) |
Returns: string — The variant name (e.g., 'control', 'blue-button')
Behavior:
- Looks up the experiment by name
- Checks if the user falls within the traffic allocation (deterministic hash)
- If yes, assigns a variant based on traffic weights
- Automatically tracks an exposure event
- Applies visual mutations if the variant has them
- Returns the variant name
Edge cases:
- If the experiment doesn't exist, returns
'control' - If the user is outside the traffic allocation, returns the control variant
- If the user doesn't match the experiment's targeting rules (URL param conditions), returns the control variant
- Assignment is deterministic: same
userId+experimentIdalways produces the same variant
// Full example
await cadence.ready()
const variant = cadence.getVariant('hero-headline')
switch (variant) {
case 'urgency':
return <h1>Limited time offer</h1>
case 'social-proof':
return <h1>Join 10,000+ teams</h1>
default:
return <h1>Start your free trial</h1>
}
isFeatureEnabled(featureKey)
const enabled: boolean = cadence.isFeatureEnabled('new-checkout')
Checks if a feature flag is enabled for the current user.
Parameters:
| Name | Type | Description |
|------|------|-------------|
| featureKey | string | The key of the feature flag |
Returns: boolean
Behavior:
- Returns
falseif the flag doesn't exist or is disabled - Uses deterministic hashing against the rollout percentage
- Same user always gets the same result for the same flag
getFeatureValue(featureKey, defaultValue?)
const price: unknown = cadence.getFeatureValue('hero-price', 9.99)
Gets a feature value, checking experiment overrides first, then feature flags.
Parameters:
| Name | Type | Description |
|------|------|-------------|
| featureKey | string | The key of the feature |
| defaultValue | unknown | Fallback value if not found (default: null) |
Returns: unknown — The feature value or the default
Resolution order:
- Checks all active experiment variants for a matching
feature_overrideskey - Falls back to
isFeatureEnabled()(returnstrueif enabled, otherwisedefaultValue)
track(eventName, properties?)
cadence.track('button-click', { location: 'hero', color: 'blue' })
Tracks a custom event. Events are batched and sent automatically.
Parameters:
| Name | Type | Description |
|------|------|-------------|
| eventName | string | Name of the event |
| properties | Record<string, unknown> | Optional key-value pairs |
trackConversion(conversionName, properties?)
cadence.trackConversion('purchase', { value: 49.99, plan: 'pro' })
Tracks a conversion event. This is the primary metric used for experiment results in the dashboard.
Parameters:
| Name | Type | Description |
|------|------|-------------|
| conversionName | string | Name of the conversion |
| properties | Record<string, unknown> | Optional key-value pairs (e.g., revenue) |
Track at the point of success
Call trackConversion() after the action succeeds (e.g., after the API confirms a purchase), not on button click. This ensures you only count real conversions.
enableAntiFlicker(timeout?)
cadence.enableAntiFlicker(2000)
Hides the page content until visual mutations are applied, preventing a flash of unstyled content. Must be called before getVariant().
Parameters:
| Name | Type | Default | Description |
|------|------|---------|-------------|
| timeout | number | 2000 | Safety timeout in milliseconds. Content becomes visible after this time even if mutations haven't loaded. |
// Recommended usage order
cadence.enableAntiFlicker(2000)
await cadence.ready()
cadence.getVariant('my-visual-test') // Content appears after mutations apply
destroy()
cadence.destroy()
Cleans up the SDK instance. Flushes any remaining queued events and stops the background flush timer.
- Sends remaining events via
navigator.sendBeacon(works even during page unload) - Clears the flush interval timer
- Further
track()ortrackConversion()calls become no-ops
// React cleanup
useEffect(() => {
const client = new CadenceClient({ sdkKey: '...' })
return () => client.destroy()
}, [])
runTest(config)
const variant = await cadence.runTest({
testId: 'cta-button-test',
selector: '#cta-button',
urlPattern: /^\/pricing/,
variants: [
{ name: 'control', weight: 50, apply: () => {} },
{ name: 'blue', weight: 50, apply: (el) => {
if (el) el.style.backgroundColor = '#3b82f6'
}},
],
})
Runs a test with declarative configuration and code-based variant application. Handles initialization, URL matching, variant assignment, and applying changes in a single call.
Parameters:
| Name | Type | Description |
|------|------|-------------|
| config.testId | string | The experiment name (as created in the dashboard) |
| config.selector | string | Optional CSS selector for the target element |
| config.urlPattern | RegExp \| string | Optional URL pattern — test only runs on matching pages |
| config.variants | RunTestVariant[] | Array of variant definitions with name, weight, and apply function |
Returns: Promise<string> — The assigned variant name
Behavior:
- Waits for SDK initialization (
ready()) - Checks if the current URL matches
urlPattern(if provided). Returns'control'if no match. - Calls
getVariant()to get the variant assignment (also tracks exposure) - Finds the element via
selector(if provided) - Calls the matching variant's
apply(element)function
This is particularly useful for script tag integrations where you want a single declarative call instead of manually wiring up ready(), getVariant(), and DOM manipulation.
version
CadenceClient.version // '1.0.0'
Cadence.version // '1.0.0' (CDN global)
A static property that returns the current SDK version string. Useful for debugging and verifying which SDK version is running on your site.
Event batching
The SDK batches events for efficient network usage:
| Setting | Value | Description |
|---------|-------|-------------|
| Flush interval | 5 seconds | Events are sent every 5 seconds if the queue is non-empty |
| Flush threshold | 10 events | If 10+ events queue up, they're sent immediately |
| Page unload | sendBeacon | Remaining events are sent synchronously on beforeunload |
| Retry on failure | Yes | Failed events are re-queued for the next flush attempt |
QA & preview mode
Force a specific variant by adding ?cadence_variant=VariantName to any page URL. This is useful for QA testing and stakeholder reviews.
https://yoursite.com/pricing?cadence_variant=green-button
- Case-insensitive matching (e.g.,
Green-Buttonmatchesgreen-button) - Applies to all experiments on the page
- Bypasses targeting rules and traffic allocation — always returns the specified variant
- Exposure events are still tracked
- The dashboard's Preview & QA card on each experiment generates these links automatically
URL param targeting
Experiments can be configured with URL parameter targeting rules in the dashboard. When set, the SDK checks window.location.search before assigning a variant.
Operators:
| Operator | Behavior |
|----------|----------|
| equals | URL param value must exactly match |
| contains | URL param value must contain the substring |
| exists | URL param must be present (any value) |
| not_exists | URL param must not be present |
- All conditions use AND logic — every rule must match for the user to enter the experiment
- Users who don't match targeting receive the control variant
?cadence_variant=preview links bypass targeting (QA always works)- Empty targeting rules (the default) means all users are eligible
Script tag attributes (CDN usage)
When using the one-line script tag, these data- attributes configure the SDK:
| Attribute | What it does | Required |
|-----------|-------------|----------|
| data-project | Your Project ID (triggers auto-init) | Yes (for zero-code) |
| data-user-id | Your user's ID for cross-device consistency | No |
| data-api-url | Custom API URL (only if self-hosting) | No |
| data-anti-flicker | Hide content until visual changes apply | No |
<script src="https://cdn.softpath.co/sdk/v1/cadence.min.js" data-project="proj_Ax8mK2pQr4nB" data-anti-flicker></script>
Zero-code conversion tracking
Add data-cadence-goal to any HTML element to track clicks as conversions:
<button data-cadence-goal="signup-click">Sign Up</button>
<a href="/pricing" data-cadence-goal="pricing-visit">See Pricing</a>
The SDK uses a delegated click listener on document, so this works for elements added dynamically.
API endpoints
The SDK communicates with two endpoints. Which pair is used depends on how you initialized:
Project ID endpoints (recommended)
GET /api/sdk/p/[projectId]/config— Fetches experiment and feature flag configurationPOST /api/sdk/p/[projectId]/events— Receives batched events
SDK key endpoints (legacy)
GET /api/sdk/[sdkKey]/config— Fetches configuration by 64-char hex keyPOST /api/sdk/[sdkKey]/events— Receives batched events by hex key
Both pairs return the same data format. Config responses are cached for 60 seconds on the server. Event endpoints accept up to 100 events per request.
Next steps
- Event Tracking — Deep dive into the event system
- Feature Flags — Gradual rollouts with flags
- Installation — Framework-specific setup