Integrate your JOIN video widgets using Google Tag Manager.
β οΈ Warning: Integrating widgets through GTM can cause CLS (Cumulative Layout Shift) on your website. This is not specific to JOIN Stories but applies to any integration injected into the DOM through a Tag Manager.
Prerequisites
Before you begin, retrieve the following information from your JOIN back office:
1. Domain name
Your domain in the following format: your-brand.my.join-stories.com
β
2. Widget alias
βThe identifier of your widget (e.g. homepage, products, pdp)
β
Widget type
βJOIN offers two widget types. Choose the one that matches your use case :
Standard Widget : Displays the same content for all visitors.
Use cases: Homepage, category pages, landing pages.
Product Page Widget : Displays content specific to the product being viewed.
Use case: Product pages (PDP).
Integration with Google Tag Manager
With GTM, you do not create the container in HTML. Instead, the container is created dynamically in JavaScript and inserted into a specific location on your page using a CSS selector.
In GTM, create a Custom HTML Tag and paste the snippet corresponding to your widget type.
β
Standard Widget
<script>
(function () {
// βββ Configuration βββββββββββββββββββββββββββββββββββββββββββ
var domainName = "votre-marque.my.join-stories.com"; // :arrow_left: Votre domaine JOIN
var alias = "votre-alias"; // :arrow_left: Alias du widget
var divId = "join-widget";
var targetSelector = ".product-info"; // :arrow_left: SΓ©lecteur CSS de l'Γ©lΓ©ment cible
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
var target = document.querySelector(targetSelector);
if (!target) {
console.warn("JOIN: ΓlΓ©ment cible non trouvΓ© (" + targetSelector + ")");
return;
}
var container = document.createElement("div");
container.id = divId;
// MΓ©thodes d'insertion disponibles (gardez-en une seule) :
target.insertAdjacentElement("afterend", container); // Après l'élément
// target.insertAdjacentElement("beforebegin", container); // Avant l'Γ©lΓ©ment
// target.appendChild(container); // Γ la fin de l'Γ©lΓ©ment
// target.prepend(container); // Au dΓ©but de l'Γ©lΓ©ment
var script = document.createElement("script");
script.src = "https://" + domainName + "/widgets/" + alias + "/index.js";
script.setAttribute("data-join-widget-id", divId);
script.setAttribute("data-join-widget-alias", alias);
script.type = "text/javascript";
container.appendChild(script);
})();
</script>
Product Page Widget
This snippet loads the widget specific to the product currently being viewed, with an automatic fallback to the default widget if no content is associated with the product.
<script>
(function () {
// βββ Configuration βββββββββββββββββββββββββββββββββββββββββββ
var domainName = "votre-marque.my.join-stories.com"; // β¬ οΈ Votre domaine JOIN
var alias = "pdp"; // β¬ οΈ Alias du widget PDP
var divId = "join-widget-pdp";
var targetSelector = ".product-form__quantity"; // β¬ οΈ SΓ©lecteur CSS de l'Γ©lΓ©ment cible
var productId = {{Page.ProductId}}; // β¬ οΈ Variable GTM contenant l'ID produit
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
var target = document.querySelector(targetSelector);
if (!target) {
console.warn("JOIN: ΓlΓ©ment cible non trouvΓ© (" + targetSelector + ")");
return;
}
var container = document.createElement("div");
container.id = divId;
target.insertAdjacentElement("afterend", container);
var baseUrl = "https://" + domainName + "/widgets/" + alias;
var script = document.createElement("script");
script.src = baseUrl + "/" + productId + ".js";
script.setAttribute("data-join-widget-id", divId);
script.setAttribute("data-join-widget-alias", alias);
script.type = "text/javascript";
script.onerror = function () {
script.remove();
var fallback = document.createElement("script");
fallback.src = baseUrl + "/index.js";
fallback.setAttribute("data-join-widget-id", divId);
fallback.setAttribute("data-join-widget-alias", alias);
fallback.type = "text/javascript";
container.appendChild(fallback);
};
container.appendChild(script);
})();
</script>
Important points
CSS selector (targetSelector)
Choose a stable element that is always present on the page.
Common examples:
.product-infoβ Product information block.product-form__quantityβ Quantity selector.product-descriptionβ Product description#add-to-cart-buttonβ Add-to-cart button
Recommended GTM trigger:
Use DOM Ready or Window Loaded to ensure the target element exists before the script runs.
β
Insertion method
Only one insertion method should be active at a time (the others should remain commented out).
By default:
insertAdjacentElement("afterend", container)
inserts the widget immediately after the target element.
Reduce CLS (optional but recommended)
To minimize layout shifts, add a minimum height to the widget container using a separate GTM HTML tag or directly in your theme.
<style>
#join-widget,
#join-widget-pdp {
display: block;
width: 100%;
min-height: 114px;
margin: 20px 0;
}
/* Hauteur adaptΓ©e sur Γ©crans larges */
@media (min-aspect-ratio: 3/4) {
#join-widget,
#join-widget-pdp {
min-height: 283px;
}
}
</style>
β
Audience data (optional)
You can send audience segmentation data to JOIN before the widget loads by pushing it to window.jDataLayer.
Audience (custom segmentation)
<script>
window.jDataLayer = window.jDataLayer || [];
window.jDataLayer.push({
type: "audience",
data: "premium" // ex: "premium", "member", "vip"
});
</script>
These scripts must be executed before the JOIN widget loading tags in GTM.

