: This div serves as the wrapper for the Wistia player, providing responsive padding to maintain the video's aspect ratio. style='padding:56.25% 0 0 0;position:relative;' : The inline style achieves a 16:9 aspect ratio (56.25% is 9/16, which is the standard aspect ratio for videos). padding:56.25% : The padding-top is set to 56.25% to ensure that the container maintains the correct 16:9 aspect ratio regardless of the container’s width. position:relative; : This positions the element relative to its normal position, which is necessary to contain the positioned inner elements.
: This div is another wrapper around the actual video player that ensures it stretches to fit the container dimensions. Step 2: Initialize the Player and Listen for Events Use the _wq queue to detect when the video is ready, then bind documented events like ctaclick and ctaformsubmit to handle user interactions programmatically. Example : window._wq = window._wq || [];
_wq.push({
id: 'VIDEO_ID',
onReady: function(video) {
console.log('Wistia video is ready');
video.bind('ctaclick', function(ctaData) {
console.log('CTA Clicked:', ctaData);
});
video.bind('ctaformsubmit', function(formData) {
console.log('Form Submitted:', formData);
// Example: Send data to analytics
fetch('/track-form-submit', {
method: 'POST',
body: JSON.stringify(formData),
headers: { 'Content-Type': 'application/json' }
});
});
}
}); Explanation : window._wq : This line ensures that the global _wq object exists on the window (global) scope. _wq stands for Wistia Queue. window._wq || [] : The || [] ensures that if _wq does not already exist (i.e., it’s not initialized yet), it will be set to an empty array. _wq.push({...}) : This pushes an object to the _wq queue. Each object in the queue specifies an event handler for a specific Wistia video. id: 'VIDEO_ID' : This refers to the unique identifier of the Wistia video you are targeting. Replace 'VIDEO_ID' with the actual Wistia video ID. onReady: function(video) { ... } : The onReady function is called when the video player has fully loaded and is ready to interact with. Step 3: Implement Branching Logic and State Persistence Branching is achieved by pausing playback at key timestamps, displaying choice UI, and jumping to different video segments based on user input, with state saved in localStorage for persistence. Track Branch Choices and Persist Viewer State Track and save a viewer’s branch choice by storing the state in local storage, allowing the video to remember the viewer's choice even after page refreshes. Example : window._wq = window._wq || [];
_wq.push({
id: 'VIDEO_ID',
onReady: function(video) {
video.bind('secondchange', function(s) {
if (s === 45 && branchState === 'default') {
video.pause();
document.getElementById('branching-options').style.display = 'block';
}
});
// Handle user branch selection
document.getElementById('choose-path-a').addEventListener('click', function() {
branchState = 'pathA';
localStorage.setItem('videoBranch', branchState);
document.getElementById('branching-options').style.display = 'none';
video.time(60); // Jump to segment A
video.play();
});
document.getElementById('choose-path-b').addEventListener('click', function() {
branchState = 'pathB';
localStorage.setItem('videoBranch', branchState);
document.getElementById('branching-options').style.display = 'none';
video.time(90); // Jump to segment B
video.play();
});
}
}); Explanation : window._wq : This initializes the Wistia Queue (_wq) if it doesn't already exist. It is an array used to store event handlers that will be executed when the Wistia video is ready. window._wq || [] : The || [] ensures that if _wq is not defined yet (for example, if this script is run before the Wistia API is loaded), it will be initialized as an empty array. _wq.push({...}) : This pushes an object containing the event handler into the _wq array. The object specifies what should happen when the video is ready. id: 'VIDEO_ID' : This is the unique identifier for the Wistia video. Replace 'VIDEO_ID' with the actual ID of your video. onReady: function(video) : The onReady function is called once the video has finished loading and is ready for interaction. Step 4: Create Hotspots and Custom Interactions Since hotspots aren’t exposed via Wistia’s public API, simulate them with HTML overlays that toggle visibility based on the video’s current time using the timechange event. Wistia’s interactivity UI does not expose hotspot creation via public API, but you can simulate hotspots using transparent overlays or DOM elements synced with video time. Example : _wq.push({
id: 'VIDEO_ID',
onReady: function(video) {
video.bind('timechange', function() {
if (video.time() >= 30 && video.time() < 35) {
document.getElementById('hotspot').style.display = 'block';
} else {
document.getElementById('hotspot').style.display = 'none';
}
});
}
});
Explanation : video.bind('timechange', function() {...}) : This binds to the timechange event, which is fired whenever the video’s playback time changes. Hotspot : shown when the video reaches the 30-second mark and disappears after 35 seconds. Step 5: Debugging and Developer Workflow Tips Leverage the global _wq queue to inspect and access player instances for debugging. Ensure interactive elements support touch events and optimize event binding when handling multiple players. Use _wq for Dynamic Debugging Use the _wq variable to dynamically inspect and debug live video behavior, allowing for real-time testing and troubleshooting. Example : console.log(window._wq); Or add a dynamic queue handler during development: _wq.push({ id: 'VIDEO_ID', onReady: function(video) { window.wistiaVideo = video; console.log('Wistia player ready:', video); } }); Explanation : console.log(window._wq); : Logs the _wq array, which stores event handlers for Wistia videos. This lets developers inspect the current state of the queue. _wq.push({...}) : Pushes an object into the _wq array, specifying the event handler for a particular video. onReady: function(video) {...} : The onReady function is triggered once the video player has finished loading. Inside this function, you can manipulate the video object. window.wistiaVideo = video; : Assigns the video instance to a global variable so it can be accessed throughout the developer’s console or debugging environment. console.log('Wistia player ready:', video); : Logs the video object when it is ready, allowing you to inspect its properties and methods in the console. Mobile Support & Touch Events Make sure all interactive overlays are optimized for touch devices, ensuring smooth usability on mobile. Example : #hotspot { touch-action: manipulation; pointer-events: auto; } Explanation : touch-action: manipulation; : This CSS property is used to disable certain default touch behaviors (like pinch-to-zoom) on mobile devices. pointer-events: auto; : This ensures that the hotspot element is interactive, i.e., the element will respond to user pointer events (like tapping on mobile or mouse clicks on desktop). Optimize Performance for Multiple Videos To optimize performance when managing multiple Wistia players, avoid reinitializing listeners on the same ID to prevent redundant operations. Lazy-load inactive video embeds to improve page load times and resource usage. Additionally, use namespaces for video.bind() callbacks to prevent memory leaks and ensure efficient event handling. Step 6: Analytics and Engagement Tracking Now you need to bind to specific Wistia events like ctaclick and ctaformsubmit to capture user actions. After that, you must forward this data to external analytics services via standard HTTP requests. Example : _wq.push({
id: 'VIDEO_ID',
onReady: function(video) {
video.bind('ctaclick', function(data) {
// Push to custom analytics
sendToAnalytics('cta_click', data);
});
video.bind('ctaformsubmit', function(data) {
sendToAnalytics('form_submitted', data);
});
}
});
function sendToAnalytics(eventType, eventData) {
fetch('/track', {
method: 'POST',
body: JSON.stringify({ type: eventType, data: eventData }),
headers: { 'Content-Type': 'application/json' }
});
} Explanation : _wq.push({...}) : This adds a new event handler to the _wq array for a specific video. When the video with id='VIDEO_ID' is ready, the functions inside onReady are executed. video.bind('ctaclick', function(data) {...}) : This binds the ctaclick event to the video player. When the viewer clicks on a CTA during the video, the data associated with that click is passed to the callback function. video.bind('ctaformsubmit', function(data) {...}) : Similarly, the ctaformsubmit event is bound to track when a viewer submits a form embedded in the video. sendToAnalytics(eventType, eventData) : This function sends the event data to an external server. The fetch() API is used to send a POST request to the /track endpoint. fetch('/track', {...}) : Sends a POST request to the server to log the event. The request body contains the eventType and the eventData.