@adalong/widget
v7.8.1
Published
AdAlong widget library
Downloads
977
Readme
AdAlong Widget library
Table of contents
- Getting Started
- Basic Configuration
- Events
- Widget Customization & Settings
- Shop this look
- Analytics & Consent
- Order Tracking
- Facebook Pixel Integration
- Debugging
Getting Started
You can retrieve a widget api key by creating a widget through our interface : https://app.adalong.com/
Method 1: Via CDN
Quickest way to add the widget to your website : Add the CDN url directly in your HTML code to make it available globally. Ensure to replace [VERSION] with the right version.
<div id="adalong-widget"></div>
<script
defer
src="https://cdn.jsdelivr.net/npm/@adalong/widget@[VERSION]/dist/adalongWidget.min.js"
></script>
<script>
window.addEventListener('load', async () => {
const { initializeAdalongWidget } = window.AdalongWidget;
const widget = await initializeAdalongWidget({
token: 'WIDGET_API_KEY',
});
await widget.load('#adalong-widget');
});
</script>Method 2: Via NPM
Browser compatibility
This package doesn't support internet explorer.
Install & import the AdAlong Widget package
For projects using npm/webpack:
Install the plugin with NPM : npm install @adalong/widget
Then you can import it in your code :
import AdalongWidget from '@adalong/widget';
// Initialize the widget
const adalongWidget = await AdalongWidget.initializeAdalongWidget({
token: 'WIDGET_API_KEY',
config: {
id: 'customId', // Optional unique identifier
// Additional configuration options...
},
});
// Load into DOM element
await adalongWidget.load('#adalong-widget');Global access
Once instantiated, all widgets in the page can also be retrieved using the global object window.adalongWidgetAPI.
Examples :
// subscribe on events for all widgets
window.adalongWidgetAPI.widgets.forEach((widget) => widget.onEvent(...))
// find a particular widget from another script in the page
const myWidget = window.adalongWidgetAPI.widgets.find(w => w.id === 'customId');Basic Configuration
The widget accepts configuration options during initialization:
const adalongWidget = await AdalongWidget.initializeAdalongWidget({
token: 'WIDGET_API_KEY',
config: {
id: 'uniqueId', // Unique identifier for this widget instance
classPrefix: 'custom-', // CSS class prefix (default: 'adl-wdgt-')
},
});Data Attributes
You can define two different types of media sources: collections & products.
- Add the data-products attribute to load the media linked to the provided products.
- Add the data-collections attribute to load the media linked to the provided collections.
Those values must be an array of strings referring to respectively the product references and the collection ids.
⚠️ In case you don't specify any data-* attributes, the media would come from the fallback sources defined in the widget configuration on app.adalong.com
You can override those media sources using data attributes on your widget container:
<div
id='adalong-widget'
data-products='["PRODUCT_REF1", "PRODUCT_REF2"]' // Load specific products
data-collections='["COLLECTION_ID1"]' // Load specific collections
></div>Product localization
If you ingested an international catalog, a localization can be set via the AdAlong widget customization interface. This will be the default location for displaying product names, links and pricing information in shop the look. You can override this setting by passing a new location directly as a parameter when the widget is loaded.
adalongWidget.load('#widget', { localization: 'GB' });⚠️ Please note that the localization names must match those defined during implementation (if in doubt, the list can be viewed via the customization interface).
Events
You can also subscribe to events :
adalongWidget.onEvent('thumbnailClicked', (event) => {
console.log(event.post);
console.log(event.product);
console.log(event.position);
console.log(event.direction);
console.log(event.elapsedSeconds);
});For example, this would be the type of information you could receive from an event about a post :
export interface IMedia {
id: string;
type: 'image' | 'video' | 'text';
caption: string;
source: 'instagram' | 'tiktok';
username?: string;
post: string;
image?: string;
video?: string;
thumbnail?: string;
products?: IProduct[];
// local properties set by the browser
postIndex: number;
}Available events are 'widgetLoaded', 'widgetLoadingFailed', 'thumbnailLoaded', 'thumbnailUnavailable', 'thumbnailHover', 'thumbnailClicked', 'originalPostOpened', 'socialProfileOpened', 'postOpened', 'postClosed', 'stlOpened', 'stlClosed', 'mobilePlayerOpened', 'mobilePlayerClosed', 'postNavigation', 'mobilePlayerNavigation', 'stlNavigation', 'videoPlayed', 'carouselArrowClicked', 'carouselNativeScroll', 'productViewed', 'productClicked', 'packshotClicked', 'minContentNotReached', 'minContentReached', 'widgetViewed'
For more details about events, please refer to the EventMap interface in ./src/types.ts
A custom event is also emitted when a new widget instance is created in the page.
document.addEventListener('adalongWidgetCreated', ({ detail }) => {
console.log(detail.widget.id);
// Note that at this point the widget instance should not be loaded yet but
// you can now wait for the widgetLoaded event or check if the loaded property is true
if (!detail.widget.loaded) {
detail.widget.onEvent('widgetLoaded', () => {});
}
});Widget Customization & Settings
You can now fully customize the widget according to your needs. This includes :
Partial customization :
- Arrow design and visibility (mobile & desktop mode),
- All customization available through the AdAlong interface. Those settings & more are also documented as typescript interface in src/types.ts.
Global customization :
- Controlling the carousel layout : Control the carousel (the media list) to slide back and forth between medias thanks to a public function.
- Controlling the post viewer : Control the postviewer (the view modal) to slide back and forth between medias thanks to a public function.
All custom settings can be passed during instantiation to override the default settings :
await adalongWidget.load('#widget', {
...customSettings,
});Resizing the Widget
You can control the size of the widget by simply applying standard CSS width properties to the widget container element. For example:
<!-- Adjust widget size using inline styles -->
<div id="adalong-widget" style="width: 80%; margin: 0 auto;"></div>Or using CSS :
/* Make widget responsive but not full width */
#adalong-widget {
width: 80%;
max-width: 1200px;
margin: 0 auto;
}
/* Adjust widget size on mobile */
@media (max-width: 768px) {
#adalong-widget {
width: 100%;
}
}The widget will automatically adjust its layout to fit the available space while maintaining proper aspect ratios for thumbnails.
Classes
Some tags have classes starting with "adl-wdgt-" to help styling and customizing. You can also override this prefix by passing a string in the config object when instantiating the widget.
new AdalongWidget('token', {
classPrefix: 'myPrefix',
});CSS Selectors for customization
The widget provides several CSS class selectors that you can use to customize its appearance. Each class name is prefixed with the classPrefix value (default: adl-wdgt-). Here are the key selectors and how to use them:
Thumbnail Components
.{prefix}-thumbnail-content-active: Applied to the currently selected/active thumbnail (default z-index: 1000).{prefix}-thumbnail-content-inactive: Applied to non-active thumbnails (default z-index: 1).{prefix}-thumbnail-video: Applied to video elements within thumbnails when the video is being played (default z-index: 1001).{prefix}-thumbnail-pill: Applied to pill-shaped elements like username displays and mute buttons (default z-index: 1002)
Overlay
.{prefix}-overlay: The overlay background that appears when a post is opened (default z-index: 999)
Productlist Components
.{prefix}-productlist: The container for product listings in "Shop This Look" mode (default z-index: 1003).{prefix}-productlist-action-buttons: Action buttons in the product list view (default z-index: 1004)
Customizing z-index
If you experience z-index issues with thumbnails overlapping other page elements, you can override the z-index values. For example:
/* Reduce z-index of active thumbnails from 1000 to a lower value */
.adl-wdgt-thumbnail-content-active {
z-index: 50 !important;
}
/* Also adjust related elements as needed */
.adl-wdgt-overlay {
z-index: 49 !important;
}Control Carousel with custom functions
The AdalongWidget class has some public functions that can be called to control the widget with custom code launched from outisde.
public getSlideState(): { canSlideLeft: boolean, canSlideRight: boolean } {
return {
canSlideLeft: this.storeState.getState().canSlideLeft,
canSlideRight: this.storeState.getState().canSlideRight,
}
}This function will tell you if the carousel is able to slide right or left, thus if there are more images to view in either direction. Then, you can call
public setSlider(dir: 'left' | 'right') {
dispatchEvent(new CustomEvent('adalongWidget_slide', {detail: dir}))
}To trigger a movement in the carousel in the desired direction (by default new images are overflowing on the right).
The last function is to cycle through the elements in the carousel once their thumbnail has been clicked, and the popup with the details is shown:
public changePost(dir: 'left' | 'right') {
dispatchEvent(new CustomEvent('adalongWidget_changePost', { detail: dir }))
}the 'left' input will open the previous media, while the 'right' input will open the next.
Shop this look
Add a "shop this look" section
The click on a "shop this look" link will by default open the product url. This behavior can be overridden by providing a function to the shopThisLookHandler field in the config object.
new AdalongWidget('token', {
shopThisLookHandler: ({ media, product }, targetUrl) => {
const url = new URL(targetUrl);
url.searchParams.set('utm_source', 'source');
url.searchParams.set('utm_medium', 'medium');
window.open(url.href, '_blank');
},
});Customization
You can now fully customize the "shop this look" section according to your needs. This includes :
Partial customization :
"shop this look" text :
shopThisLookText?: string;
"more like this" text :
moreLikeThisText?: string;
arrows and background color, including the possibility to hide arrows in carousel mode, desktop and/or mobile :
hideArrows?: boolean;displayMobileCarouselArrows?: boolean;
"shop this look" custom product buttons (for ex. to add a "Add to cart" or "Add to favorites" button) : See Shop this look custom product buttons
all options directly available through the widget editing tool in our app

