New Engagement setup

This guide walks you through a new Bloomreach Web SDK implementation for Engagement. Follow these steps if you're starting from scratch with no existing Bloomreach tracking on your website and don't need Discovery at this stage.

If you're setting up both products together, see New Engagement and Discovery setup.

Prerequisites

Before you start, make sure the following have been provisioned and you have access to:

Add the tracking snippet

Add the snippet below to every page on your website. Place it in the <head> before the closing </head> tag. This placement is required for non-flickering experiments to work correctly.

You can also add it via Google Tag Manager if you manage scripts through a tag management system.

⚠️

Important

Do not add the tracking snippet to payment gateways or pages that handle credit card data. Tracking scripts on payment pages can be exploited to intercept sensitive financial information.

Replace the placeholder values with your actual credentials. See Find your credentials for instructions.

<style>.xnpe_async_hide{opacity:0 !important}</style>
<script>
  !function(e,t,n,i,o,r){
    const s=4e3,c="xnpe_async_hide";
    function a(e){
      if("number"!=typeof e)return e;
      const t=new Date;
      return new Date(t.getTime()+1e3*e)
    }
    function p(e){
      return e.reduce((function(e,t){
        return e[t]=function(){e._.push([t.toString(),arguments])},e
      }),{_:[]})
    }
    function m(e,t,n){
      const i=n.createElement(t);
      i.src=e;
      const o=n.getElementsByTagName(t)[0];
      return o.parentNode.insertBefore(i,o),i
    }
    function l(e){
      return"[object Date]"===Object.prototype.toString.call(e)
    }
    r.target=r.target||"//api.exponea.com",
    r.file_path=r.file_path||r.target+"/js/brweb.min.js",
    o[t]=p(["anonymize","initialize","identify","getSegments","update",
      "track","trackLink","trackEnhancedEcommerce","getHtml","showHtml",
      "showBanner","showWebLayer","ping","getAbTest","loadDependency",
      "getRecommendation","reloadWebLayers","_preInitialize",
      "_initializeConfig","metadata"]),
    o[t].notifications=p(["isAvailable","isSubscribed","subscribe","unsubscribe"]),
    o[t].segments=p(["subscribe"]),
    o[t]["snippetVersion"]="v3.1.1",
    function(e,t,n,i){
      e[i]={sdk:e[n],sdkObjectName:n,skipExperiments:!!t.new_experiments,
        path:t.target,streamId:t.stream_id}
    }(o,r,t,i),
    function(e,t,n){m(e.file_path,t,n)}(r,n,e),
    function(e,t,n,i,o,r,p,u){
      if(!e.new_experiments)return;
      !0===e.new_experiments&&(e.new_experiments={});
      const _=e.new_experiments.hide_class||c,
            f=e.new_experiments.timeout||s,
            d=encodeURIComponent(r.location.href);
      let g;
      e.cookies&&e.cookies.expires&&(
        "number"==typeof e.cookies.expires||l(e.cookies.expires)
          ?g=a(e.cookies.expires)
          :e.cookies.expires.tracking&&(
              "number"==typeof e.cookies.expires.tracking||
              l(e.cookies.expires.tracking)
            )&&(g=a(e.cookies.expires.tracking)));
      g&&g<new Date&&(g=void 0);
      const b=
        e.target+"/webxp/streams/"+e.stream_id+"/"+t+"/"+
        (u.exec(p.cookie)||[0,"new"])[1]+
        "/modifications.min.js?http-referer="+d+
        "&timeout="+f+"ms"+
        (g?"&cookie-expires="+Math.floor(g.getTime()/1e3):"");
      "sync"===e.new_experiments.mode&&
      r.localStorage.getItem("__exponea__sync_modifications__")
        ?function(e,t,n,i,o){
            n[o][t]="<"+t+' src="'+e+'"></'+t+">";
            i.writeln(n[o][t]);
            i.writeln("<"+t+">!"+o+".init && document.writeln("+o+"."+t+
              '.replace("/'+t+'/","/'+t+'-async/")'+
              '.replace("><"," async><")</'+t+">)")
          }(b,t,r,p,n)
        :function(e,t,n,i,o,r,s,c){
            r.documentElement.classList.add(e);
            const a=m(n,i,r);
            function p(){
              o[c].init||m(n.replace("/"+i+"/","/"+i+"-async/"),i,r)
            }
            function l(){r.documentElement.classList.remove(e)}
            a.onload=p,a.onerror=p,o.setTimeout(l,t),o[s]._revealPage=l
          }(_,f,b,t,r,p,o,n)
    }(r,n,i,0,t,o,e,RegExp("__exponea_etc__"+"=([\\w-]+)")),
    function(e,t,n){
      var i;
      e[t]._initializeConfig(n);
      (null===(i=n.experimental)||void 0===i
        ?void 0:i.non_personalized_weblayers)&&e[t]._preInitialize(n);
      e[t].start=function(i){
        i&&Object.keys(i).forEach((e=>n[e]=i[e]));
        e[t].initialize(n)
      }
    }(o,t,r)
  }(document,"brweb","script","webxpClient",window,{
    target: "https://api.XXXXXXX.dev",
    // Your Bloomreach API base URL
    stream_id: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    // Your event stream ID
    experimental: {
      non_personalized_weblayers: true
    },
    new_experiments: {
      mode: "sync"
    },
    customer: {
      email_id: "[email protected]"
      // Identified visitor's email address
    },
    track: {
      default_properties: {
        customer_tier: "gold-member"
        // Custom properties added to all events
      },
      metadata: {
        domain_key: "Pacific",
        // Provided by your Discovery consultant
        view_id: "en_US",
        // Provided by your Discovery consultant
        test_data: true,
        // Ignores events in Discovery on production
        debug: true
        // Enables real-time integration mode in Discovery
      }
    },
  });
  brweb.start();
