Shopify

Shopify is an eCommerce platform that provides tools to help online sellers run their businesses.  

Fullstory can easily be set up on most Shopify themes by following the steps below. Once installed, you can use Fullstory to play back user sessions, build conversion funnels, and gain new insights into how your customers navigate your store. 

Installation

    1. Log in to your Shopify account, and open your admin panel.

    2. Select “Online Store” under the “Sales Channels” section of the admin panel.

      1.png 

    3. On the “Themes” section of the panel, click the Actions button in the upper right-hand corner of the page to reveal a dropdown.

    4. Click “Edit code”.
      2.png

    5. Click “theme.liquid” under the “Layout” section.*
      3.png

    6. Paste your Fullstory data capture snippet (learn how to find it here) into the <head> of the theme.
      4.png

 

* If you’re using a custom theme, it’s possible that the theme file has a name other than "theme.liquid". Check with the theme’s developer to verify.

Sending Shopify analytics events to Fullstory

In addition to adding the Fullstory snippet to your theme as described, you can send Shopify-provided analytics events to Fullstory.

Note: Shopify now recommends merchants and third parties upgrade to Checkout Extensibility.  Doing so affects previous Fullstory integration with the following notable changes per Shopify:

  • On August 13, 2024, checkout.liquid for the information, shipping, and payment pages will be turned off and no longer supported.
  • On August 28, 2025, checkout.liquid for the thank you and order status pages will be turned off and no longer supported. This also includes turning off apps using script tags and additional scripts under the post-purchase and order status pages. Shopify Scripts will continue to work alongside checkout extensibility until this date.
  • The checkout object will be deprecated for the Information, Shipping, and Payment pages on August 13, 2024.

To accommodate Checkout Extensibility, Fullstory provides shop administrators:

  1. A recommended Order Status page script that reliably sends a data-rich “Order Completed” event.
  2. A custom web pixel that captures newly available analytics events.  A shop admin can configure the custom web pixel. It works out-of-the-box with no custom development required.

Adding your data capture snippet to your Order Status page

Install the additional script by following the Tracking order steps provided by Shopify:

  1. From your Shopify admin, go to Settings > Checkout.
  2. Copy and paste the additional script code from this article.  If you have existing scripts, prepend the Fullstory script to the beginning of the existing scripts.
  3. Replace the text <org id> in the script’s code with your Org Id. To locate your Org Id, see the article How do I find my Fullstory Org Id.  The resulting line should appear similar to window._fs_org = 'o-0rGId-na1';.
  4. Click the Save button.

Order Status page script

