-
-
Save samba/3a6c901fac1459eda80d58388c996d40 to your computer and use it in GitHub Desktop.
{% if first_time_accessed %} | |
<script> | |
(function(dataLayer){ | |
var customer_type = ({{customer.orders_count}} > 1) ? 'repeatcustomer' : 'newcustomer'; | |
var discounts = "{{ order.discounts | map: 'code' | join: ',' | upcase}}"; | |
function strip(text){ | |
return text.replace(/\s+/, ' ').replace(/^\s+/, '').replace(/\s+$/, ''); | |
} | |
function firstof(){ | |
for(var i = 0; i < arguments.length; i++){ | |
if(arguments[i]) return arguments[i]; | |
} | |
return null; | |
} | |
var products = []; | |
{% for line_item in order.line_items %} | |
products.push({ | |
'id': firstof(strip('{{line_item.sku}}'), strip('{{line_item.product_id}}')), | |
'name': strip('{{line_item.product.title}}'), | |
'category': strip('{{line_item.product.type}}'), | |
'brand': strip('{{line_item.vendor}}'), | |
'variant': strip('{{line_item.variant.title}}'), | |
'coupon': "{{ line_item.discounts | map : 'code' | join: ',' | upcase}}", | |
'price': {{line_item.price | times: 0.01}}, | |
'quantity': {{line_item.quantity}} | |
}); | |
{% endfor %} | |
dataLayer.push({ | |
'event': 'checkoutComplete', | |
'customerType': customer_type, | |
'ecommerce': { | |
'currencyCode': '{{shop.currency}}', | |
'purchase': { | |
'actionField': { | |
'id': '{{order.order_number}}', | |
'affiliation': strip('Shopify {{shop.name}}'), | |
'revenue': {{order.total_price | times: 0.01}}, | |
'tax': {{order.tax_price | times: 0.01}}, | |
'shipping': {{order.shipping_price | times: 0.01}}, | |
'coupon': discounts | |
}, | |
'products': products | |
} | |
} | |
}); | |
setTimeout(function(){ | |
// Clear the ecommerce data for subsequent hits. | |
dataLayer.push({ 'ecommerce': null }); | |
}, 3); | |
}(window.dataLayer = window.dataLayer || [])); | |
</script> | |
{% endif %} | |
<script> | |
function containsGTMStart(dl){ | |
var i = 0; | |
dl.map(function(e){ if('gtm.start' in e) i++; }); | |
return !!i; | |
} | |
(function(w,d,s,l,i){ | |
w[l]=w[l]||[]; | |
// attempts to prevent GTM from loading twice. | |
if(containsGTMStart(w[l])) return false; | |
w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'}); | |
var f=d.getElementsByTagName(s)[0], | |
j=d.createElement(s), | |
dl=l!='dataLayer'?'&l='+l:''; | |
j.async=true; | |
j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl; | |
f.parentNode.insertBefore(j,f); | |
})(window,document,'script','dataLayer','GTM-XXXXX'); | |
</script> |
Found the reason. It seems that shopify has changed the order object a bit. On some payment methods the order object will not be present at the first view of the order detail page. If this happens the order object will be nil. Therefore the entire script fails. The solution is to use the checkout object variables instead:
{% if first_time_accessed %} <script> (function(dataLayer){ var customer_type = ((Number({{customer.orders_count}}) || 0) > 1) ? 'repeatcustomer' : 'newcustomer'; var discounts = "{{ order.discounts | map: 'code' | join: ',' | upcase}}"; function strip(text){ return text.replace(/\s+/, ' ').replace(/^\s+/, '').replace(/\s+$/, ''); } function firstof(){ for(var i = 0; i < arguments.length; i++){ if(arguments[i]) return arguments[i]; } return null; } var products = []; {% for line_item in line_items %} products.push({ 'item_id': firstof(strip('{{line_item.sku}}'), strip('{{line_item.product_id}}')), 'item_name': strip('{{line_item.product.title}}'), 'item_category': strip('{{line_item.product.type}}'), 'item_brand': strip('{{line_item.vendor}}'), 'item_variant': strip('{{line_item.variant.title}}'), 'coupon': "{{ line_item.discounts | map : 'code' | join: ',' | upcase}}", 'price': {{line_item.price | times: 0.01}}, 'quantity': {{line_item.quantity}} }); {% endfor %} dataLayer.push({ 'event': 'checkoutComplete', 'customerType': customer_type, 'ecommerce': { 'currencyCode': '{{currency}}', 'purchase': { 'actionField': { 'id': '{{order_number}}', 'affiliation': strip('Shopify {{shop.name}}'), 'revenue': {{total_price | times: 0.01}}, 'tax': {{tax_price | times: 0.01}}, 'shipping': {{shipping_price | times: 0.01}}, 'coupon': discounts }, 'products': products } } }); setTimeout(function(){ // Clear the ecommerce data for subsequent hits. dataLayer.push({ 'ecommerce': null }); }, 3); }(window.dataLayer = window.dataLayer || [])); </script> {% endif %} <script> function containsGTMStart(dl){ var i = 0; dl.map(function(e){ if('gtm.start' in e) i++; }); return !!i; } (function(w,d,s,l,i){ w[l]=w[l]||[]; // attempts to prevent GTM from loading twice. if(containsGTMStart(w[l])) return false; w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'}); var f=d.getElementsByTagName(s)[0], j=d.createElement(s), dl=l!='dataLayer'?'&l='+l:''; j.async=true; j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl; f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-XXXXXXX'); </script>
Hi @chr1s1 does this script working for you ? because I had same issue since September
Yes, the adapted script from my comment above works. It is not referencing the order object, but uses the accessible checkout variables directly.
Yes, the adapted script from my comment above works. It is not referencing the order object, but uses the accessible checkout variables directly.
Thanks will give it a try 👍
Hey,
Could you explain what
| times: 0.01
does?
Thanks a lot for the code!
IIRC the "price" attribute is (by default) an integer representing cents so representing it as (floating point) dollars requires dividing it by 100; it was here implemented as multiplying by 0.01. This gets you better currency representation in GTM that is intuitively sensible. Hope that helps!
@samba I am have setup code but still getting the error. order_number is null.
Note:
I believe this depends on checkout.liquid
. Unfortunately, checkout.liquid
will be deprecated on August 13, 2024 and store owners will need to upgrade to Checkout Extensibility before then.
After upgrading, you will no longer have access or be able to edit the checkout.liquid
file.
Reference: https://shopify.dev/docs/themes/architecture/layouts/checkout-liquid
To add customer events via GTM, refer to this page https://help.shopify.com/en/manual/promoting-marketing/pixels/custom-pixels/gtm-tutorial
Web Pixels Overview: https://help.shopify.com/en/manual/promoting-marketing/pixels/overview
Note: I believe this depends on
checkout.liquid
. Unfortunately,checkout.liquid
will be deprecated on August 13, 2024 and store owners will need to upgrade to Checkout Extensibility before then.After upgrading, you will no longer have access or be able to edit the
checkout.liquid
file.Reference: https://shopify.dev/docs/themes/architecture/layouts/checkout-liquid
To add customer events via GTM, refer to this page https://help.shopify.com/en/manual/promoting-marketing/pixels/custom-pixels/gtm-tutorial
Web Pixels Overview: https://help.shopify.com/en/manual/promoting-marketing/pixels/overview
I am not editing the checkout.liquid to run the script.
Hi @chr1s1
You've got some good code here. I read your instructions above regarding where to add the code.
Unfortunately, the Order Processing -> Additional Scripts input textarea is gone.
There are now two "Additional Scripts" areas.
One is under Post-purchase page section.
The second is under Order status page section.
With checkout extensibility, the entire checkout process is sandboxed. You're only able to push customer events data once you've completed your checkout and arrive at the order status page.
Your script would be added to the Order status page section > Additional Scripts.
Correct?
Hi @chr1s1
Instead of CustomerType: NewCustomer
Is it possible to use a boolean:
New customer: false
Depending on the {{customer.orders_count}} ?
As in: if {{customer.orders_count}} is greater than 0, newcustomer: false
if {{customer.orders_count}} equals 0, newcustomer: true
Has Anyone tried this?
Thank you very much and kind regards
@umuthan You can copy & paste the script from my article here: https://www.owntag.eu/blog/shopify-checkout-datalayer/
It's written specifically to work with Checkout Extensibility and follows the GA4-style standard dataLayer so that most tags in Google Tag Manager will work out of the box with it.
now that it works again, that might be a great solution! 😊