</script>

📘

Note

Some privacy regulations require you to call brweb.start() only after the visitor has granted cookie consent.

Snippet configuration reference

The table below covers the configuration parameters most relevant to an Engagement-only setup. For the full configuration reference, see JS SDK configuration.

ParameterTypeDescription
targetStringYour Bloomreach API base URL. Find it in Data Hub > Workspace settings > Access Management > API > API Credentials.
stream_idStringYour event stream ID. Find it in Data Hub > Event streams > select your stream > Access security.
customer.email_idStringThe identified visitor's email address. Set this when the visitor is logged in.
track.default_propertiesObjectCustom properties appended to every tracked event automatically.
track.metadataObjectOptional. Discovery-specific properties. Leave this out for an Engagement-only setup, or include it now if you plan to add Discovery later. See Bloomreach Web SDK - Metadata for the full parameter reference.

Identify visitors

Identify visitors as soon as they log in, using the hard ID configured in your Engagement project. This links their anonymous tracking history to their customer profile.

brweb.identify({ email_id: "[email protected]" });

When a visitor logs out, call anonymize() to clear their identifying cookies and begin tracking subsequent events under a new anonymous profile:

brweb.anonymize();

For the full identify() reference — including parameters, best practices, and re-identification behavior, see Customer identification in web tracking.

Track events

This section covers the recommended retail event set for Engagement. These events give you the data you need for customer segmentation, campaign targeting, funnel analysis, and personalization.

The full event reference, including all properties, Discovery parameter mappings, and API request examples, is on the Required events page. Your Bloomreach consultant or implementation partner will confirm which events and properties are relevant to your specific use cases.

view_item

Track this event when a product detail page (PDP) loads. It records an impression of the product.

brweb.track("view_item", {
  title: "Yellow wide sweater with turtleneck",
  product_id: "119479",
  variant_id: "MJ12199-0400",
  price: 49.99
});

view_category

Track this event on product listing pages and category pages.

brweb.track("view_category", {
  category_id: "650",
  title: "Turtlenecks",
  category_level_1: "Clothes",
  category_level_2: "Sweaters",
  category_level_3: "Sweaters & Cardigans"
});

cart_update

Track cart_update when a visitor adds or removes an item from the cart. The product_list property must always reflect the full cart contents after the change, as it's a snapshot of the end state. For the full property reference and limitations, see cart_update in Required events.

Add to cart

brweb.track("cart_update", {
  action: "add",
  title: "Yellow wide sweater with turtleneck",
  product_id: "119479",
  variant_id: "MJ12199-0400",
  product_list: [
    {
      product_id: "119479",
      quantity: 2
    }
  ],
  total_price: 99.98  // in USD reference currency for Engagement
});

Remove from cart

brweb.track("cart_update", {
  action: "remove",
  title: "Yellow wide sweater with turtleneck",
  product_id: "119479",
  variant_id: "MJ12199-0400",
  product_list: [
    {
      product_id: "119479",
      quantity: 1
    }
  ],
  total_price: 49.98
});
{
  "commands": [
    {
      "name": "customers/events",
      "data": {
        "customer_ids": {
          "cookie": "d218dfa8-37eb-4cd1-aec0-421ad6ccc5c9"
        },
        "event_type": "cart_update",
        "properties": {
          "action": "add",
          "title": "Yellow wide sweater with turtleneck",
          "product_id": "119479",
          "variant_id": "MJ12199-0400",
          "product_list": [
            {
              "product_id": "119479",
              "quantity": 2
            }
          ],
          "total_price": 99.98,
          "page_title": "Pacific | Clothing & accessories",
          "lang": "en-US",
          "location": "https://www.pacific.com/en/clothing/sweaters-cardigans/turtleneck.html",
          "referrer": "https://www.pacific.com/",
          "os": "Windows",
          "browser": "Chrome",
          "device": "Other"
        },
        "timestamp": 1749545984.2786303
      }
    }
  ]
}

checkout

Track this event at each step of a multi-step checkout flow. Use step_number to identify which step the visitor is on and step_title to label it. This event is used for checkout funnel analysis in Engagement and is not sent to Discovery.

brweb.track("checkout", {
  step_number: 2,
  step_title: "Shipping"
});

purchase

Track this event on the order confirmation page when an order is placed. Use purchase_status: "created" to mark a successful conversion.

For reliability and security, track purchase from your server rather than the browser. Server-side tracking lets you include sensitive data such as margins and costs, and allows you to send additional status updates, for example, when an order is cancelled or items are returned.

Send a POST request to:

https://tracking-api.bloomreach.co/track/u/v1/batch?stream_id=YOUR_STREAM_ID

For the required HTTP headers (X-Forwarded-For and User-Agent) and a full explanation of server-side tracking, see Required headers for Server-side tracking.

{
  "commands": [
    {
      "name": "customers/events",
      "data": {
        "customer_ids": {
          "email_id": "[email protected]"
        },
        "event_type": "purchase",
        "properties": {
          "purchase_id": "OID123",
          "purchase_status": "created",
          "total_price": 99.98,
          "product_list": [
            {
              "title": "Yellow wide sweater with turtleneck",
              "product_id": "119479",
              "variant_id": "MJ12199-0400",
              "price": 49.99,
              "quantity": 2
            }
          ]
        },
        "timestamp": 1749545984.2786303
      }
    }
  ]
}

Verify your implementation

Use the Bloomreach Tracking Console extension to validate your tracking setup in the browser. It lets you inspect events as they fire, check that properties are passing correctly, and confirm data is reaching Engagement.

What's next?