Trigger Convert experiments dynamically when elements become visible on screen using custom JavaScript for efficient and optimized A/B testing.
Overview
This guide explains how to trigger Convert experiments when specific elements become visible on the user's screen (viewport). Think of the viewport as a window frame—only elements that appear within this frame are visible to your users. This solution is particularly useful when:
-
You don't have access to the Element In-view trigger feature in your current plan.
-
You need to trigger experiments when elements actually become visible on the user's screen.
-
You want to ensure experiments only run when specific content enters the user's screen view.
-
You need to trigger experiments based on users scrolling to specific content.
Implementation
Step 1: Access Global JavaScript
-
Navigate to your Convert dashboard.
-
Go to Your Project > Configuration > Global JS.
-
Add the following code to the Global JS section.
Step 2: Add the Code
// Configuration variables - MODIFY THESE
const SELECTOR_TO_WAIT_FOR = '.my-element'; // Change to your target element's selector
const EXPERIMENT_ID = '123456789'; // Change to your experiment ID
function waitForElementInViewport(selector, experimentId) {
return new Promise((resolve, reject) => {
let elementFound = false;
let elementInViewport = false;
// Set a timeout to reject the promise
const timeoutId = setTimeout(() => {
cleanup();
reject(new Error(`Timeout waiting for element in viewport: ${selector}`));
}, 5000);
function cleanup() {
if (intersectionObserver) intersectionObserver.disconnect();
if (domObserver) domObserver.disconnect();
clearTimeout(timeoutId);
}
// Create Intersection Observer with minimum threshold
const intersectionObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
elementInViewport = entry.isIntersecting;
// Only launch if element is currently in viewport when found
if (elementFound && elementInViewport) {
cleanup();
launchExperiment(experimentId);
resolve(entry.target);
}
});
},{
root: null,
threshold: 0 // trigger as soon as even 1px is visible
});
// Create DOM observer
const domObserver = new MutationObserver(() => {
const element = document.querySelector(selector);
if (element && !elementFound) {
elementFound = true;
intersectionObserver.observe(element);
// If element is immediately in viewport when found
const rect = element.getBoundingClientRect();
if (rect.top < window.innerHeight && rect.bottom > 0) {
elementInViewport = true;
cleanup();
launchExperiment(experimentId);
resolve(element);
}
}
});
// Check if element already exists
const element = document.querySelector(selector);
if (element) {
elementFound = true;
intersectionObserver.observe(element);
// Check if already in viewport
const rect = element.getBoundingClientRect();
if (rect.top < window.innerHeight && rect.bottom > 0) {
elementInViewport = true;
cleanup();
launchExperiment(experimentId);
resolve(element);
return;
}
}
// Start observing DOM changes
domObserver.observe(document.documentElement, {
childList: true,
subtree: true
});
});
}
function launchExperiment(experimentId) {
// Set the experiment flag
window[`experiment${experimentId}flag`] = true;
// Initialize converter queue if it doesn't exist
window._conv_q = window._conv_q || [];
// Push experiment execution
window._conv_q.push({
what: "executeExperiment",
params: {
experienceId: experimentId,
triggerIntegrations: false
}
});
}
// Execute the code
waitForElementInViewport(SELECTOR_TO_WAIT_FOR, EXPERIMENT_ID)
.then(element => {
console.log('Element found in viewport and experiment launched:', element);
console.log('Experiment flag set:', window[`experiment${EXPERIMENT_ID}flag`]);
})
.catch(error => {
console.error('Error:', error);
});
Step 3: Configure the Code
-
Change
SELECTOR_TO_WAIT_FOR
to match your target element's CSS selector. -
Update
EXPERIMENT_ID
with your specific experiment ID.
How It Works
This code:
-
Watches for a specific element to appear in the DOM.
-
Sets a flag variable (
experiment{ID}flag
) when the element is found. -
Launches the Convert experiment only after the element appears.
-
Uses
MutationObserver
for efficient DOM monitoring. -
Includes a 5-second timeout to prevent infinite waiting.
Key Features
-
Resource Efficient: Uses
MutationObserver
instead of polling. -
Automatic Cleanup: Properly disconnects observers when done.
-
Error Handling: Includes timeout and error catching.
-
Debug Logging: Console logs for troubleshooting.
-
Experiment Flag: Sets a trackable flag before launching.
When to Use This Solution
This code is ideal when:
-
Elements load dynamically after the initial page load.
-
You need to ensure experiments only run after specific content is available.
-
You want to track when experiments are actually ready to run.
-
You need a reliable way to trigger experiments based on DOM changes.
Best Practices
Selector Choice
-
Use specific, unique selectors.
-
Avoid overly complex selectors.
-
Test your selector in the browser console first.
Timeout Setting
-
The default timeout is 5 seconds.
-
Adjust based on your page's typical load time.
-
Consider increasing for slower-loading pages.
Error Monitoring
-
Check browser console for error messages.
-
Monitor the experiment flag status.
-
Test thoroughly in different scenarios.
Troubleshooting
If the experiment isn't triggering:
-
Verify your selector in the browser console.
-
Check if the experiment ID is correct.
-
Look for error messages in the console.
-
Ensure the element actually appears in the DOM.
-
Consider increasing the timeout value.
Additional Notes
-
This code should be added to the Global JS section to ensure it's available across all pages.
-
The solution is particularly useful for single-page applications (SPAs) or sites with dynamic content.
-
Multiple instances can be used for different experiments by duplicating and modifying the configuration variables.