<script>
window['_fs_host'] = 'fullstory.com';
window['_fs_script'] = 'edge.fullstory.com/s/fs.js';
window['_fs_org'] = '<org id>';
window['_fs_namespace'] = 'FS';
!function(m,n,e,t,l,o,g,y){var s,f,a=function(h){
return!(h in m)||(m.console&&m.console.log&&m.console.log('FullStory namespace conflict. Please set window["_fs_namespace"].'),!1)}(e)
;function p(b){var h,d=[];function j(){h&&(d.forEach((function(b){var d;try{d=b[h[0]]&&b[h[0]](h[1])}catch(h){return void(b[3]&&b[3](h))}
d&&d.then?d.then(b[2],b[3]):b[2]&&b[2](d)})),d.length=0)}function r(b){return function(d){h||(h=[b,d],j())}}return b(r(0),r(1)),{
then:function(b,h){return p((function(r,i){d.push([b,h,r,i]),j()}))}}}a&&(g=m[e]=function(){var b=function(b,d,j,r){function i(i,c){
h(b,d,j,i,c,r)}r=r||2;var c,u=/Async$/;return u.test(b)?(b=b.replace(u,""),"function"==typeof Promise?new Promise(i):p(i)):h(b,d,j,c,c,r)}
;function h(h,d,j,r,i,c){return b._api?b._api(h,d,j,r,i,c):(b.q&&b.q.push([h,d,j,r,i,c]),null)}return b.q=[],b}(),y=function(b){function h(h){
"function"==typeof h[4]&&h[4](new Error(b))}var d=g.q;if(d){for(var j=0;j<d.length;j++)h(d[j]);d.length=0,d.push=h}},function(){
(o=n.createElement(t)).async=!0,o.crossOrigin="anonymous",o.src="https://"+l,o.onerror=function(){y("Error loading "+l)}
;var b=n.getElementsByTagName(t)[0];b&&b.parentNode?b.parentNode.insertBefore(o,b):n.head.appendChild(o)}(),function(){function b(){}
function h(b,h,d){g(b,h,d,1)}function d(b,d,j){h("setProperties",{type:b,properties:d},j)}function j(b,h){d("user",b,h)}function r(b,h,d){j({
uid:b},d),h&&j(h,d)}g.identify=r,g.setUserVars=j,g.identifyAccount=b,g.clearUserCookie=b,g.setVars=d,g.event=function(b,d,j){h("trackEvent",{
name:b,properties:d},j)},g.anonymize=function(){r(!1)},g.shutdown=function(){h("shutdown")},g.restart=function(){h("restart")},
g.log=function(b,d){h("log",{level:b,msg:d})},g.consent=function(b){h("setIdentity",{consent:!arguments.length||b})}}(),s="fetch",
f="XMLHttpRequest",g._w={},g._w[f]=m[f],g._w[s]=m[s],m[s]&&(m[s]=function(){return g._w[s].apply(this,arguments)}),g._v="2.0.0")
}(window,document,window._fs_namespace,"script",window._fs_script);
</script>
{% if first_time_accessed %}
<script>
(function () {
  window[window['_fs_namespace']]('observe', {
    type: 'start',
    callback: () => {
      window[window['_fs_namespace']]('trackEvent', {
        name: 'Order Completed',
        properties: {
          cancel_reason: '{{ order.cancel_reason }}',
          cancelled: !!'{{ order.cancelled }}',
          confirmation_number: '{{ order.confirmation_number }}',
          financial_status: '{{ order.financial_status }}',
          fulfillment_status: '{{ order.fulfillment_status }}',
          id: '{{ order.id }}',
          item_count: +'{{ order.item_count }}',
          line_items_subtotal_price: +'{{ order.line_items_subtotal_price | money_without_currency }}',
          name: '{{ order.name }}',
          note: '{{ order.note }}',
          order_number: '{{ order.order_number }}',
          shipping_price: +'{{ order.shipping_price | money_without_currency }}',
          subtotal_price: +'{{ order.subtotal_price | money_without_currency }}',
          tax_price: +'{{ order.tax_price | money_without_currency }}',
          total_discounts: +'{{ order.total_discounts | money_without_currency }}',
          total_duties: +'{{ order.total_duties | money_without_currency }}',
          total_net_amount: +'{{ order.total_net_amount | money_without_currency }}',
          total_price: +'{{ order.total_price | money_without_currency }}',
          total_refunded_amount: +'{{ order.total_refunded_amount | money_without_currency }}',
        }
      });
    }
  })
}());
</script>
{% endif %}

When Shopify turns off the additional scripts feature on August 28, 2025, the “Order Completed” event will be provided by the pixel described in the next section.  

Adding the Fullstory Checkout Extensibility pixel to Shopify

Install the pixel by following the Add a custom pixel steps provided by Shopify:

  1. From your Shopify admin, go to Settings > Customer events.
  2. Click the Add custom pixel button.
  3. Name the pixel Fullstory Checkout Extension or similar.
  4. Click the Add pixel button.
  5. Copy and paste the pixel’s JavaScript code from this article.
  6. Replace the text <org id> in the pixel’s code with your Org Id. To locate your Org Id, see the article How do I find my Fullstory Org Id.  The resulting line should appear similar to window._fs_org = 'o-0rGId-na1';.
  7. Click the Save button.
  8. Activate the pixel by clicking the Connect button.

Fullstory Checkout Extensibility pixel

