To activate Arrow on a Shopify store follow all these steps. Before you start, make sure you have a seller account with Arrow to get the Arrow API keys and API url.

After this setup is complete, you’ll have added Shopify credentials on Arrow ( passed them to the dev team ). This is needed for Arrow to connect to the seller’s Shopify store.

To complete Arrow account setup you need help from the dev team ( Sudhan ), so check in with them when onboarding a seller.

1. Enable Custom Apps

To add Arrow as a ‘custom app’, you need to enable custom app development. Only the store owner can enable custom app development.


  1. From your Shopify admin, go to Apps.
  2. Click Develop apps.
  3. Click Allow custom app development.
  4. Read the warning and information provided, and then click Allow custom app development.

2. Create a Custom App

Now that you’ve enabled custom app development you can create a custom app.

  1. Click on Apps on the menu on the left side of the screen

  2. Select the “Develop apps” button on the top right corner of the app to get started.

  1. In the next window click "Create an App" on the top right corner and in the popup enter “Arrow Checkout” as App name and "[email protected]" as App developer

3. Configure Settings for the Arrow App

Now that you’ve created an app you have define the app access scopes (both Admin API and Storefront API)

Click configure next to “Admin API Integration” section to set the following properties and click save:

Field Name Access Setting
Analytics Read Access
Assigned fulfillment orders Read and Write
Customers (Must) Read and Write
Discounts (Must) Read and Write
Draft Orders (Must) Read and Write
Fulfillment Services Read and Write
GDPR Data Requests Read Access
Gift Cards Read and Write
Inventory (Must) Read and Write
Kit Skills Read and Write
Legal Policies Read and Write
Locations Read Access
Marketing Events Read and Write
Merchant Managed Fulfilment Orders Read and Write
Online Store Pages Read and Write
Order Editing (Must) Read and Write
Orders (Must) Read and Write
Price Rules (Must) Read and Write
Products (Must) Read and Write
Reports Read and Write
Resource Feedback Read and Write
Script Tags Read and Write
Shipping (Must) Read and Write
Shop Locale Read and Write
Shopify Payment Accounts Read Access
Shopify Payments Bank Accounts Read Access
Shopify Payments Disputes Read Access
Shopify Payments Payouts Read Access
Store Content Read and Write
Themes (Must) Read and Write
Third Party Fulfilment Orders Read and Write
Translations Read and Write

To enable Arrow checkouts to complete orders, enable the ‘Storefront’ API by clicking configure on the " Storefront API integration" section:

And under “Storefront API Permissions”, enable the following boxes:

  • Checkout (required)
    • unauthenticated_write_checkouts
    • unauthenticated_read_checkouts
  • Customers (required)
    • unauthenticated_write_customers
    • unauthenticated_read_customers
    • unauthenticated_read_customer_tags
  • Products (required)
    • unauthenticated_read_product_listings
    • unauthenticated_read_product_inventory
    • unauthenticated_read_product_pickup_locations
    • unauthenticated_read_product_tags
  • Selling plans
    • unauthenticated_read_selling_plans

Make sure to press “Save” at the bottom or top of the page after completing these steps.

4. Get the Admin API Access Token and Storefront API Access Token and add it to Arrow

The Shopify API key is needed to get shipping rates in Arrow checkout. This is a required step, without it Arrow checkout will not work.

Get the Admin API Access Token and Storefront API Access Token

On your Arrow private app page, in the ‘Admin API’ section copy and save the Shopify Admin API Access Token and Storefront API Access Token into a safe place like a password manager. The API Key is needed for Arrow to connect with this Shopify store.

Get the Store ID

Copy the Shopify Store ID from your admin’s browser address bar, that is


Also copy your Store ID which is in the browser address bar when on the Shopify portal.

Share the Admin API Access Token, Storefront API Access Token and Store ID with the dev team to add them to the sellers account in Arrow. This is needed for Arrow to make requests to the Shopify API.

It is not necessary to share the API Key with Arrow anymore.

5. Add Arrow.js to the Shop Checkout Page

To make sure the Arrow checkout button can appear the arrow.js client library and an encryption library need to be added to the checkout pages. This is done by modifying the Shopify theme.

Modify a Theme

In the left menu under “Sales Channel” -> My Store, select “Themes”. Then, on the section “Current Theme” in the Actions dropdown select “edit code”. This will take you to an editor where the shopify code can be updated:

When on the “Edit Code” page, open the file “theme.liquid”:

Within the <head> tag add these script tags before the closing </head> tag:

Note: Make sure to replace {{your arrow client key}} with the Arrow client key for this store.

