Skip to content

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.

  1. 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.

create snippet

paste in code

  1. 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

edit checkout.liquid

<main class="main__content" role="main">
{% render 'quikly' %}
{{ content_for_layout }}
</main>

Here is the contents of snippets/quikly.liquid.

<script type="application/javascript">
(function (d) {
if (d.getElementById('quikly-embed-js')) {
return;
}
s = d.createElement("script");
s.id = 'quikly-embed-js';
s.src = 'https://pixel.quikly.com/embed/js';
s.async = true;
f = d.scripts[0];
f.parentNode.insertBefore(s, f);
})(document);
window.qData || (window.qData = function() {
(window.qDataLayer = window.qDataLayer || []).push(arguments);
});
qData('config', '##REPLACE_WITH_YOUR_BRAND_KEY##');
try {
var qCheckoutTemplate = '{% if checkout %}checkout{% else %}{{ template }}{% endif %}';
if (window.Shopify && window.Shopify.Checkout) {
if (window.Shopify.Checkout.step === 'thank_you') {
qCheckoutTemplate = 'thank_you';
} else if (Shopify.Checkout.isOrderStatusPage) {
qCheckoutTemplate = 'order_status';
}
}
qData('ui', {
placements: 'auto',
platformData: {
platform: 'shopify',
template: qCheckoutTemplate,
}
});
} catch (error) {
console.log(error);
}
var quiklyAppExtension = (function() {
const Q_SCOPE = 'q_scope';
function getLastClickedScope(scopes) {
const scopesArray = [];
Object.keys(scopes).forEach((key) => {
scopesArray.push({ [Q_SCOPE]: key, clicked: scopes[key].clicked });
});
// Sort descending by click time
scopesArray.sort((a, b) => {
return b.clicked - a.clicked;
});
// First in array has highest click UNIX timestamp === last to be clicked
return scopesArray[0][Q_SCOPE];
}
function getCookieValue(key) {
// if cookie is not set do not try to split
const cookie = document.cookie
.split("; ")
.find((row) => row.startsWith(key));
if (!cookie) {
return;
}
return cookie.split("=")[1];
}
function notifyQuikly(cart) {
const evt = new CustomEvent("quikly:cart", {
detail: {
cart,
},
});
window.dispatchEvent(evt);
}
function getBaseUrl(key, defaultUrl) {
if (window.QuiklyRoutes && window.QuiklyRoutes[key]) {
return window.QuiklyRoutes[key] + ".js";
}
if (window.Shopify && window.Shopify.routes && window.Shopify.routes.root) {
return window.Shopify.routes.root + defaultUrl;
}
return defaultUrl;
}
function cartUrl() {
return getBaseUrl("cart_url", "{{ routes.cart_url | default: 'cart' }}.js");
}
function cartUpdateUrl() {
return getBaseUrl("cart_update_url", "{{ routes.cart_update_url | default: 'cart/update' }}.js");
}
async function fetchCart() {
try {
const response = await fetch(cartUrl());
return response.json();
} catch (error) {
console.error("Error fetching cart:", error);
throw error;
}
}
function getCookieScope() {
const cookieScope = getCookieValue(Q_SCOPE);
if (cookieScope) {
const decodedQscopeCookieValue = decodeURIComponent(cookieScope);
const parsedQscope = JSON.parse(decodedQscopeCookieValue);
const qscope = getLastClickedScope(parsedQscope);
return qscope;
}
}
function fetchConfig(type = "json") {
return {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: `application/${type}`,
},
};
}
async function synchronizeCart() {
let updateCart = false;
let cart;
let attributes;
try {
cart = await fetchCart();
notifyQuikly(cart);
attributes = cart["attributes"] || {};
const cookieQScope = getCookieScope();
if (cookieQScope && attributes[Q_SCOPE] !== cookieQScope) {
attributes[Q_SCOPE] = cookieQScope;
updateCart = true;
}
const receiptTokens = getCookieValue("quikly-order-receipt-tokens");
if (receiptTokens && attributes["q_tokens"] !== receiptTokens) {
attributes["q_tokens"] = receiptTokens;
updateCart = true;
}
if (updateCart) {
const body = JSON.stringify({ attributes });
const fetchResult = await fetch(cartUpdateUrl(), {
...fetchConfig(),
...{ body },
});
if (!fetchResult.ok) {
throw new Error(
`Cart update failed with status ${fetchResult.status}`
);
}
return fetchResult.json();
}
} catch (error) {
console.error("Error updating cart:", error);
}
}
async function applyDiscount(code) {
const res = await fetch(`/checkout?discount=${code}`);
return res.text();
}
synchronizeCart();
return {
fetchCart: fetchCart,
applyDiscount: applyDiscount,
}
})();
{% if checkout %}
(function($) {
$(document).on("page:change", function() {
quiklyAppExtension.fetchCart();
});
})(Checkout.$);
{% endif %}
</script>