API Reference

Complete reference for every method on the CADENCE SDK.

Constructor

typescript
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()

typescript
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)

typescript
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:

  1. Looks up the experiment by name
  2. Checks if the user falls within the traffic allocation (deterministic hash)
  3. If yes, assigns a variant based on traffic weights
  4. Automatically tracks an exposure event
  5. Applies visual mutations if the variant has them
  6. 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 + experimentId always produces the same variant
typescript
// 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)

typescript
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 false if 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?)

typescript
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:

  1. Checks all active experiment variants for a matching feature_overrides key
  2. Falls back to isFeatureEnabled() (returns true if enabled, otherwise defaultValue)

track(eventName, properties?)

typescript
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?)

typescript
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?)

typescript
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. |

typescript
// Recommended usage order
cadence.enableAntiFlicker(2000)
await cadence.ready()
cadence.getVariant('my-visual-test') // Content appears after mutations apply

destroy()

typescript
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() or trackConversion() calls become no-ops
typescript
// React cleanup
useEffect(() => {
  const client = new CadenceClient({ sdkKey: '...' })
  return () => client.destroy()
}, [])

runTest(config)

typescript
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:

  1. Waits for SDK initialization (ready())
  2. Checks if the current URL matches urlPattern (if provided). Returns 'control' if no match.
  3. Calls getVariant() to get the variant assignment (also tracks exposure)
  4. Finds the element via selector (if provided)
  5. 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

typescript
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-Button matches green-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 |

html
<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:

html
<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 configuration
  • POST /api/sdk/p/[projectId]/events — Receives batched events

SDK key endpoints (legacy)

  • GET /api/sdk/[sdkKey]/config — Fetches configuration by 64-char hex key
  • POST /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