# AdAlong Widget library

## Table of contents

- [Getting Started](#getting-started)
  - [Method 1: Via CDN](#method-1-via-cdn)
  - [Method 2: Via NPM](#method-2-via-npm)
  - [Global access](#global-access)
- [Basic Configuration](#basic-configuration)
  - [Data Attributes](#data-attributes)
  - [Product localization](#product-localization)
- [Events](#events)
- [Widget Customization & Settings](#widget-customization--settings)
  - [Classes](#classes)
  - [CSS Selectors for customization](#css-selectors-for-customization)
  - [Control Carousel with custom functions](#control-carousel-with-custom-functions)
  - [Custom Arrow Icons](#custom-arrow-icons)
- [Shop this look](#shop-this-look)
  - [Add a "shop this look" section](#add-a-shop-this-look-section)
  - [Customization](#customization)
  - [Shop this look custom product buttons](#shop-this-look-custom-product-buttons)
  - [Shop This Look entire customization](#shop-this-look-entire-customization)
- [Analytics & Consent](#analytics--consent)
  - [Quick start](#quick-start)
  - [Updating consent at runtime](#updating-consent-at-runtime)
  - [Integration examples](#integration-examples)
- [Order Tracking](#order-tracking)
  - [Script loading](#script-loading)
  - [Payload contract](#payload-contract)
  - [CMP integration](#cmp-integration)
- [Facebook Pixel Integration](#facebook-pixel-integration)
  - [Add Facebook Pixel base code](#add-facebook-pixel-base-code)
  - [Track Events in your Facebook Pixel](#track-events-in-your-facebook-pixel)
- [Debugging](#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.

```html
<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 :

```js
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 :

```js
// 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:

```js
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:

```js
<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.

```js
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).

#### Catalogs and multilingual sites
If you are working with a multilingual site (for example, Canada French - Canada English), it is essential that the localization used matches the loaded catalog (e.g., `CA_FR` for French, `CA_EN` for English). When implementing, creating catalogs, or calling the widget, always ensure that the localization parameter matches the correct catalog. A mismatch between localization and catalog can result in incorrect products or information being displayed to the user.

## Events

You can also subscribe to events :

```js
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 :

```js
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](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) is also emitted when a new widget instance is created in the page.

```js
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 :

```js
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:

```html
<!-- Adjust widget size using inline styles -->
<div id="adalong-widget" style="width: 80%; margin: 0 auto;"></div>
```

Or using CSS :

```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.

```js
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:

```css
/* 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.

```js
  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

```js
 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:

```js
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.

### Custom Arrow Icons

You can replace the default left and right arrow icons with any custom HTML (typically an inline SVG) using the `arrowLeft` and `arrowRight` config options:

```js
const widget = await AdalongWidget.initializeAdalongWidget({
  token: 'WIDGET_API_KEY',
  config: {
    arrowLeft: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M15 18l-6-6 6-6" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/></svg>',
    arrowRight: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M9 18l6-6-6-6" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/></svg>',
  },
});
```

The value is injected as raw HTML, so any valid inline SVG or HTML string works. Omitting either option keeps the default built-in arrow for that direction.

### Add to Cart button

You can display a built-in "Add to cart" button on each product by providing an `addToCartHandler` in the config. The button appears automatically — no extra markup needed.

```js
const widget = await AdalongWidget.initializeAdalongWidget({
  token: 'WIDGET_API_KEY',
  config: {
    addToCartHandler: ({ product, media }) => {
      console.log('Add to cart clicked');
      console.log('product.id    :', product.external_id);
      console.log('product.title :', product.title);
      console.log('product.link  :', product.link);
      console.log('media.id      :', media.id);
    },
  },
});
```

When `addToCartHandler` is set:

- In the **product list** (`shop_this_look_display: 'product_list'`), a cart button appears on the right side of each product row, alongside the navigation arrow.
- In the **product modal** (`shop_this_look_display: 'modal'`), the cart button is overlaid on the bottom-right corner of the product image with a frosted-glass background. Its size adapts automatically: larger when only one section is shown ("Shop this look" or "More like this"), smaller when both sections are displayed simultaneously.

#### Custom Add to Cart icon

You can replace the default shopping bag icon with any custom HTML (typically an inline SVG) using the `addToCartIcon` config option :

```js
const widget = await AdalongWidget.initializeAdalongWidget({
  token: 'WIDGET_API_KEY',
  config: {
    addToCartIcon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z"/><line x1="3" y1="6" x2="21" y2="6"/><path d="M16 10a4 4 0 0 1-8 0"/></svg>',
    addToCartHandler: ({ product, media }) => {
      // your handler
    },
  },
});
```

The icon uses `currentColor` for its stroke, so it inherits the button's text color. Omitting `addToCartIcon` keeps the default shopping bag.

#### Cart confirmation screen

After the add-to-cart button is clicked, a confirmation screen is showing in place of the shop this look :
- An **"Added to Cart"** heading
- A preview of the added product (image, title, price)
- A **"See my cart"** button that links to your cart page
- A **"Continue"** button that returns to the product list

Configure the cart link with the `cartUrl` option:

```js
const widget = await AdalongWidget.initializeAdalongWidget({
  token: 'WIDGET_API_KEY',
  config: {
    addToCartHandler: ({ product, media }) => { /* ... */ },
    cartUrl: 'https://example.com/cart',
  },
});
```

Omitting `cartUrl` hides the "See my cart" button.

## 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.

```js
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;` ⚠️ **Deprecated** — this label can now be configured directly in the widget settings on [app.adalong.com](https://app.adalong.com/). If a value is set in the interface it will take precedence and this config option will be ignored.
  - "more like this" text :
    - `moreLikeThisText?: string;` ⚠️ **Deprecated** — same as above, configurable via the interface and will be overridden by it.
  - arrows and background color, including the possibility to hide arrows in carousel mode, desktop and/or mobile :
    - `hideArrows?: boolean;`
    - `displayMobileCarouselArrows?: boolean;`
    - `arrowLeft?: string;` — custom HTML/SVG for the left arrow icon
    - `arrowRight?: string;` — custom HTML/SVG for the right arrow icon
    - See [Custom Arrow Icons](#custom-arrow-icons) for a full example
  - "add to cart" button and icon:
    - `addToCartHandler?: ({ product, media }) => void;` — enables the add to cart button; called when clicked
    - `addToCartIcon?: string;` — custom HTML/SVG for the add to cart icon
    - `cartUrl?: string;` — URL for the "See my cart" button in the confirmation screen
    - See [Add to Cart button](#add-to-cart-button) for a full example
  - "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](#shop-this-look-custom-product-buttons)

  - all options directly available through the widget editing tool in our app

![partial customization visualization](https://gitlab.com/adalongcorp/widget/-/raw/master/readme_images/partial_customization.png)

- 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.

![full customization visualization](https://gitlab.com/adalongcorp/widget/-/raw/master/readme_images/full_customization.png)

### 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`.

```js
 /**
   * @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 :

```js
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 :

```js
 /**
   * @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 :

```js
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:

```js
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`.

```js
// 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

```html
<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

```html
<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

```html
<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.

```html
<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.
- `items` or `products` *(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 to `window.location.href` if omitted.
- `pageReferrer` *(string, optional)* – defaults to `document.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](https://www.facebook.com/business/help/952192354843755?id=1205376682832142 'FB Pixel creation documentation'). 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.

```html
<!-- 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:

```js
adalongWidget.onEvent('widgetLoaded', (event) => {
  fbq('track', 'ViewContent', { posts: event.posts });
});
```

[Here](https://developers.facebook.com/docs/facebook-pixel/reference 'FB Standard Events') 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:

```js
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:

```js
console.log(window.adalongWidgetAPI.version);
```

