Commanders Act Integration
Inject the Ekoo widget through a custom tag in TagCommander
Commanders Act (formerly TagCommander) is a European tag management platform. Like Google Tag Manager, it lets you add the Ekoo widget to your product pages without touching your site's source code. You create a Free input (custom) tag that inserts the container and loads the Ekoo script.
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-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"1. Create a Custom Tag
- Open your TagCommander container.
- Go to the EDIT step and click Add a tag.
- Pick the Free input (custom) tag from the library.
- In the JAVASCRIPT CODE section, paste the snippet below (replacing the default content).
- Uncheck Use Tag Cleaner if you want to keep the code as-is.
1<script>2(function() {3 // 1. Create the widget container4 var container = document.createElement('div');5 container.setAttribute('data-ekoo', 'YOUR_WEBSITE_ID');6 container.setAttribute('data-ekoo-product-id', 'MY_PRODUCT_ID');7 container.setAttribute('data-ekoo-locale', 'fr');89 // 2. Insert the container at the desired location10 // Adjust the CSS selector to match your site11 var target = document.querySelector('.product-detail');12 if (target) {13 target.appendChild(container);14 } else {15 document.body.appendChild(container);16 }1718 // 3. Load the Ekoo script (only once per page)19 if (!document.querySelector('script[src*="widget-4.0.0-standalone"]')) {20 var script = document.createElement('script');21 script.src = 'https://app.ekoo.co/widgets/widget-4.0.0-standalone.js';22 script.defer = true;23 document.head.appendChild(script);24 } else if (window.ekooLoad) {25 window.ekooLoad();26 }27})();28</script>2. Target the Right Element on the Page
Use document.querySelector() to position the widget where you want it. Common selectors:
.product-detail— main product detail block#add-to-cart— right before/after the add-to-cart button[data-product-id]— element carrying the product ID
Tip
Inspect your product page in the browser, identify the ideal CSS selector, then test it in the console with document.querySelector('...').
3. Dynamic Product ID via tc_vars
Commanders Act exposes your business data through the global window.tc_vars object (the Commanders Act dataLayer). On a product page, you'll typically find tc_vars.product_id or tc_vars.product_array.
1<script>2(function() {3 // Read the product ID from the Commanders Act dataLayer (tc_vars)4 // Common conventions: tc_vars.product_id or tc_vars.product_array[0].id5 var tcVars = window.tc_vars || {};6 var productId =7 tcVars.product_id ||8 (Array.isArray(tcVars.product_array) && tcVars.product_array[0]9 ? tcVars.product_array[0].id10 : null);1112 if (!productId) return; // Not a product page → do nothing1314 var container = document.createElement('div');15 container.setAttribute('data-ekoo', 'YOUR_WEBSITE_ID');16 container.setAttribute('data-ekoo-product-id', productId);17 container.setAttribute('data-ekoo-locale', tcVars.env_language || 'fr');1819 var target = document.querySelector('.product-detail');20 if (target) target.appendChild(container);2122 if (!document.querySelector('script[src*="widget-4.0.0-standalone"]')) {23 var script = document.createElement('script');24 script.src = 'https://app.ekoo.co/widgets/widget-4.0.0-standalone.js';25 script.defer = true;26 document.head.appendChild(script);27 } else if (window.ekooLoad) {28 window.ekooLoad();29 }30})();31</script>Populate tc_vars before the container
The tc_vars object must be populated before the container file loads. Otherwise the tag fires with an empty product_id and the widget won't mount.
4. Configure the Trigger
The tag should fire only on product pages, after the DOM is ready. Three common strategies in Commanders Act:
- Page View + condition — a
page_viewtrigger filtered bytc_vars.page_type === 'product'. - URL contains — filter on the page URL (e.g.
/product/). - Custom event — fire via
cact('trigger', 'product_view', {...})(particularly useful for SPAs, see section 5).
5. SPA Sites — Event-Driven Triggers
On a SPA (React, Vue, Angular…), navigation doesn't reload the page — a Page View trigger only fires once. Use the Commanders Act event API instead:
1<script>2// Listen to a custom Commanders Act event fired by your site3// (e.g. cact('trigger', 'product_view', { product_id: '...' }))4window.cact = window.cact || function () {5 (window.cact.q = window.cact.q || []).push(arguments);6};78cact('on', 'product_view', function (data) {9 if (!data || !data.product_id) return;1011 var container = document.createElement('div');12 container.setAttribute('data-ekoo', 'YOUR_WEBSITE_ID');13 container.setAttribute('data-ekoo-product-id', data.product_id);14 container.setAttribute('data-ekoo-locale', data.locale || 'fr');1516 var target = document.querySelector('.product-detail') || document.body;17 target.appendChild(container);1819 if (!document.querySelector('script[src*="widget-4.0.0-standalone"]')) {20 var script = document.createElement('script');21 script.src = 'https://app.ekoo.co/widgets/widget-4.0.0-standalone.js';22 script.defer = true;23 document.head.appendChild(script);24 } else if (window.ekooReload) {25 window.ekooReload();26 }27});28</script>On the application side, your SPA code must emit the event on each product navigation:
1// On every navigation to a product page2cact('trigger', 'product_view', {3 product_id: 'my-product-123',4 locale: 'en',5});6. Target Element Not Yet Rendered
The tag runs before client rendering
If your site renders the product block client-side (lazy-loading, deferred hydration), the target element may not exist when the tag runs. Use a MutationObserver to wait for it to appear.
1<script>2(function() {3 function injectEkoo(target) {4 var container = document.createElement('div');5 container.setAttribute('data-ekoo', 'YOUR_WEBSITE_ID');6 container.setAttribute('data-ekoo-product-id',7 (window.tc_vars && window.tc_vars.product_id) || 'MY_PRODUCT_ID');8 container.setAttribute('data-ekoo-locale', 'fr');9 target.appendChild(container);1011 if (!document.querySelector('script[src*="widget-4.0.0-standalone"]')) {12 var script = document.createElement('script');13 script.src = 'https://app.ekoo.co/widgets/widget-4.0.0-standalone.js';14 script.defer = true;15 document.head.appendChild(script);16 } else if (window.ekooLoad) {17 window.ekooLoad();18 }19 }2021 var target = document.querySelector('.product-detail');22 if (target) {23 injectEkoo(target);24 return;25 }2627 var observer = new MutationObserver(function(mutations, obs) {28 var el = document.querySelector('.product-detail');29 if (el) {30 obs.disconnect();31 injectEkoo(el);32 }33 });34 observer.observe(document.body, { childList: true, subtree: true });35})();36</script>7. Preview and Publish
- Enable Commanders Act Debug mode (URL parameter
?tc_debug=1or via the browser extension). - Navigate to a product page that has a published audio.
- In the Commanders Act console, verify that the tag fires and that the Ekoo widget renders.
- If everything looks good, deploy the container to production.
Consent (TrustCommander)
The Ekoo widget uses no cookies and collects no personal data on the client side. It therefore does not require GDPR consent to run. You can fire it as soon as the page loads, without waiting for CMP acceptance.
If your internal policy requires it
If you still prefer to gate loading on a consent category (e.g. "User Experience" or "Personalization"), hook into Commanders Act's consent.update event:
1cact('on', 'consent.update', function (consent) {2 // Adjust 'experience' to your CMP's consent category3 if (consent && consent.experience === true) {4 // Fire the Ekoo tag (container insertion + script)5 cact('trigger', 'product_view', {6 product_id: window.tc_vars && window.tc_vars.product_id,7 });8 }9});Performance — Load the Script Earlier
To shorten the time before the widget appears, you can create a second tag (All Pages trigger) that simply injects the Ekoo script into the <head>. See the Script loading page for the full pattern.
Common Pitfalls
- Empty tc_vars — the tag fires before the dataLayer is populated. Force the order by using the
page_viewtrigger (which waits fortc_vars) instead ofDOM Ready. - Tag fires on every page — remember the
tc_vars.page_type === 'product'filter or a URL filter to avoid loading the widget everywhere. - Script loaded twice — the
querySelector('script[src*="widget-4.0.0-standalone"]')guard prevents adding the script multiple times. - SPA without a custom event — a regular
page_viewtag won't re-fire. Usecact('trigger', 'product_view', …)from your SPA code on each navigation. - CSP policy — if your site uses a strict CSP, add
app.ekoo.coto thescript-srcdirective. - Tag Cleaner enabled — can rewrite IIFEs and conditional logic. Uncheck the option if the code looks altered in unexpected ways.
Note
Need help? Check the FAQ or contact Ekoo support.