window._fs_org = '<org id>';
window._fs_identify_customer = false;
window._fs_use_order_completed = false;
window._fs_additional_scripts_snippet = true;
window._fs_host = 'fullstory.com';
window._fs_namespace = 'FS';
window._fs_debug = false;
window._fs_script = !window._fs_debug ? 'edge.fullstory.com/s/fs.js' : 'edge.fullstory.com/s/fs-debug.js';
function isAdditionalScriptAllowed() {
  return Date.now() < new Date('2025-08-28');
}
function isCheckout() {
  return document.location.pathname.indexOf('/checkouts/') !== -1;
}
function isThankYou() {
  return document.location.pathname.indexOf('/thank_you') !== -1;
}
if (isCheckout() || isThankYou()) {
  if (isCheckout()) {
    window._fs_is_outer_script = true;
  } else {
    if (isAdditionalScriptAllowed() && window._fs_additional_scripts_snippet) {
      window._fs_capture_on_startup = false;
    } else {
      window._fs_is_outer_script = true;
    }
  }
} else {
  window._fs_run_in_iframe = true;
}
!function(m,n,e,t,l,o,g,y){var s,f,a=function(h){
return!(h in m)||(m.console&&m.console.log&&m.console.log('FullStory namespace conflict. Please set window["_fs_namespace"].'),!1)}(e)
;function p(b){var h,d=[];function j(){h&&(d.forEach((function(b){var d;try{d=b[h[0]]&&b[h[0]](h[1])}catch(h){return void(b[3]&&b[3](h))}
d&&d.then?d.then(b[2],b[3]):b[2]&&b[2](d)})),d.length=0)}function r(b){return function(d){h||(h=[b,d],j())}}return b(r(0),r(1)),{
then:function(b,h){return p((function(r,i){d.push([b,h,r,i]),j()}))}}}a&&(g=m[e]=function(){var b=function(b,d,j,r){function i(i,c){
h(b,d,j,i,c,r)}r=r||2;var c,u=/Async$/;return u.test(b)?(b=b.replace(u,""),"function"==typeof Promise?new Promise(i):p(i)):h(b,d,j,c,c,r)}
;function h(h,d,j,r,i,c){return b._api?b._api(h,d,j,r,i,c):(b.q&&b.q.push([h,d,j,r,i,c]),null)}return b.q=[],b}(),y=function(b){function h(h){
"function"==typeof h[4]&&h[4](new Error(b))}var d=g.q;if(d){for(var j=0;j<d.length;j++)h(d[j]);d.length=0,d.push=h}},function(){
(o=n.createElement(t)).async=!0,o.crossOrigin="anonymous",o.src="https://"+l,o.onerror=function(){y("Error loading "+l)}
;var b=n.getElementsByTagName(t)[0];b&&b.parentNode?b.parentNode.insertBefore(o,b):n.head.appendChild(o)}(),function(){function b(){}
function h(b,h,d){g(b,h,d,1)}function d(b,d,j){h("setProperties",{type:b,properties:d},j)}function j(b,h){d("user",b,h)}function r(b,h,d){j({
uid:b},d),h&&j(h,d)}g.identify=r,g.setUserVars=j,g.identifyAccount=b,g.clearUserCookie=b,g.setVars=d,g.event=function(b,d,j){h("trackEvent",{
name:b,properties:d},j)},g.anonymize=function(){r(!1)},g.shutdown=function(){h("shutdown")},g.restart=function(){h("restart")},
g.log=function(b,d){h("log",{level:b,msg:d})},g.consent=function(b){h("setIdentity",{consent:!arguments.length||b})}}(),s="fetch",
f="XMLHttpRequest",g._w={},g._w[f]=m[f],g._w[s]=m[s],m[s]&&(m[s]=function(){return g._w[s].apply(this,arguments)}),g._v="2.0.0")
}(window,document,window._fs_namespace,"script",window._fs_script);


