Checkout Extension
Checkout Extension
If you use Shopify Plus and have not yet updated to the new "extensible checkout" system, you can use the "Edit Code" feature in your Shopify theme to add the Quikly checkout snippet.
- Create a new snippet called 'quikly.liquid'. Make sure you replace ##REPLACE_WITH_BRAND_ID## with your config key provided by Quikly. You can find the full source of this file below.


- Edit the checkout.liquid file, and add
{% render 'quikly' %}
to include the new snippet. Typically you will want to place this directly above the{{ content_for_layout }}
tag

1<main class="main__content" role="main">2 {% render 'quikly' %}3 {{ content_for_layout }}4</main>
Here is the contents of snippets/quikly.liquid.
1<script type="application/javascript">2 (function (d) {3 if (d.getElementById('quikly-embed-js')) {4 return;5 }6 s = d.createElement("script");7 s.id = 'quikly-embed-js';8 s.src = 'https://pixel.quikly.com/embed/js';9 s.async = true;10 f = d.scripts[0];11 f.parentNode.insertBefore(s, f);12 })(document);13 window.qData || (window.qData = function() {14 (window.qDataLayer = window.qDataLayer || []).push(arguments);15 });16 qData('config', '##REPLACE_WITH_YOUR_BRAND_KEY##');17 try {18 var qCheckoutTemplate = '{% if checkout %}checkout{% else %}{{ template }}{% endif %}';19 if (window.Shopify && window.Shopify.Checkout) {20 if (window.Shopify.Checkout.step === 'thank_you') {21 qCheckoutTemplate = 'thank_you';22 } else if (Shopify.Checkout.isOrderStatusPage) {23 qCheckoutTemplate = 'order_status';24 }25 }26 qData('ui', {27 placements: 'auto',28 platformData: {29 platform: 'shopify',30 template: qCheckoutTemplate,31 }32 });33 } catch (error) {34 console.log(error);35 }3637 var quiklyAppExtension = (function() {38 const Q_SCOPE = 'q_scope';39 function getLastClickedScope(scopes) {40 const scopesArray = [];41 Object.keys(scopes).forEach((key) => {42 scopesArray.push({ [Q_SCOPE]: key, clicked: scopes[key].clicked });43 });4445 // Sort descending by click time46 scopesArray.sort((a, b) => {47 return b.clicked - a.clicked;48 });4950 // First in array has highest click UNIX timestamp === last to be clicked51 return scopesArray[0][Q_SCOPE];52 }5354 function getCookieValue(key) {55 // if cookie is not set do not try to split56 const cookie = document.cookie57 .split("; ")58 .find((row) => row.startsWith(key));59 if (!cookie) {60 return;61 }6263 return cookie.split("=")[1];64 }6566 function notifyQuikly(cart) {67 const evt = new CustomEvent("quikly:cart", {68 detail: {69 cart,70 },71 });7273 window.dispatchEvent(evt);74 }7576 function getBaseUrl(key, defaultUrl) {77 if (window.QuiklyRoutes && window.QuiklyRoutes[key]) {78 return window.QuiklyRoutes[key] + ".js";79 }8081 if (window.Shopify && window.Shopify.routes && window.Shopify.routes.root) {82 return window.Shopify.routes.root + defaultUrl;83 }8485 return defaultUrl;86 }8788 function cartUrl() {89 return getBaseUrl("cart_url", "{{ routes.cart_url | default: 'cart' }}.js");90 }9192 function cartUpdateUrl() {93 return getBaseUrl("cart_update_url", "{{ routes.cart_update_url | default: 'cart/update' }}.js");94 }9596 async function fetchCart() {97 try {98 const response = await fetch(cartUrl());99 return response.json();100 } catch (error) {101 console.error("Error fetching cart:", error);102 throw error;103 }104 }105106 function getCookieScope() {107 const cookieScope = getCookieValue(Q_SCOPE);108 if (cookieScope) {109 const decodedQscopeCookieValue = decodeURIComponent(cookieScope);110 const parsedQscope = JSON.parse(decodedQscopeCookieValue);111 const qscope = getLastClickedScope(parsedQscope);112 return qscope;113 }114 }115116 function fetchConfig(type = "json") {117 return {118 method: "POST",119 headers: {120 "Content-Type": "application/json",121 Accept: `application/${type}`,122 },123 };124 }125126 async function synchronizeCart() {127 let updateCart = false;128 let cart;129 let attributes;130131 try {132 cart = await fetchCart();133 notifyQuikly(cart);134 attributes = cart["attributes"] || {};135136 const cookieQScope = getCookieScope();137 if (cookieQScope && attributes[Q_SCOPE] !== cookieQScope) {138 attributes[Q_SCOPE] = cookieQScope;139 updateCart = true;140 }141142 const receiptTokens = getCookieValue("quikly-order-receipt-tokens");143 if (receiptTokens && attributes["q_tokens"] !== receiptTokens) {144 attributes["q_tokens"] = receiptTokens;145 updateCart = true;146 }147148 if (updateCart) {149 const body = JSON.stringify({ attributes });150151 const fetchResult = await fetch(cartUpdateUrl(), {152 ...fetchConfig(),153 ...{ body },154 });155156 if (!fetchResult.ok) {157 throw new Error(158 `Cart update failed with status ${fetchResult.status}`159 );160 }161162 return fetchResult.json();163 }164 } catch (error) {165 console.error("Error updating cart:", error);166 }167 }168169 async function applyDiscount(code) {170 const res = await fetch(`/checkout?discount=${code}`);171 return res.text();172 }173174 synchronizeCart();175176 return {177 fetchCart: fetchCart,178 applyDiscount: applyDiscount,179 }180 })();181182{% if checkout %}183 (function($) {184 $(document).on("page:change", function() {185 quiklyAppExtension.fetchCart();186 });187 })(Checkout.$);188{% endif %}189</script>190