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 (*when available), build conversion funnels, and gain new insights into how your customers navigate your store.
In addition to adding the Fullstory snippet to your theme as described below, you can also send Shopify-provided analytics events to Fullstory. Fullstory provides shop administrators:
- A recommended Order Status page script that reliably sends a data-rich “Order Completed” event.
- 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.
Configuration Steps
2. Adding your data capture snippet to your Order Status page
3. Adding the Fullstory Checkout Extensibility pixel to Shopify
4. Check 'Capture data by domain' settings
5. Configure a Revenue Event (*Optional)
6. Update Page Definitions (*Optional)
Additional Information
Events captured by Fullstory after creating a pixel
Looking for Shopify Events in Fullstory
Known issues with the Fullstory Checkout Extensibility pixel
Timeline of changes made by Shopify
Step 1 - Installation
Method 1 - Add Fullstory snippet to the theme in Shopify
-
- Log in to your Shopify account, and open your admin panel.
- Select “Online Store” under the “Sales Channels” section of the admin panel.
- On the “Themes” section of the panel, click the Actions button in the upper right-hand corner of the page to reveal a dropdown.
- Click “Edit code”.
- Click “theme.liquid” under the “Layout” section.*
- Paste your Fullstory data capture snippet (learn how to find it here) into the <head> of the theme.
* 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.
- Log in to your Shopify account, and open your admin panel.
-
Once the snippet has been added, you can review the steps below for some additional configuration steps to capture analytics events.
Method 2 - Add Fullstory snippet via a Tag Manager
Fullstory's snippet can be added via a Tag Manager, such as GTM, you can find more detailed instructions on how to do this here.
If you have already added the snippet to your site, you can review the steps below to capture analytics events.
The web pixel is designed to send events to the outer page (e.g. collection or product) even if the outer page’s capture is delayed. Once the tag manager loads Fullstory, any events received will be processed at that time.
Step 2 - Adding your data capture snippet to your Order Status page
Updating the Additional Scripts allows Fullstory to resume session capture on the Thank You / Order Status pages but not all Shopify accounts will have access to modify this section.
Method 1 - Additional Scripts option available
Install the additional script by following the Tracking order steps provided by Shopify:
- From your Shopify admin, go to Settings > Checkout.
- 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.
- 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';.
- 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.
Method 2 - If Additional Scripts option not available
If you’ve chosen not to revert Checkout Extensibility, you no longer have the option to add additional scripts to the Thank You page. Follow step 3 to create a pixel which includes a slight adjustment to the code:
window._fs_additional_scripts_snippet = false;
window._fs_use_order_completed = true;
This configuration will ensure that the pixel does not rely on Fullstory capture being loaded as an additional script. It will also rename the checkout_completed event to “Order Completed” so that the products in the Shopify event can be sent to Fullstory. You will find a “Product Purchased” event corresponding to each item listed in products.
Step 3 - Adding the Fullstory Checkout Extensibility pixel to Shopify
Previously, merchants could manually add JavaScript snippets in several places in their online store: in online preferences, in checkout scripts, and in apps. Shopify are moving away from this approach to improve security, so you will now need to manage scripts to track customer events using Shopify's pixel manager instead.
You can create a pixel for Fullstory by following the Add a custom pixel steps provided by Shopify:
- From your Shopify admin, go to Settings > Customer events.
- Click the Add custom pixel button.
- Name the pixel Fullstory Checkout Extension or similar.
- Click the Add pixel button.
- Copy and paste the pixel’s JavaScript code from this article:
Code to use if Additional Scripts option IS available
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);
}
});Code to use if Additional Scripts option IS NOT available
window._fs_org = '<org id>';
window._fs_identify_customer = false;
window._fs_use_order_completed = true;
window._fs_additional_scripts_snippet = false;
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);
}
}); - 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 will typically appear in this format: window._fs_org = 'o-0rGId-na1'; or window._fs_org = 'o-0rGId-eu1'; but may look a bit different for older accounts.
- Click the Save button.
- Activate the pixel by clicking the Connect button.
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.
Step 4 - Check 'Capture data by domain' settings
Go to Settings > Data Capture and Privacy > Data Capture and make sure 'All Other domains' is toggled ON:
This setting is required to allow the web pixel to work, as 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.
Step 5 - Configure a Revenue Event (*Optional)
As the pixel provides a conversion event, admin users on Advanced / Enterprise plans with access to Conversions will be able to configure a revenue event as described here.
Choose the "Order Completed” event and select either total_price_real
or totalPrice_real
as the revenue property.
Step 6 - Update Page Definitions (*Optional)
If you have page rules created in your account looking for visits to a /checkout page, the URL path may look a little different once the pixel is in place because the data comes to Fullstory via the pixel instead of directly from your site.
Once a session comes through create a metric looking for visits to your Checkout page:
You can then group the results by URL Path / Page to see how these results show, you will typically see a URL which includes references to wpm@ / sandbox / web-pixel, which wouldn't be the same URL seen by the end-user.
You can create new rules or edit any existing rules by going to Settings > Data Management > Pages. Wildcards can be used in the URL path but if you would like more guidance you can reach out to support.
Events captured by Fullstory after creating a pixel
Fullstory custom events will now appear throughout session replays shortly after activating the pixel. More specifically, the following custom events have been instrumented:
Any theme page where the Fullstory snippet has been added:
- cart_viewed
- collection_viewed
- product_viewed
- product_added_to_cart
- product_removed_from_cart
- search_submitted
Payments page:
- checkout_started
- checkout_address_info_submitted
- checkout_contact_info_submitted
- checkout_shipping_info_submitted
- payment_info_submitted
- clicked (the value property will be removed to protect user privacy)
- input_changed (the value property will be removed to protect user privacy)
Thank you page (after August 28, 2025):
- checkout_completed renamed to “Order Completed”
Note: 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.
Looking for Shopify Events in Fullstory
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.
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 Checkout (Information, Shipping, and Payment) pages 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 Checkout page. Since the Checkout pages’ content is inaccessible to third parties, you will see a period of only custom events and blank pages in session replay. Of note, custom events accurately reflect the time and user activity of the Checkout pages.
- 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. After August 28, 2025, the thank you page will similarly appear blank (with analytics events still captured).
- Page variables are not supported. Because the pixel is contained in an iframe, using FS(‘setProperties’) is not supported.
- Web pixels only run when visitors have provided the permissions required in the pixel configuration, you can read more about this requirement here - Customer privacy. By default new pixels created will be set to require Marketing and Analytics permissions e.g via a cookie banner - Manage customer privacy settings.
Timeline of changes made by Shopify
Note: Shopify now recommends merchants and third parties upgrade to Checkout Extensibility which is more secure and better performing than the old method of updating scripts within the checkout.liquid file, which is now deprecated.
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 was turned off and is no longer supported.
- The checkout object is deprecated for the Information, Shipping, and Payment pages as of August 13, 2024.
- From January 6, 2025, Shopify will begin auto-upgrading checkouts still using checkout.liquid customizations.
- 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.
FAQs
Why does session replay show blank for the Checkout pages?
With the introduction of Checkout Extensibility, the content of Checkout pages’ is no longer accessible to third parties so Fullstory are not able to recreate end-users actions in session replay for these pages.
Is it possible to determine if users see specific elements on the Checkout pages?
No, at this time element visibility in the viewport is not exposed by Shopify, so you will not be able to track watched elements.
How can we determine if users apply discount codes or gift cards during checkout?
Depending on your configuration either the checkout_completed or “Order Completed” event will have discount code related information. The discountTitles_strs property contains discount code(s) or title(s) of discount(s) as found in Shopify administration. Additionally, the discountApplications_strs property will contain the allocationMethod, targetSelection, targetType, and type values provided by the checkout_completed event. Refer to the Shopify web pixels API for specifics on these properties.
Will Fullstory capture rage clicks, dead clicks, and error clicks on the Checkout pages?
No. these signals are not available on pages such as payment where capture is intentionally limited by Shopify.
Is it possible to determine when customers modify information within fields?
Yes, certain events provided by Shopify (e.g. checkout_contact_info_submitted), will include information provided by the customer. Additionally, input_changed events will indicate where customers enter information into a field; however, the pixel prevents capture of the value entered to limit the possibility of capturing personal or sensitive information. Pixel customization is required to adjust the code in order to capture these values. The format function in the pixel accepts a list of properties that should be removed. Alter the code format(event.data.element, ['value'])) to be format(event.data.element, []) instead.
Will data layer events appear as duplicates in Fullstory after the addition of the pixel?
If instrumented events using Fullstory APIs have names exactly matching those provided by Shopify, this situation is possible. Fullstory’s Enhanced E-commerce integration, however, has similar but different naming (add_product versus Shopify’s product_added_to_cart) and will not duplicate events. If duplicate events do exist, you can either edit the pixel’s code to remove the analytics.subscribe call for the offending event or archive an existing event to prevent it from being used by Fullstory end users. See the Sending custom event data into Fullstory article for details on archiving events.
Can I capture Network errors during Checkout?
Network errors are not included in the standard events that Shopify make available to Fullstory via the pixel. As an alternative, customers could consider implementing server-side events.
Can Shopify Checkout pages be used in Fullstory Heatmaps?
With the introduction of Checkout Extensibility, the content of Checkout pages (Information, Shipping, and Payment) is no longer accessible to third parties, meaning Fullstory cannot recreate session replay for these pages. Since we cannot capture these pages, in turn this means such pages will not work in Heatmaps.
Why do Shopify reports sometimes show higher sales than Fullstory?
Data from Shopify can only be shared with Fullstory if visitors have provided the permissions required in the pixel configuration. By default, new pixels require Marketing and Analytics permissions.
You can filter your Shopify reports to add a filter for "Accepts marketing" as mentioned here. If you're seeing discrepancies of >15% we would recommend you reach out to the support team with the information requested in our help article so we can take a closer look.