﻿#### 

In this article I`ll show you how to setup Facebook  (Meta) Ads for your existing website and how to use advantages of Sitecore CDP to make your advertising more flexible and save your money.

If you want to know more detailed about Facebook Ads integration and see it in action, here is my meetup presentation with demo:

#### Create Facebook Pixel with Conversions API.

First of all, you need create [Facebook Pixel](https://developers.facebook.com/docs/facebook-pixel)  and install it on your website. In your facebook account navigate to **Events Manager -&gt; Pixel app -&gt; Settings** and generate token for Conversions API:

![Sitecore CDP - Facebook Conversation API token](https://www.brimit.com/-/media/project/brimit/blog/2021/x3mxray/6/access_token.jpg)

The second key that you need is **Pixel ID**:

![Sitecore CDP - Facebook Ads Pixel ID](https://www.brimit.com/-/media/project/brimit/blog/2021/x3mxray/6/pixel_id.jpg)

Once you have **Pixel ID** and **token** it is time to test connection. In your facebook account navigate to **Events Manager -&gt; Pixel app -&gt; Test Events,** copy test event code *(TEST37153 in my case)* for future testing in Sitecore CDP and open **Graph API Explorer**:

![Sitecore CDP - Test Facebook Events](https://www.brimit.com/-/media/project/brimit/blog/2021/x3mxray/6/facebook_test_events_2.jpg) 

Insert your token in **Access Token** input and click submit button:

![Sitecore CDP - Facebook developer console](https://www.brimit.com/-/media/project/brimit/blog/2021/x3mxray/6/facebook_console_2.jpg) 

If you see response like on screenshot above, your connection is OK. If you return to **Test Events** tab you will see that your event is successfully tracked:

![Sitecore CDP - Facebook events tracking](https://www.brimit.com/-/media/project/brimit/blog/2021/x3mxray/6/facebook_test_success.jpg)

#### Install Facebook Pixel on your website.

Once you have Pixel ID, you need to insert facebook pixel integration javascript snippet in a layout page of your website:

```

<!-- 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 -->

```

#### How Facebook matches your website visitors with their facebook accounts?

When facebook`s script is loaded, it hits facebook with fingerprint of visitor device/browser/etc. Facebook stores this fingerprint and generates **\_fbp** cookie based on fingerprint.

There are 2 ways: your visitor is logged in to facebook in the same browser or not :

1. If facebook knows your visitor account, it includes this information in **\_fbp** cookie, and all events triggered on your website are immediately associated with this visitor facebook account.
2. The second case: if you visitor is not logged in to facebook, **\_fbp** cookie just contains visitor fingerprint and all events that are triggered on your website are just stored in facebook as anonymous and just used for data mining.But as soon as this visitor login to facebook and facebook identify this visitor account, all his history *(that was anonymous in the past)* will be immediately recognized by fingerprints and associated with visitor facebook account.

#### Push events to Facebook and Sitecore CDP.

On frontend side you need to trigger requests to facebook and CDP for all types of your events *View, AddToCard, Payment, ClearCard, Identity, etc.*There is a snippet of code that will be useful. Main function is **addEventTracker** that is called in format addEventTracker('View', data, 'boxever, fbq'), where first parameter is event type, third is list of systems where you want to push event, second is event data *(see Facebook pixel specification for each event type for more detailes).*

