HTML / Vanilla JS Integration
Standard integration without a framework, directly in HTML
data-ekooReqdata-ekoo-product-idReqdata-ekoo-localeautodata-ekoo-variantdata-ekoo-review-iddata-ekoo-on-eventdata-ekoo-directionnormaldata-ekoo-scale1data-ekoo-animationpulsedata-ekoo-animation-durationcontinuousdata-ekoo-always-openfalsedata-ekoo-show-imagetruedata-ekoo-not-fully-clickablefalsedata-ekoo-autoplayfalsedata-ekoo-audio-preloadmetadatadata-ekoo-show-transcriptfalsedata-ekoo-show-speed-buttonfalsedata-ekoo-closed-state-main-textdata-ekoo-closed-state-secondary-textdata-ekoo-modeautodata-shadow-modeopenwindow.EKOO_FORCE_SPA = truewindow.ekooShadowMode = "open"Recommended method: data attributes
Add a container with data-ekoo-* attributes and load the official script. The widget initializes automatically.
1<!-- Widget container -->2<ekoo-widget3 data-ekoo="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"4 data-ekoo-product-id="my-product-123"5 data-ekoo-locale="fr"6></ekoo-widget>78<!-- Ekoo script — load once per page -->9<script src="https://app.ekoo.co/widgets/widget-4.0.0-standalone.js"</script>Dynamic Product ID
If the product identifier is dynamic (e.g. extracted from the URL or a page attribute), you can use a JavaScript function to retrieve it and inject it into the data-ekoo-product-id attribute.
1<!-- Container — the ID will be injected by the script below -->2<div id="ekoo-container"3 data-ekoo="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"4 data-ekoo-locale="fr"5></div>67<script>8 // Retrieve the product ID from the URL, e.g.: /products/my-product-1239 function getProductId() {10 const parts = window.location.pathname.split('/');11 return parts[parts.length - 1];12 }1314 const container = document.getElementById('ekoo-container');15 if (container) {16 container.setAttribute('data-ekoo-product-id', getProductId());17 }18</script>1920<!-- Ekoo script — AFTER the product ID injection -->21<script src="https://app.ekoo.co/widgets/widget-4.0.0-standalone.js"</script>Declare callbacks BEFORE the script
If you use data-ekoo-on-event to receive widget events, declare the callback function before loading the Ekoo script. Otherwise, the script will not find the function at initialization time.
1<script>2 // Declare the function BEFORE the Ekoo script3 // The callback receives a single argument: the full stats body object4 function onEkooEvent(data) {5 console.log('Ekoo event:', data.stats.type, data);6 // E.g.: send to Google Analytics, dataLayer, etc.7 }8</script>910<ekoo-widget11 data-ekoo="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"12 data-ekoo-on-event="onEkooEvent"13 data-ekoo-product-id="my-product-123"14 data-ekoo-locale="fr"15></ekoo-widget>1617<script src="https://app.ekoo.co/widgets/widget-4.0.0-standalone.js"</script>Widget lifecycle
The widget emits ekoovisible once a review has been selected and is ready to display, and ekoohidden when it cannot display. Declare listeners before the widget script.
1<script>2 // Register listeners BEFORE loading the Ekoo widget script.3 document.addEventListener('ekoovisible', (event) => {4 const { productId, reviewId, review } = event.detail;5 console.log('Selected audio:', { productId, reviewId, review });6 });78 document.addEventListener('ekoohidden', ({ detail }) => {9 console.warn('Widget hidden:', detail.reason);10 });11</script>ekoovisible includes the widget, product and review identifiers, plus a public review object (audio and contributor). This contract is versioned and may gain fields without breaking integrations. ekoohidden exposes one of these reasons: noMatchingProduct, noAudios, experimentDisabled, or loadError.
Common pitfalls
- Script loaded before the container: if the
data-ekoocontainer is not yet in the DOM, the widget will not mount. Usedeferor place the script at the end of<body>. - Missing or incorrect Product ID: the widget will not display if the ID does not match any published audio.
- Multiple scripts loaded: only load the
widget-4.0.0-standalone.jsscript once per page, even if you have multiple containers. - Undeclared callback: the function referenced in
data-ekoo-on-eventmust be globally accessible (onwindow). - Wrong script URL: always use
widget-4.0.0-standalone.js, not an older version.