Global customization :
- Shop this look : When enabled, the "shop this look" section can be entirely replaced by a piece of code of your own creation.

Shop this look custom product buttons
You can add up to four custom buttons to your products.
This function is called for each product when we have to render and must return an object with react components for rendering the custom buttons. All button events must be handled here following react rules.
Place this function in an object as a parameter of the function AdalongWidget.
/**
* @param react The react lib used by AdalongWidget
* @param product Current rendered product
* @param media Current opened media
*/
getCustomProductButtons: (react, product, media) => {
const addToCart = () =>
react.createElement(
'button',
{
onClick: () => handleAddToCart(),
},
'🛒'
);
const addToFavorites = () =>
react.createElement(
'button',
{
// ... same here
},
'♡'
);
return {
topRight: addToCart,
// each position is optional
bottomRight: addToFavorites,
};
},You can use four keys to position your custom buttons on the product image : topRight, bottomRight, topLeft, bottomLeft.
If you want to place two buttons next to each other on the product image, you can use react fragments to create a single element :
const twoButtons = () =>
react.createElement(
react.Fragment,
null,
react.createElement(
'button',
{
onClick: () => handleAddToCart(),
},
'🛒',
),
react.createElement(
'button',
{
onClick: () => handleAddToFavorites(),
},
'❤️',
),
);Shop This Look entire customization
If you do not want to use the standard "Shop This Look" design, you can entirely customize this section to your needs, thanks to a rendering function called displayCustomShopThisLook.
In this function, you'll insert your piece of react or your react component as well as your logic in order to display it in place of the standard "Shop This Look". This function gives you the possibility to get all products-related info in order to map on it.
Here is a very simple example of the use of this function, by mapping on the products :
/**
* @param react The react lib used by AdalongWidget
* @param products An array containing all related products
* @param media Current opened media
* @param isMobile If the widget is viewed in desktop mode (false) or mobile mode (true)
*/
displayCustomShopThisLook: ({ react, products, media, isMobile, context }) => {
const { createElement } = react;
// Optional : Add the "Shop This Look" event tracking function
const handleProductClick = (product, e) => {
if (media) {
context.triggerEvent('shopThisLook', {
post: media,
originalEvent: e,
product: product.id,
});
}
};
// Map over the products array and create JSX elements for each product
const productElements = products.map((product) =>
createElement(
'div',
{ key: product.id },
createElement('img', { src: product.image_link, alt: product.title }),
createElement('h3', null, product.title),
createElement('p', null, product.description),
createElement('p', null, `${product.price} ${product.currency}`),
createElement('a', { href: product.link, onClick: (e) => handleProductClick(product, e), }, 'See the product'),
createElement('button', null, createElement('i', { className: 'fa fa-heart' }))
)
);
// Return the JSX to be rendered in place of the standard "Shop This Look" section
return createElement(
'div',
null,
createElement('h2', null, 'Custom Shop This Look'),
...productElements
);
},Here is the info you'll receive about a product :
export interface IProduct {
catalog_id: string;
company_id: string;
description: string;
id: string;
image_link: string;
link: string;
price?: number;
currency?: string;
title: string;
updated_at: string;
variant_name?: string;
}Analytics & Consent
Quick start
Analytics events are always sent to /api/widget/analytics/batch. By default they are anonymous: no persistent identifiers are created and the payloads include consent: false.
If you want visitor/session attribution, pass the consent state when you initialize the widget:
const widget = await initializeAdalongWidget({
token: 'WIDGET_API_KEY',
config: {
hasAnalyticsConsent: window.hasMeasurementConsent === true,
},
});Updating consent at runtime
When the user changes their cookie preferences, update the widget via the setHasAnalyticsConsent helper. Cookies (adalong_vid, adalong_sid) are created as soon as consent is true and are immediately deleted when you switch back to false.
// Using the instance
widget.setHasAnalyticsConsent(true);
// Or globally if you need to flip the flag before the instance is available
AdalongWidget.setHasAnalyticsConsent(false);Integration examples
Vanilla banner
<button id="accept-analytics">Accept analytics cookies</button>
<button id="decline-analytics">Decline analytics cookies</button>
<script>
const { setHasAnalyticsConsent } = window.AdalongWidget;
document.getElementById('accept-analytics').addEventListener('click', () => {
setHasAnalyticsConsent(true);
});
document.getElementById('decline-analytics').addEventListener('click', () => {
setHasAnalyticsConsent(false);
});
</script>Cookiebot
<script>
window.addEventListener('CookiebotOnLoad', async () => {
const hasConsent = () => Cookiebot.consent?.statistics === true;
const widget = await window.AdalongWidget.initializeAdalongWidget({
token: 'WIDGET_API_KEY',
config: { hasAnalyticsConsent: hasConsent() },
});
window.addEventListener('CookiebotOnAccept', () => {
widget.setHasAnalyticsConsent(hasConsent());
});
window.addEventListener('CookiebotOnDecline', () => {
widget.setHasAnalyticsConsent(false);
});
await widget.load('#adalong-widget');
});
</script>CookieScript
<script>
const onCookieScriptReady = async () => {
const hasConsent = () => {
const categories = window.CookieScriptConsent?.categories || {};
return Boolean(categories.statistics || categories.analytics);
};
const widget = await window.AdalongWidget.initializeAdalongWidget({
token: 'WIDGET_API_KEY',
config: { hasAnalyticsConsent: hasConsent() },
});
window.addEventListener('cookiescript-consent-updated', () => {
widget.setHasAnalyticsConsent(hasConsent());
});
await widget.load('#adalong-widget');
};
if (window.CookieScriptConsent) {
onCookieScriptReady();
} else {
window.addEventListener('CookieScriptReady', onCookieScriptReady);
}
</script>Important: If you do not update the consent flag after the user changes their preferences, the widget will remain in whichever mode you last set (anonymous or consented). Please keep the flag in sync with your CMP so consent choices stay respected.
Order Tracking
The widget package now publishes a lightweight bundle dedicated to checkout tracking. It lets you send confirmed orders to Adalong.
Script loading
Load adalongTrack.js on the order confirmation page (or wherever the purchase completes). The file lives next to the widget bundle on the CDN/NPM build.
<script
src="https://cdn.jsdelivr.net/npm/@adalong/widget@[VERSION]/dist/adalongTrack.js"
defer
></script>
<script>
window.addEventListener('load', async () => {
const { AdalongTrack } = window;
AdalongTrack.configure({
hasAnalyticsConsent: window.hasMeasurementConsent === true,
// Optional: point to a test URL instead of the default AdAlong production API URL
// apiUrl: 'http://localhost:3000',
});
AdalongTrack.trackOrder({
orderId: 'ORDER-123',
revenue: 249.9,
currency: 'EUR',
products: [
{ id: 'SKU-001', quantity: 1, price: 199.9 },
{ id: 'SKU-002', quantity: 1, price: 50 },
],
pageLocation: window.location.href,
});
});
</script>Payload contract
AdalongTrack.trackOrder(payload) accepts the following fields:
orderId(string, required) – your order reference, used for idempotency.revenue(number, required) – total amount captured for the order (taxes/shipping already included if you need them in analytics).currency(string, required) – ISO currency code (EUR,USD, ...). It is uppercased automatically.itemsorproducts(array, optional) – detailed line items. Objects support the keys{ id | productId, quantity?, price? }. Only entries with an ID are forwarded, and the list is capped at 50.pageLocation(string, optional) – falls back towindow.location.hrefif omitted.pageReferrer(string, optional) – defaults todocument.referrer.
CMP integration
Always call AdalongTrack.configure({ hasAnalyticsConsent: boolean }) when the confirmation page loads so the tracking bundle picks up the initial consent. Then, whenever your CMP toggles consent, call AdalongTrack.setHasAnalyticsConsent(boolean)— exactly the same flow as the widget. This pairing ensures the script keeps visitor/session identifiers only when consent allows it, and drops them (cookies included) the moment consent is revoked.
Facebook Pixel Integration
You can leverage AdAlong widget events in your Facebook Pixel.
Add Facebook Pixel base code
First you have to follow those instructions to create a FB pixel. Once created, you need to add the following base code into the <head> tag of the page. Please note that you should reference your pixel id in two places.
<!-- Facebook Pixel Code -->
<script>
!(function (f, b, e, v, n, t, s) {
if (f.fbq) return;
n = f.fbq = function () {
n.callMethod ? n.callMethod.apply(n, arguments) : n.queue.push(arguments);
};
if (!f._fbq) f._fbq = n;
n.push = n;
n.loaded = !0;
n.version = '2.0';
n.queue = [];
t = b.createElement(e);
t.async = !0;
t.src = v;
s = b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t, s);
})(window, document, 'script', 'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', '{your-pixel-id-goes-here}');
fbq('track', 'PageView');
</script>
<noscript>
<img
height="1"
width="1"
style="display:none"
src="https://www.facebook.com/tr?id={your-pixel-id-goes-here}&ev=PageView&noscript=1"
/>
</noscript>
<!-- End Facebook Pixel Code -->Track Events in your Facebook Pixel
Track standard Facebook events
Now to send information to Facebook from the AdAlong Widget you can map AdAlong events to Facebook standard events:
adalongWidget.onEvent('widgetLoaded', (event) => {
fbq('track', 'ViewContent', { posts: event.posts });
});Here is the full documentation on standard Facebook events
Track custom events
Now if you want to track specifically which post has been opened, and not only viewed, Facebook Pixel allows to track custom events following this model:
adalongWidget.onEvent('thumbnailClicked', (event) => {
fbq('trackCustom', 'ThumbnailClicked', {
post: event.post,
productIds: event.post.products.map(({ id }) => id),
});
});Note that in the example we send information about which products the opened post illustrates.
Debugging
Use npm start to build and watch for changes.
Then use npm link to link this repo to another project in which to require the library.
You can also use node debug.js to directly test the library and display it on
http://localhost:9800/?apiKey=yourWidgetKey
Widget version
Open your browser console and run:
console.log(window.adalongWidgetAPI.version);