<script src="//"></script>
<script type="text/javascript" src=""></script>
        clientKey: "your arrow client key"

  var clientId = 0;
  ga(function(tracker) {
     clientId = tracker.get('clientId');

  function getCookie(cname) {
    let fbp = document.cookie.split(';').filter(c => c.includes('_fbp=')).map(c => c.split('_fbp=')[1]);
    let fbc = document.cookie.split(';').filter(c => c.includes('_fbc=')).map(c => c.split('_fbc=')[1]);
    fbp = (fbp.length && fbp[0]) || undefined;
    fbc = (fbc.length && fbc[0]) || undefined;

    if(!fbc &&'fbclid=')){
      fbc = 'fb.1.'+ (+new Date()) +'.'+'fbclid=')[1];
    if (cname == "_fbp") {
      return fbp
    } else if (cname == "_fbc") {
      return fbc

function arrow_checkout_clicked() { 
  .then(response => response.json()) 
  .then(data => {  
    var fbp = getCookie('_fbp');
    var fbc = getCookie('_fbc');
    var cartAll = data.items; 
      var cpAmt = 0;
      var customCart = window.currentCart != undefined ? window.currentCart : [];
      for (i = 0; i < cartAll.length; i++) {
        var curOptions = "";
        if (cartAll[i].variant_options != undefined){
          for (j = 0; j < cartAll[i].variant_options.length; j++) {
            curOptions += cartAll[i].variant_options[j];
            if (j < cartAll[i].variant_options.length - 1){
              curOptions += " , ";
        if (customCart.items != undefined && customCart.items.length) {
          for (j = 0; j < customCart.items.length; j++) {
            if (cartAll[i].variant_id == customCart.items[j].variant_id) {
              cpAmt += customCart.items[j].discount;
            name : cartAll[i].title,
            quantity : cartAll[i].quantity,
            image: cartAll[i].image,
            description : cartAll[i].product_description,
            option : curOptions,
            extraData : {"variant_id":cartAll[i].variant_id}
      if (customCart.items != undefined && customCart.items.length) {
        for (k = 0; k < customCart.items.length; k++) {
          cpAmt += customCart.items[k].discount;
              name: "",
              quantity : customCart.items[k].quantity,
              option : "",
              extraData : {"variant_id":customCart.items[k].variant_id}
      if (cpAmt > 0) { = {"amount" : cpAmt}
      arrowOrder.shipping =[
      var deliveryTime = $("input[name^='attributes[Delivery Time']").attr("name");
      var deliveryDateVal = $("input[name='attributes[Delivery Date]']").val();
      var deliveryTimeVal = $("input[name^='attributes[Delivery Time']").val();
      var deliveryDayVal = $("input[name='attributes[Delivery Day]']").val();
      var note_attributes = {};

      if (deliveryTime != undefined) {
        //var matches = deliveryTime.match(/(?<=\[)[^\][]*(?=])/g);
        var matches = deliveryTime.match(/(\[(?:\[jQuery3210290589496665961_1645086608211[^\[]*?\]))/g);

        if (matches.length > 0) {
          var raw = matches[0].replace(/^\[(.+)\]$/,'$1')
          note_attributes[raw] = deliveryTimeVal;
      if (deliveryDateVal != undefined){
        note_attributes['Delivery Date'] = deliveryDateVal;
      if (deliveryTimeVal != undefined){
        note_attributes['Delivery Time'] = deliveryTimeVal;
      if (deliveryDayVal != undefined){
        note_attributes['Delivery Day'] = deliveryDayVal;
      var notes = $("textarea[name='note']").val();

      arrowOrder.extraData = {};    

      if (note_attributes != {}){
        arrowOrder.extraData['note_attributes'] = note_attributes; 
      if (notes != undefined){
        arrowOrder.extraData['notes'] = notes; 
      arrowOrder.redirect = {
        "success" : window.location.origin + "/pages/order-successful",
        "fail" : window.location.origin,
        "cancel" : window.location.origin + "/cart"
//       if (!!window.bndlr) {
//         window.bndlr.getCheckoutInfo(
//           function(data) {
//             console.log(data);
//             arrowOrder.promocode = data.code;
//             console.log(arrowOrder);
//             launchArrowShopify();
//           }
//         );
//       } else {
//         launchArrowShopify();  
//       }
      if (document.getElementsByClassName("cpn_dcnt_price")[1] != undefined) {
        arrowOrder.promocode = document.getElementsByClassName("cpn_dcnt_price")[1].childNodes[0].innerText;
      arrowOrder.currency = {
        "base_currency": "IDR",
        "currency_symbol": "Rp"
      arrowOrder.extraData['locale'] = "id"; 

      if(fbp !== undefined){
        arrowOrder.extraData['fbp'] = fbp; 

      if(fbc !== undefined){
        arrowOrder.extraData['fbc'] = fbc; 
      arrowOrder.extraData['event_source_url'] = "INSERT REFERRING URL HERE (CART OR PRODUCT PAGE)"; 
      if (clientId != 0){
        arrowOrder.extraData['clientId'] = clientId;
//       console.log(fbc);
//       console.log(fbp);


      const open =;

      function openReplacement() {
        this.addEventListener("load", function () {
          if (
          ) {
            cartJS = JSON.parse(this.response);
        return open.apply(this, arguments);
      } = openReplacement;

      (function(ns, fetch) {
          if (typeof fetch !== 'function') return;

          ns.fetch = function() {
              const response = fetch.apply(this, arguments);

              response.then(res => {
                  if ([
                      ].includes(res.url)) {
                      res.clone().json().then(data => cartJS = data);

              return response;

      }(window, window.fetch))


If you are setting up Arrow via Arrow QA environment you have to replace this script:

<script type="text/javascript" src=""></script>

with the snippet below:

    const arrowHost = "";
    const arrowAPI = "";
<script type="text/javascript" src=""></script>


Note: weight: cartAll[i].grams / 1000, is only needed if your product has weight data.

Press ‘Save’ in the upper right corner to save these changes.
Note, jquery is mandatory if your site doesn’t have jquery installed yet. If you’re not sure, please reach out to the dev team.

At times, we need to add the Shopify GET cart ajax call when calling arrow_checkout_clicked() to ensure we get the cart’s items.

function arrow_checkout_clicked() { 
  .then(response => response.json()) 
  .then(data => {  
    var cartAll = data.items; 

Lastly if we want to enable language of the checkout to be localised (for now we only offer localisation to Bahasa Indonesia) you have to add this code snippet after "arrowOrder.extraData" has been defined in the function:

 arrowOrder.extraData['locale'] = "id";

6. Handle Successful or Cancelled Handlers

To help shoppers see the result of their checkout on this store we add these handlers to direct them to the right page after their checkout on Arrow is completed or cancelled.

In the ‘theme.liquid’ file in the ‘Layout’ folder, add the following script within the <body> tag:

    var checkoutWindow;
    function checkout_cancel() {
      window.location.href = window.location.origin + "/cart";
    function checkout_success() {
      window.location.href = window.location.origin + "/pages/order-successful";
    window.addEventListener("message", function(event) {
      var data =;
      if (data && data.message) {
        if (data.message == "checkout_success") {
        } else if (data.message == "checkout_cancel") {
    var cartJS = {{cart | json }};

7. Add the Arrow Checkout button on the cart page

After loading the required Arrow.js in the Shopify theme, it’s possible to add the Arrow checkout button on the cart page.

To enable Arrow checkout on the cart page we want to load the checkout button. The Arrow checkout button can be added in different areas of the Shopify code, and the code may look different depending on what Shopify theme is installed on your website.

To customise the Shopify cart page, while still in the code editor for your theme, in the “Sections” folder, open the file “cart-template.liquid”. The following is the code for the Arrow Checkout button:

<div class="arrow-checkout-block" data-brand-fpx=false data-brand-cimb=false data-brand-maybank=false></div>

This code will create a button that looks like this:

Deciding where you want the Arrow Checkout button to be positioned is up to you.

We strongly recommend that you locate the existing checkout button on the cart page, and position it just above it. To locate, look for a button with the value being “'cart.general.checkout'”.

Styling might need adjustment according to your site theme.

Again press ‘Save’ in the upper right corner to save these changes to the ‘cart-template.liquid’ file.

Lastly, here are the possible data value for arrow-checkout-block:


Default = none

If set to "product" it will call the function buy() instead of arrow_checkout_clicked()


Default = true

values = "true"/"false"

Show/Hide learn more button below the checkout


Default = true

values = "true"/"false"

Show/Hide Visa Branding


Default = true

values = "true"/"false"

Show/Hide Mastercard Branding


Default = true

values = "true"/"false"

Show/Hide Paynow Branding


Default = true

values = "true"/"false"

Show/Hide JCB Branding


Default = true

values = "true"/"false"

Show/Hide Union Branding


Default = true

values = "true"/"false"

Show/Hide American express Branding


Default = true

values = "true"/"false"

Show/Hide FPX Branding


Default = true

values = "true"/"false"

Show/Hide CIMB Branding


Default = true

values = "true"/"false"

Show/Hide Maybank Branding

Mini cart / Side cart (optional):

If you have a side cart / mini cart, you can add the same code to the section. Side/mini cart code is usually located under “Snippet”, with file title containing “cart” (e.g. mini-cart.liquid). \

<div class="arrow-checkout-block"></div>

Extra notes

  • At times, mini cart is only rendered when it is toggled to open, and therefore the initial arrowInit() function called would not have the opportunity to attach the CSS and JS code to arrow-checkout-block inserted in mini cart. We would need to re-trigger the arrowInit() function after the mini cart is properly rendered in such a situation.
  • When there are additional CSS treatment to be done on the checkout button, you can leverage on the data-scripts label to call a custom function upon completing of button load. Example:
function arrow_add_css() {
      var arrowElement = document.getElementsByClassName('reset-this arrow-f arrow-fc arrow-jsb')[0];["margin-left"] = "auto";["margin-right"] = "0"

<div class="arrow-checkout-block" data-scripts="arrow_add_css()"></div>

8. Configuring an SKU Button

Follow these steps to have an SKU button, note that the configuration for the button is dependent on your store’s theme on Shopify. These steps can be followed exactly when using the Basic Theme.

First, navigate to the “product-template.liquid” file under the Section folder and locate the position of the “Add to Cart” button code. (at times, the file is a custom snippet that is nested within the product-template.liquid file).

Sometimes the buy button is in a different file so you can download the entire theme file and search it using your editor of choice (e.g. sublime text).

After this line, add the following code snippet (Note the additional data-type=”product” needed, which will call the buy() function instead of arrow_checkout_clicked())

<div class="arrow-checkout-block" data-type="product" data-brand-fpx=false data-brand-cimb=false data-brand-maybank=false></div>

After completing this step, you will need to add another code snippet at the very end of the same “product-template.liquid” file. This code snippet can be added on the most bottom of the page, at line 775 or below if there is code already on this line.

The code snippet that should be added at this point is as follows:

<!--  Arrow Checkout For Product Page-->
 function buy() {
   var product = {{ product | json }};
   var cur_quantity = document.querySelector('#Quantity').value;
   var variant1 = "";
   var opt1 = document.querySelector('#ProductSelect-product-template-option-0');
   if (opt1 != null) {
     variant1 = opt1.value;
   var variant2 = "";
   var opt2 = document.querySelector('#ProductSelect-product-template-option-1');
   if (opt2 != null) {
     variant2 = opt2.value;
   var variant3 = "";
   var opt3 = document.querySelector('#ProductSelect-product-template-option-2');
   if (opt3 != null) {
     variant3 = opt3.value;
   var variant_title = variant1;
   if (variant2 != "") {
     variant_title += " / " + variant2;
   if (variant3 != "") {
     variant_title += " / " + variant3;
   var product_variants = product.variants;
   var variant_id = 0;
   var weight = 0;
   var image = null;
   for(var i=0;i < product_variants.length;i++) {
     if (product_variants[i].title == variant_title){
       variant_id = product_variants[i].id;
       weight = product_variants[i].weight;
       image = product_variants[i].featured_image;
   if (!!image) {
        image = image.src;
   } else {
        image = "https:" + product.images[0];
   if (variant_id == 0){
     variant_id = product.variants[0].id;
     variant_title = product.variants[0].title;
     weight = product.variants[0].weight;
       name : product.title,
       quantity : cur_quantity,
       image: image,
       weight: weight / 1000,
       description : product.description,
       option : variant_title,
       extraData : {"variant_id":variant_id, properties:}
   arrowOrder.shipping =[
   arrowOrder.extraData = {
     "cart_id": 1
   arrowOrder.redirect = {
     "success" : window.location.origin + "/pages/order-successful",
     "fail" : document.location.href,
     "cancel" : document.location.href

Note: weight: weight / 1000, is only needed if your product has weight data.

If you are using a custom theme, you will need to make a slight change in the above code since custom themes have different configurations.

Within the “buy” function we have given above that you would have copied, there is a section towards the bottom reading:

       name : product.title,
       quantity : cur_quantity,
       image: image,
       weight: weight / 1000,
       description : product.description,
       option : variant_title,
       extraData : {"variant_id":variant_id,}

When using a custom theme, you will need to build this exact data depending on the custom theme you are using as custom themes may have different names, different selectors, etc. Therefore, these fields will need to be adapted to fit your custom theme’s configurations.

Technical note for fetching variant and quantity data:

You can look for product quantity by fetching quantity spinner / dropdown value, for example:



You can look for product variants by looking at theme.js or theme.js.liquid file, and then look for variant change triggers. On variant trigger, pass the selected variant data to product-template.json code.
You can pass quantity data from theme.js or theme.js.liquid file also, if querySelector doesn’t fetch updated quantity. Look for product quantity triggers and pass the updated quantity to product-template.json code

For using jQuery to select the existing selected value from a <select> tag:

var opt1 = $("select#SingleOptionSelector-0").children("option:selected").val();

Another example of fetching variant value, where options are provided in a list, and the currently selected one having assigned an active class:

var opt1 = document.getElementsByClassName('lh-swatch-select lh-exists active')[0];
if (!!opt1) {
   variant1 = opt1.dataset.value;

Another way to fetch the right variant if the other methods fail is fetch the variant id from the back of the URL using the following function and inserting it into product.liquid

 function getQueryParam(name) {
    var q = RegExp('[?&]' + name + '=([^&#]*)'));
    return q && q[1];

For handling sold out buttons and hide Arrow checkout button:

You can go to theme.js.liquid file, and look for _updateAddToCart function (look for “updateAddToCart”, as sometimes it could be slightly different, such as “_updateAddToCartButton”)

Assign the product page Arrow checkout block a special ID, and use show() or hide():

to show and hide the Arrow checkout button according to the case. \

At times, we ought to try looking for the SKU-change function in theme.js/theme.js.liquid, passing it an arrowVariant variable so that we can just conveniently obtain the right variant that is being selected when the buy() function is triggered.

For example, the currently selected variant might be initialised under the function ​​_getVariantFromOptions(), with any changes in selection made by user triggered under function _onSelectChange.

9. Add the Successful Order Page

To redirect shoppers to the page that shows their order is successful we need to create that page as a template.

Add the template

In the “Templates” folder create a new template by clicking the “Add a new template” link at the top of the list. Select “page” and select “liquid” as template type and give it the name “checkout-success”. (ie. page.checkout-success.liquid)

On the first line of the new template, add the new script:

    $(window).on('load', function () {
         type: "POST",
         url: '/cart/clear.js',
         success: function(){ window.location.replace(window.location.origin + "/pages/thanks-for-your-order");  },
         dataType: 'json' });

Once added the template should look like this:

After adding the text press “Save” to save the new page.

Add the page

Once the template has been made, we need to create two new pages that the user will land in. To do so go to “Pages” in the left menu under.

This will redirect you to a page that will be empty if you have not created any new pages, if this is the case you can create a new page by selecting the “Add page” button.

However, if you have created new pages before, select the “Add page” button on the top right.

This will redirect you to a set of fields that need to be filled. For the first page we are only going to make two changes. We will set the Title to “Thanks For Your Order” and then set the Content to “Your purchase will be delivered soon. Thank You!” The page should look like this:

After adding the text press “Save” to save the new page.

When you return to the “Pages” site, select the “Add page” button to create the second new page. This time, we will be making a few more changes. For this page, set the Title to “Order Successful” and set the Content to “Thank you for your order!” The additional change we will make for this page is: in the right menu go to “select a template for this page” and select the template you just created -> “checkout-success” from the dropdown. This page will clear the customer cart after the order is confirmed. The page should look like this (Note the Template section in the right menu is now set to checkout-success):

Press “Save” to save this new page as well.

Remember that only the “Order Successful” page should have the template changed. Not both pages.

10. Connect Arrow with Webhooks

To help Shopify connect with Arrow, events need to be sent between both platforms.

That gets payment confirmations across and makes sure orders are confirmed when payments complete.

In the left menu on the shopify go to Settings, in Settings go to the Notifications menu.

In the Notifications menu, scroll down to the Webhooks section.

In the Webhooks section, select ‘Create Webhook’ to create a webhook.

In the url enter:{{ your client key }} 

Note: If installation is performed for production usage, endpoint would be{{ your client key }} instead

Replace {{your client key}} with the Arrow API client key.

Select ‘2021-01’ for API version, and ‘JSON’ for format

Do the same for the following events, and use the same URL for each:

Order creation

Order fulfillment

“Order Cancellation

Refund create

You should now have 4 webhooks configured for:

  • Order cancellation
  • Order creation
  • Order fulfillment
  • Refund create


Congratulations, with these steps you have now added Arrow One Click Checkout for your Shopify Store.

To verify that everything is working, try checking out on your store with Arrow.

Make sure you see the ‘Checkout with Arrow’ button appear. If you have items in your cart try checking out by clicking Arrow and completing an order.

💬 We're here to help!

If anything is not right, double check if everything is configured as in this guide, if it is, reach out to Arrow support to get help with your setup ( [email protected] )