var customer = init.data.customer;
if (window._fs_identify_customer && customer && customer.id) {
  window[window._fs_namespace]('setIdentity', {
    uid: customer.id,
    properties: {
      email: customer.email,
      displayName: customer.firstName + ' ' + customer.lastName,
      ordersCount: customer.ordersCount
    }
  });
}
function format(obj) {
  var keys = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
  if (keys && keys.length > 0) {
    for (var key in obj) {
      if (keys.includes(key)) {
        delete obj[key];
      } else if (typeof obj[key] === 'object' && obj[key] !== null) {
        format(obj[key], keys);
      }
    }
  }
  return obj;
}
function trackEvent(name) {
  var properties = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  if (window._fs_debug) {
    console.log(Date.now() + ' ' + name + ' ' + JSON.stringify(properties));
  }
  window[window._fs_namespace]('trackEvent', {
    name: name,
    properties: properties
  }, 'shopify-pixel-v1');
}
if (isCheckout()) {
  analytics.subscribe('clicked', function (event) {
    trackEvent(event.name, format(event.data.element, ['value']));
  });
  analytics.subscribe('input_changed', function (event) {
    trackEvent(event.name, format(event.data.element, ['value']));
  });
}
analytics.subscribe('page_viewed', function (event) {
});
analytics.subscribe('cart_viewed', function (event) {
  trackEvent(event.name, format(event.data.cart, ['lines']));
});
analytics.subscribe('collection_viewed', function (event) {
  trackEvent(event.name, {
    productVariants: data.collection.productVariants.length,
    title: data.collection.title
  });
});
analytics.subscribe('product_viewed', function (event) {
  trackEvent(event.name, format(event.data.productVariant, ['image', 'url']));
});
analytics.subscribe('product_added_to_cart', function (event) {
  trackEvent(event.name, format(event.data.cartLine, ['image', 'url']));
});
analytics.subscribe('product_removed_from_cart', function (event) {
  trackEvent(event.name, format(event.data.cartLine, ['image', 'url']));
});
analytics.subscribe('search_submitted', function (event) {
  trackEvent(event.name, {
    productVariants: event.productVariants.length,
    query: event.query
  });
});
analytics.subscribe('checkout_started', function (event) {
  trackEvent(event.name);
});
analytics.subscribe('checkout_address_info_submitted', function (event) {
  trackEvent(event.name);
});
analytics.subscribe('checkout_contact_info_submitted', function (event) {
  trackEvent(event.name);
});
analytics.subscribe('checkout_shipping_info_submitted', function (event) {
  trackEvent(event.name);
});
analytics.subscribe('payment_info_submitted', function (event) {
  trackEvent(event.name);
});
analytics.subscribe('checkout_completed', function (event) {
  var checkout = event.data.checkout;
  var properties = {
    attributes: checkout.attributes,
    currencyCode: checkout.currencyCode,
    discountApplications: checkout.discountApplications.map(function (d) {
      return d.allocationMethod + ':' + d.targetSelection + ':' + d.targetType + ':' + d.type;
    }),
    discountTitles: checkout.discountApplications.map(function (d) {
      return d.title;
    }),
    lineItems: checkout.lineItems.length,
    orderId: checkout.order.id,
    subtotalPrice: checkout.subtotalPrice,
    totalPrice: checkout.totalPrice,
    totalTax: checkout.totalTax,
    transactionGateways: checkout.transactions.map(function (t) {
      return t.gateway;
    })
  };
  if (window._fs_use_order_completed || !isAdditionalScriptAllowed()) {
    properties.products = checkout.lineItems.map(function (l) {
      return {
        quantity: l.quantity,
        productTitle: l.title,
        price: l.variant.price,
        sku: l.variant.sku,
        variantTitle: l.variant.title
      };
    });
    trackEvent('Order Completed', properties);
  } else {
    trackEvent(event.name, properties);
  }
});

Fullstory custom events will now appear throughout session replays shortly after activating the pixel. More specifically, the following custom events have been instrumented.  Note that some events may have data incompatible with Fullstory and may be omitted.  Additionally, the pixel specifically omits the value property of Shopify DOM events as it could include sensitive or personal information.

Any theme page where the Fullstory snippet has been added:

Payments page:

Thank you page (after August 28, 2025):

Configure a Revenue Event

Since the pixel provides a conversion event, follow the steps to Choose Your Revenue Event in Settings, and choose either the “Order Completed” event.  Select either the total_price_real or totalPrice_real property available.

 

Known issues with the Fullstory Checkout Extensibility pixel

Due to technical limitations of the pixel sandbox provided by Shopify, the following issues are known to occur.

The payment page and thank you page (after August 28, 2025) will appear blank in session replay, but analytics events will still be captured.  Fullstory session replays will show website content on all pages leading up to the payment page.  Since the payment page’s content is inaccessible to third parties, you will see a period of only custom events and a blank page in session replay.  Of note, custom events accurately reflect the time and user activity of the payment page.  If the thank you page has the Fullstory snippet added (prior to August 28, 2025), replay will resume showing website content once the user has been redirected to the thank you page. 

The pixel requires the All other domains data capture setting to be On. Fullstory’s capture data by domain feature is unable to identify the pixel’s iframe origin and determine if the domain is allowed.  As a result, all domains must be allowed.

Page variables are not supported.  Because the pixel is contained in an iframe, using FS(‘setProperties’) is not supported.

As a best practice (for both pixel and historical integration), segments and metrics using custom events on the thank you page should add the Entry Page is false criteria.  When users become inactive on the thank you page and later active, Shopify may generate analytics events again.  The Entry Page is false criteria excludes sessions and events that are the result of the user resuming activity on the thank you page after their previous session has ended.

Configure the Fullstory Checkout Extensibility pixel

It’s recommended that most customers use the pixel’s default configuration. For more advanced configuration and customization, please contact support@fullstory.com to inquire about Fullstory Professional Services.

Need to get in touch with us?

The Fullstory Team awaits your every question.

Ask the Community Technical Support