```

export const sendBoxeverCallFlows = (options, callback) => {
  const { params, friendlyId } = options;

  if (window.Boxever) {
    const flowData = {
      clientKey: Boxever.client_key,
      browserId: Boxever.getID(),
      channel: 'WEB',
      language: getCookie('order-cloud#lang').toLowerCase() || 'en',
      pointOfSale: window.location.host,
      currencyCode: localStorage.getItem('ocCurrency') || 'EUR',
      params: params,
      friendlyId: friendlyId,
    };

    Boxever.callFlows(flowData, function (response) {
      if (callback) callback(response);
    });
  }
};

export const sendBoxeverEvent = (type, options, callback) => {
  const { page, currency, ext } = options;

  _boxeverq.push(function () {
    const boxeverEvent = {
      browser_id: Boxever.getID(),
      channel: 'WEB',
      type: type,
      language: getCookie('order-cloud#lang').toUpperCase() || 'EN',
      pos: window.location.host,
      currency: currency,
      page: page || '/',
      ext: ext,
    };

    Boxever.eventCreate(
      boxeverEvent,
      function (data) {
        if (callback) callback();
      },
      'json'
    );
  });
};

export const sendBoxeverSearchEvent = (query, options, callback) => {
  const { page, currency, ext } = options;

  _boxeverq.push(function () {
    let boxeverEvent = {
      browser_id: Boxever.getID(),
      channel: 'WEB',
      type: 'SEARCH',
      language: getCookie('order-cloud#lang').toUpperCase() || 'EN',
      pos: window.location.host,
      currency: currency,
      page: page || '/',
      search_parameters: {
        search_input: query,
      },
      ext: ext,
    };

    boxeverEvent = Boxever.addUTMParams(boxeverEvent);
    Boxever.eventCreate(
      boxeverEvent,
      function (data) {
        if (callback) callback();
      },
      'json'
    );
  });
};

export const sendBoxeverIdentityEvent = (user, options, callback) => {
  const { page, currency, ext } = options;

  _boxeverq.push(function () {
    const boxeverEvent = {
      browser_id: Boxever.getID(),
      channel: 'WEB',
      type: 'IDENTITY',
      language: getCookie('order-cloud#lang').toUpperCase() || 'EN',
      pos: window.location.host,
      currency: currency,
      page: page || '/',
      email: user.Email,
      firstName: user.FirstName,
      lastName: user.LastName,
      ext: ext,
    };

    Boxever.eventCreate(
      boxeverEvent,
      function (data) {
        if (callback) callback();
      },
      'json'
    );
  });
};

export const sendBoxeverAddEvent = (product, options, callback) => {
  const { page, currency } = options;

  _boxeverq.push(function () {
    const boxeverEvent = {
      browser_id: Boxever.getID(),
      channel: 'WEB',
      type: 'ADD',
      language: getCookie('order-cloud#lang').toUpperCase() || 'EN',
      pos: window.location.host,
      currency: currency,
      page: page || '/',
      product: {
        type: 'STANDARD',
        productId: product.ID,
        name: product.Name,
        orderedAt: new Date(Date.now()).toISOString(),
        quantity: product.Quantity,
        price: product.Price.toFixed(2),
        currencyCode: currency || 'EUR',
        originalPrice: product.Price.toFixed(2),
        originalCurrencyCode: currency || 'EUR',
        referenceId: product.ReferenceId,
        item_id: product.ID,
        ext: product.Ext,
      },
    };

    Boxever.eventCreate(
      boxeverEvent,
      function (data) {
        if (callback) callback();
      },
      'json'
    );
  });
};

export const sendBoxeverConfirmEvent = (product, options, callback) => {
  const { page, currency } = options;

  _boxeverq.push(function () {
    const boxeverEvent = {
      browser_id: Boxever.getID(),
      channel: 'WEB',
      type: 'CONFIRM',
      language: getCookie('order-cloud#lang').toUpperCase() || 'EN',
      pos: window.location.host,
      currency: currency,
      page: page || '/',
      product: product,
    };

    Boxever.eventCreate(
      boxeverEvent,
      function (data) {
        if (callback) callback();
      },
      'json'
    );
  });
};

export const sendBoxeverPaymentEvent = (options, callback) => {
  const { page, currency } = options;

  _boxeverq.push(function () {
    const boxeverEvent = {
      browser_id: Boxever.getID(),
      channel: 'WEB',
      type: 'PAYMENT',
      language: getCookie('order-cloud#lang').toUpperCase() || 'EN',
      pos: window.location.host,
      currency: currency,
      page: page || '/',
      pay_type: 'Other',
    };

    Boxever.eventCreate(
      boxeverEvent,
      function (data) {
        if (callback) callback();
      },
      'json'
    );
  });
};

export const sendBoxeverCheckoutEvent = (order, options, callback) => {
  const { page, currency, ext } = options;

  _boxeverq.push(function () {
    const boxeverEvent = {
      browser_id: Boxever.getID(),
      channel: 'WEB',
      type: 'CHECKOUT',
      language: getCookie('order-cloud#lang').toUpperCase() || 'EN',
      pos: window.location.host,
      currency: currency,
      page: page || '/',
      referenceId: order.ID,
      status: order.Status,
      ext: ext,
    };

    Boxever.eventCreate(
      boxeverEvent,
      function (data) {
        if (callback) callback();
      },
      'json'
    );
  });
};

const uuidv4 = () => {
  return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(https://www.brimit.com/[018]/g, c =>
    (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
  );
};

const sha256 = async (message) => {
  // encode as UTF-8
  const msgBuffer = new TextEncoder().encode(message);                    
  // hash the message
  const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
  // convert ArrayBuffer to Array
  const hashArray = Array.from(new Uint8Array(hashBuffer));
  // convert bytes to hex string
  const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('');

  return hashHex;
};
https://www.brimit.com/* eslint-enable */

export const addEventTracker = (type, data, trackBy) => {
  const isBoxever = trackBy.indexOf('boxever') > -1;
  const isFbq = trackBy.indexOf('fbq') > -1;
  const guid = isFbq ? uuidv4() : undefined;
  const currency = localStorage.getItem('ocCurrency') || 'EUR';

  switch (type) {
    case 'Identity': {
      const { user } = data;

      sha256(user.Email).then((ecrEmail) => {
        if (isBoxever && window.Boxever) {
          sendBoxeverIdentityEvent(user, { page: window.location.pathname, currency: currency });
          getBoxeverUser(user.Email).then((response) => {
            if (response && response.items.length > 0) {
              setBoxeverUserExtensions(response.items[0].href, 'external_id', ecrEmail);
            }
          });
        }
        if (isFbq && window.fbq) {
          fbqInit({
            external_id: ecrEmail,
          });
        }
      });
      break;
    }

    case 'View': {
      const page = data.page;

      if (isBoxever && window.Boxever) {
        sendBoxeverEvent('VIEW', { page: page, currency: currency });
      }
      break;
    }

    case 'Search': {
      const { query } = data;

      if (isBoxever && window.Boxever) {
        sendBoxeverSearchEvent(query, { page: window.location.pathname, currency: currency });
      }
      break;
    }

    case 'ViewProduct': {
      const { product, page } = data;

      if (isBoxever && window.Boxever) {
        sendBoxeverEvent('VIEW', {
          page: page,
          currency: currency,
          ext: {
            productId: product.ID,
            facebook_event_id: guid,
            fbp: getCookie('_fbp'),
          },
        });
      }
      if (isFbq && window.fbq) {
        fbqTrack(
          'ViewContent',
          {
            content_ids: [product.ID],
            content_name: product.Name,
            value: product.PriceSchedule.PriceBreaks[0].Price,
            currency: currency,
            contents: [
              {
                id: product.ID,
              },
            ],
            content_type: 'product',
          },
          { eventID: guid }
        );
      }
      break;
    }

    case 'Checkout': {
      const { cart, order, page } = data;

      if (isBoxever && window.Boxever) {
        sendBoxeverEvent('VIEW', {
          page: page,
          currency: currency,
          ext: {
            facebook_event_id: guid,
            fbp: getCookie('_fbp'),
            cart: cart.map((ci) => {
              return {
                ProductID: ci.ProductID,
                Quantity: ci.Quantity,
                UnitPrice: ci.UnitPrice,
              };
            }),
            total: order.Total,
          },
        });
      }
      if (isFbq && window.fbq) {
        fbqTrack(
          'InitiateCheckout',
          {
            content_ids: cart.map((li) => li.ProductID),
            content_name: 'Checkout',
            value: order.Total,
            currency: currency,
            contents: cart.map((li) => {
              return { id: li.ProductID };
            }),
            content_type: 'product',
          },
          { eventID: guid }
        );
      }
      break;
    }

    case 'ClearCart': {
      if (isBoxever && window.Boxever) {
        sendBoxeverEvent('CLEAR_CART', { page: window.location.pathname, currency: currency });
      }
      break;
    }

    case 'AddToCart':
    case 'UpdateCart': {
      const { product, quantity, orderId } = data.extendedProduct;
      const { cart } = data;

      if (isBoxever && window.Boxever) {
        sendBoxeverAddEvent(
          {
            Name: product.Name,
            Quantity: quantity,
            Price: product.PriceSchedule.PriceBreaks[0].Price,
            originalPrice: product.PriceSchedule.PriceBreaks[0].Price,
            ID: product.ID,
            ReferenceId: orderId,
            Ext: {
              cart: cart,
              total: cart.reduce(
                (total, item) => total + Number(item.UnitPrice) * Number(item.Quantity),
                0
              ),
              image: product.xp.Images[0].Url || 'http://via.placeholder.com/300x300?text=No Image',
              facebook_event_id: guid,
              fbp: getCookie('_fbp'),
            },
          },
          { page: window.location.pathname, currency: currency }
        );
      }
      if (isFbq && window.fbq) {
        fbqTrack(
          'AddToCart',
          {
            content_ids: [product.ID],
            content_name: product.Name,
            value: product.PriceSchedule.PriceBreaks[0].Price,
            currency: currency,
            contents: [
              {
                id: product.ID,
                quantity: quantity,
              },
            ],
            content_type: 'product',
          },
          { eventID: guid }
        );
      }
      break;
    }

    case 'Payment': {
      if (isBoxever && window.Boxever) {
        sendBoxeverPaymentEvent({ page: window.location.pathname, currency: currency });
      }
      break;
    }

    case 'Confirm': {
      const { productList } = data;

      if (isBoxever && window.Boxever) {
        sendBoxeverConfirmEvent(productList, {
          page: window.location.pathname,
          currency: currency,
        });
      }
      break;
    }

    case 'Purchase': {
      const { cart, order, page } = data;

      if (isBoxever && window.Boxever) {
        sendBoxeverCheckoutEvent(
          { ID: order.ID, Status: 'PURCHASED' },
          {
            page: window.location.pathname,
            currency: currency,
            ext: {
              facebook_event_id: guid,
              fbp: getCookie('_fbp'),
              cart: cart.map((ci) => {
                return {
                  ProductID: ci.ProductID,
                  Quantity: ci.Quantity,
                  UnitPrice: ci.UnitPrice,
                };
              }),
              total: order.Total,
            },
          }
        );
      }
      if (isFbq && window.fbq) {
        fbqTrack(
          'Purchase',
          {
            content_ids: cart.map((li) => li.ProductID),
            content_name: 'Purchase',
            value: order.Total,
            currency: currency,
            contents: cart.map((li) => {
              return {
                id: li.ProductID,
                quantity: li.Quantity,
              };
            }),
            content_type: 'product',
          },
          { eventID: guid }
        );
      }
      break;
    }

    default: {
      break;
    }
  }
};

```

