Script Tag Setup
Add A/B testing to any website with a single <script> tag. No npm, no bundler, no build step. This guide walks through a complete integration from setup to results.
Who this is for
- Static HTML sites
- WordPress, Squarespace, Webflow, or any CMS
- Landing pages and marketing sites
- Any project where you don't want (or can't use) a build tool
1. Add the SDK and initialize
Paste this in your HTML <head> so the SDK loads before the page renders:
<head>
<!-- other tags... -->
<script src="https://cdn.softpath.co/sdk/v1/cadence.min.js"></script>
<script>
Cadence.init({
apiKey: 'YOUR_API_KEY',
userId: '{{user.id}}' // Replace with your user ID variable
});
</script>
</head>
That's it — two lines. The SDK is now initialized and available globally as Cadence.
Replace YOUR_API_KEY
Get your API key from your project Settings page in the CADENCE dashboard. You can view and regenerate it anytime.
3. Complete example — button color test
Here's a full working HTML page that runs an A/B test on a call-to-action button and tracks clicks as conversions:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My Landing Page</title>
<script src="https://cdn.softpath.co/sdk/v1/cadence.min.js"></script>
<script>
Cadence.init({ apiKey: 'YOUR_API_KEY' });
</script>
<style>
.cta-button {
padding: 16px 32px;
font-size: 18px;
font-weight: bold;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
}
/* Default (control) style */
.cta-button { background-color: #1e293b; }
/* Variant styles — applied by the SDK */
.cta-button.variant-blue { background-color: #3b82f6; }
.cta-button.variant-green { background-color: #16a34a; }
</style>
</head>
<body>
<h1>Welcome to our site</h1>
<button id="cta-button" class="cta-button">Get Started Free</button>
<script>
Cadence.ready().then(function () {
var variant = Cadence.getVariant('cta-button-test')
var button = document.getElementById('cta-button')
// Apply the variant class
if (variant === 'blue') {
button.classList.add('variant-blue')
button.textContent = 'Start Free Trial'
} else if (variant === 'green') {
button.classList.add('variant-green')
button.textContent = 'Try It Free'
}
// 'control' — keep the default style
// Track clicks as conversions
button.addEventListener('click', function () {
Cadence.trackConversion('cta-click')
})
})
</script>
</body>
</html>
What this does
- Loads the SDK from the CDN and initializes with your API key
- Calls
Cadence.ready()to fetch your experiment config - Calls
getVariant('cta-button-test')— this assigns a variant and automatically tracks an exposure - Applies the variant's styles and copy to the button
- Tracks a conversion event when the button is clicked
3. Create the experiment in the dashboard
For the example above to work, create a matching experiment in the CADENCE dashboard:
- Go to your project and click Code Builder (or Create Experiment)
- Name it
cta-button-test(must match the string in your code exactly) - Add three variants:
control— the default dark buttonblue— blue button with "Start Free Trial"green— green button with "Try It Free"
- Set traffic allocation to 100% and split weights evenly (33/33/34)
- Start the experiment
Alternatively, use the Code Builder to generate a Cadence.runTest() snippet that handles variant application for you.
4. Track conversions
Any user action can be a conversion. Call trackConversion() wherever the goal action happens:
<script>
// Button click
document.getElementById('signup-btn').addEventListener('click', function () {
Cadence.trackConversion('signup-click')
})
// Form submission
document.getElementById('contact-form').addEventListener('submit', function () {
Cadence.trackConversion('form-submit')
})
// Page view (e.g., reaching a thank-you page)
if (window.location.pathname === '/thank-you') {
Cadence.trackConversion('purchase-complete', { value: 49.99 })
}
</script>
You can pass an optional properties object as the second argument. Use it for revenue values, plan names, or any metadata you want to see in your results.
5. Identify users (optional)
By default, the SDK generates an anonymous user ID and stores it in localStorage. This means the same visitor gets the same variant every time they return — as long as they don't clear their browser data.
For logged-in users, pass your own user ID for consistent assignment across devices:
<script>
Cadence.init({
apiKey: 'YOUR_API_KEY',
userId: 'user_abc123',
});
</script>
Mix anonymous and logged-in
You can initialize without a userId for anonymous visitors, then re-initialize with a userId after login. The SDK will use the new ID for all future assignments.
6. Prevent flicker
When the SDK changes visible elements (button text, colors, layout), users may see the original version flash before the variant loads. To prevent this, use enableAntiFlicker():
<head>
<script src="https://cdn.softpath.co/sdk/v1/cadence.min.js"></script>
<script>
Cadence.init({ apiKey: 'YOUR_API_KEY' });
Cadence.enableAntiFlicker(2000);
</script>
</head>
The page content is hidden until either:
- The SDK loads and applies variant changes, or
- The safety timeout (2 seconds) elapses — whichever comes first
This keeps the <script> in the <head> so it runs before any content renders.
7. Multiple experiments on one page
You can run as many experiments as you want. Each getVariant() call is independent:
<script>
Cadence.ready().then(function () {
// Experiment 1: button color
var btnVariant = Cadence.getVariant('cta-button-test')
if (btnVariant === 'blue') {
document.getElementById('cta').style.backgroundColor = '#3b82f6'
}
// Experiment 2: headline copy
var headlineVariant = Cadence.getVariant('hero-headline')
var headlines = {
control: 'Build something great',
urgency: 'Build something great — limited time offer',
social: 'Join 10,000+ teams building something great',
}
document.getElementById('hero-title').textContent =
headlines[headlineVariant] || headlines.control
// Experiment 3: pricing
var priceVariant = Cadence.getVariant('pricing-test')
if (priceVariant === 'annual-discount') {
document.getElementById('price').textContent = '$19/mo (billed annually)'
}
})
</script>
Each experiment tracks its own exposure and variant assignment independently.
8. Flush events on navigation
The SDK batches events and sends them every 5 seconds. It also flushes automatically on page unload using navigator.sendBeacon. For single-page apps or custom navigation, call destroy() to flush manually:
<script>
// Before navigating away
Cadence.destroy()
window.location.href = '/next-page'
</script>
Full reference
| Method | What it does |
|--------|-------------|
| Cadence.init({ apiKey, userId? }) | Initialize the SDK |
| Cadence.ready() | Returns a Promise that resolves when config is loaded |
| Cadence.getVariant('name') | Get the user's variant (tracks exposure automatically) |
| Cadence.runTest({ testId, variants, ... }) | Run a test with declarative config |
| Cadence.trackConversion('name', props?) | Track a goal completion |
| Cadence.track('name', props?) | Track a custom event |
| Cadence.isFeatureEnabled('name') | Check if a feature flag is on |
| Cadence.getFeatureValue('name', default) | Get a feature flag's value |
| Cadence.enableAntiFlicker(ms) | Hide content until variants apply |
| Cadence.destroy() | Flush events and clean up |
| Cadence.version | Returns the SDK version string |
For the full API reference with detailed signatures and examples, see API Reference.
Troubleshooting
Variant always returns "control"
Make sure Cadence.ready() has resolved before calling getVariant(). Without it, the SDK hasn't loaded your experiment config yet. Always put your logic inside the .then() callback, or use Cadence.runTest() which handles this automatically.
Events not appearing in the dashboard
Events are batched and sent every 5 seconds. Wait a moment, then refresh. Check your browser's Network tab for requests to /api/sdk/[key]/events — look for 4xx errors that indicate a bad SDK key.
Flicker on page load
Move the SDK <script> tag into the <head> and call Cadence.enableAntiFlicker() before any content renders. See step 6 above.
API key not working
Double-check that you copied the full key from project Settings. Go to Settings and click Test Connection to verify. Also check that no ad blockers are interfering with requests to cdn.softpath.co.
Content Security Policy (CSP) errors
If your site has a CSP, make sure it allows cdn.softpath.co in script-src and your CADENCE API domain in connect-src.
Next steps
- Quickstart — See all framework options side by side
- Creating Tests — Patterns for common test types
- Visual Editor — Make visual changes without writing code
- Event Tracking — Deep dive into the event system