#### How to setup Facebook Conversions API connection in Sitecore CDP?

Login to your Sitecore CDP application account, **Connections -&gt; Add Connection-&gt; Destination**. Enter *Name* and *Description* of your connection,  choose *None* on Athentification tab and configure request parameters:

- **Method**: POST
- **URI**:  [https://graph.facebook.com/v12.0/{pixel\_id}/events?access\_token=](https://your_CH_endpoint/api/entities/query?query=Definition.Name=='M.PCM.Product'&amp;members=ProductName,ProductPrice){token}

Replace {pixel\_id} and {token} with your real values. To test your connection copy resuest body from recently tested facebook Graph API explorer:

![Sitecore CDP - Destination connection to Facebook](https://www.brimit.com/-/media/project/brimit/blog/2021/x3mxray/6/cdp_test.jpg)

If you testing request is successfull,  you will see recieved event in facebook **Test Events** tab. Save your connection with default mappings, don`t worry about testing Request body: it will be overwritten in triggered experience webhook in the future.

#### How to configure triggered experience?

In Sitecore CDP navigate to **Experiences -&gt; Full Stack -&gt; Create Experience -&gt; Triggered Experience**. In **Choose Connection** popup select your recently created Facebook destination connection:

![Sitecore CDP - Triggered Experience](https://www.brimit.com/-/media/project/brimit/blog/2021/x3mxray/6/triggered_experience.jpg)

For this demo I`ll show you how to forward *VIEW* event from your website to **Facebook Conversions API** *(for your real solution you can add more events as a trigger)*. Navigate to **Trigger** section and add custom trigger as shown on image below:

![Sitecore CDP - Add event trigger](https://www.brimit.com/-/media/project/brimit/blog/2021/x3mxray/6/view_trigger.jpg)

Go to **Webhook Composer** section and click on *Edit* button. Paste this Freemarker code into **API** tab:

```

<#assign pageUrl = "https://" + entity.pointOfSale + entity.arbitraryData.page>
<#assign timestamp = (.now?long / 1000)?floor?c>
<#assign guestUnique = guest.ref?replace("-","") + guest.ref?replace("-","")>
{
   "data": [
      {
         "event_name": "ViewContent",
         "event_time": ${timestamp},
         "event_source_url": "${pageUrl}",
         "action_source": "website",
         "user_data": {
            "em": "${guestUnique}",
            "client_user_agent": "Sitecore CDP"
         }
      }
   ],
   "test_event_code" : "TEST37153"
}

```

Parameters explanation:

- ```
    event_time - timestamp of triggered event in unix format (in seconds),
    ```
- ```
    user_data.em - any unique identifier of user in sha256 format. Unfortunatelly, I didn`t find how to caclulate sha256 in Freemarker, so for this demo example I just concatenate 2 times guest.ref value that is unique user identitier and looks like sha256; for real solution I store already sha256-hashed value of user email in extended guest profile properties.
    ```

Start your experience, navigate to your website and [generate some *VIEW* events](https://www.brimit.com/blog/cdp-1-how-to-connect-to-website). Go to **your experience -&gt; Operations -&gt; Execution Repost** where you will see statuses of youe triggered *VIEW* events. If all is OK you will see *SUCCESS* status:

![Sitecore CDP - Triggered Experience Execution Report](https://www.brimit.com/-/media/project/brimit/blog/2021/x3mxray/6/trigger_success.jpg?w=768&amp;hash=D32878CDA43FB2BBD1CFE1A076F563FB)

Because of we also passed **test\_event\_code** parameter, we can see that our events successfully hit facebook:

![Sitecore CDP - Success trigger](https://www.brimit.com/-/media/project/brimit/blog/2021/x3mxray/6/facebook_success.jpg)  

*NOTE: Remove **test\_event\_code** parameter for production events.*

In the next article I`ll show you how to setup **Facebook Ads** with triggered experience more flexible by using decision modeling. Stay updated!

Here goes the table of contents for my Sitecore CDP blog series:

- [Introduction](https://www.brimit.com/blog/cdp-0-intruduction)
- [How to connect Sitecore CDP to website](https://www.brimit.com/blog/cdp-1-how-to-connect-to-website)
- [Debugging tools](https://www.brimit.com/blog/cdp-2-debugging-tools)
- [How to pass extended data to Sitecore CDP](https://www.brimit.com/blog/cdp-3-how-to-pass-extended-data-to-sitecore-cdp)
- [How to use Data System connections (Decision model with Content Hub products)](https://www.brimit.com/blog/cdp-5-how-to-use-data-system-connections)
- [How to use AI connections (Web experience with Azure Cognitive Services)](https://www.brimit.com/blog/cdp-4-how-to-use-ai-connections)
- How to use Destination connections (Triggered experience webhook)
- How to use External service connections (Flows with External Service)
- Remarketing with Sitecore CDP and Facebook Ads

###### Author

[!\[sergey-200\](https://www.brimit.com/-/jssmedia/feature/blogs/authors/sergey-200.jpg?h=197&amp;iar=0&amp;w=200&amp;hash=0D636570F87F1C13C39E06EB19D9DF06)
Sergey Baranov
Sitecore MVP/ Senior Sitecore Developer](https://www.brimit.com/blog/author?authors=Sergey%20Baranov)

#### More on Sitecore

[!\[How Vercel Will Help You Save Effort When Deploying Sophisticated Sitecore Projects\](https://www.brimit.com/-/jssmedia/project/brimit/blog/2024/vercel_cover-image.png)
#Guides#How-toDXPE-commerce
##### How Vercel Will Help You Save Effort When Deploying Sophisticated Sitecore Projects
Optimize and accelerate the development and deployment of complex multisite Sitecore projects.
Alexei Vershalovich on July 17, 2024](https://www.brimit.com/blog/how-vercel-will-help-you-save-effort-when-deploying-sophisticated-sitecore-projects)

[!\[Training Up Tomorrow's Sitecore MVPs: a Mentoring Success Story\](https://www.brimit.com/-/jssmedia/project/brimit/blog/2023/sitecore-mentoring---cover-image.png)
#How-toDXP
##### Training Up Tomorrow's Sitecore MVPs: a Mentoring Success Story
How to participate in the Sitecore Mentor program and help younger colleagues jump-start a career in Sitecore development.
Sergey Baranov on October 2, 2023](https://www.brimit.com/blog/training-up-tomorrows-sitecore-mvps)

[!\[Going Headless. Part 2: When a Headless CMS Is Your Best Bet (if you have Sitecore)\](https://www.brimit.com/-/jssmedia/project/brimit/blog/2022/headless/adobestock_456986731.jpg)
#How-toDXPE-commerce
##### Going Headless. Part 2: When a Headless CMS Is Your Best Bet (if you have Sitecore)
Discover how a headless CMS can benefit organizations that use Sitecore.
Daniil Raschupkin, Palina Trokhautsava on September 15, 2022](https://www.brimit.com/blog/going-headless-part-2-when-a-headless-cms-is-your-best-bet-if-you-have-sitecore)

![](https://bat.bing.net/action/0?ti=187017043&amp;tm=gtm002&amp;Ver=2&amp;mid=a9e9c884-8cdd-411b-8974-6ab70be3a321&amp;bo=2&amp;gtm_tag_source=1&amp;pi=0&amp;lg=en-US&amp;sw=800&amp;sh=600&amp;sc=24&amp;nwd=1&amp;tl=Dive%20into%20Sitecore%20CDP%20-%20Remarketing%20with%20Sitecore%20CDP%20and%20Facebook%20Ads&amp;kw=sitecore%20CDP&amp;p=https%3A%2F%2Fwww.brimit.com%2Fblog%2Fcdp-7-facebook&amp;r=&amp;lt=329&amp;evt=pageLoad&amp;sv=2&amp;asc=D&amp;cdb=AQAY&amp;rn=839200)