# Integration Guide

This part of the documentation will guide you through the steps of integrating your e-commerce site with SIW. We'll go through patterns for embedding the shipping selector, handle updates to cart or customer information and marking the checkout session as completed in SIW API.

# Creating a session

The first thing you need to do before you can embed the shipping selector in your checkout page is to create a session. This is done by calling session.create which returns session details and generated HTML snippet.

Each Session has an ID that can be used to later fetch, update or complete the session. It is recommended that you store the session id together with the customer's order.

# Embed the shipping selector

The responses of session.create and session.get contain the attribute called html_snippet which includes the html snippet to display the shipping selector in your checkout page. Just put it in the part of the page where you want the shipping selector to be displayed.

<html>
  <head></head>
  <body>
    <div id="cart">
      ...
    </div>

    <div id="shipping">
      {{{ html_snippet }}}
    </div>

    <div id="payment">
      ...
    </div>
  </body>
</html>

Caveats

The HTML snippet is designed to only be added to the page once. So if you are using AJAX to load the snippet you should make sure that this only happens once. Adding or replacing it multiple times will cause the bootstrapping of the widget to run multiple time causing multiple event handlers to be registered.

Also, if you are using AJAX fetch and insert the HTML snippet in the DOM you might experience issues with the script tags not executing. Using jQuery's append() function can mitigate this or you can use the script below to clone the script tag to make it execute.

function replaceScriptNode(node) {
  if (isScriptNode(node) && !isExternalScript(node)) {
    node.parentNode.replaceChild(cloneScriptNode(node), node);
  } else {
    var i = 0,
      children = node.childNodes;
    while (i < children.length) {
      replaceScriptNode(children[i++]);
    }
  }
  return node;
}

function isScriptNode(node) {
  return node.tagName === "SCRIPT";
}

function isExternalScript(node) {
  return !!node.src && node.src !== "";
}

function cloneScriptNode(node) {
  var script = document.createElement("script");
  script.text = node.innerHTML;
  for (var i = node.attributes.length - 1; i >= 0; i--) {
    script.setAttribute(node.attributes[i].name, node.attributes[i].value);
  }
  return script;
}

replaceScriptNode(document.getElementById("shipwallet-container"));

# Handling abandoned carts

In some cases customers can drop out of the checkout process early. Either because they didn't have time to complete the purchase or they went on to continue shopping on the page or for some other reason. In cases like this, when the customer returns, we want them to continue where they left off.

By storing the session ID together with the cart, as mentioned earlier, we can reuse the previously created SIW session. We can updated the cart using session.update and then fetch the session using session.get.

Note

If, for some reason, the session cannot be found when you try to call session.update or session.get with a previous session ID we suggest that you handle this error in this case by creating an entirely new session.

# Updating cart and customer information

It is common for a checkout page to contain customer interactions that can alter the customer's cart or contact information. Two parts that are used by the shipping selector to display the correct shipping options for a customer. Maybe a customer can login on your checkout page, or maybe they add or remove items from their cart.

In these cases you must use the session.update call to update the session with the new information. However, it is important that you use the JavaScript API to suspend and resume the shipping selector while you update the session otherwise the changes won't be reflected.

function updateCart() {
  // suspend shipping selector
  window._sw(function(api) {
    api.suspend();
  });

  // update cart via the backend.
  $.postJSON("url", data, function(response) {
    // resume shipping selector when done.
    window._sw(function(api) {
      api.resume();
      // Shipping selector will now refresh itself
    });
  });
}

# Suspending and resuming shipping selector

The JavaScript API can be used for responding to events in the shipping selector triggered by the customer or for refreshing the session state.

Suspend and resume are both used when a merchant makes changes to the Session in the backend and that needs to be propagated down to the shipping selector.

Note

You should not put the shipping selector in suspend mode when the user changes the shipping option, because in that case the shipping selector is master, eg the provider of data. The only time you should put the widget in suspend mode is when there are updates to the Session, such as cart, voucher or customer updates, because those changes can affect the shipping options and refresh is needed to reflect the changes.

# JavaScript Events

If you want to respond to changes in the shipping selector made by the customer you can subscribe to a number of different events.

# Events

If you want to respond to changes in the widget made by the customer you can subscribe to a number of different events.

# address_changed

window._sw(function(api) {
  api.on("address_changed", function(address) {
    console.log("address updated: ", address);
    // { postal_code: "11733", country: "SE" }
  });
});

# shipping_option_changed

window._sw(function(api) {
  api.on("shipping_option_changed", function(option) {
    console.log("option changed: ", option);
    // { price: 1000, currency: "SEK" }
  });
});

# loaded

window._sw(function(api) {
  api.on("loaded", function() {
    console.log("loaded");
  });
});

# Embedding with React

interface Props {
  // html_snippet from SIW response
  htmlSnippet: string;
}

export class IngridWidget extends React.Component<Props> {
  componentDidMount() {
    const { htmlSnippet } = this.props;
    const element = document.createElement("div");
    element.innerHTML = htmlSnippet;
    const wrapper = document.getElementById("widget-wrapper");
    if (wrapper) {
      wrapper.appendChild(element);
      this.cloneTag();
    }
  }

  cloneTag = () => {
    const container = document.getElementById("shipwallet-container");
    this.replaceScriptNode(container);
  };

  replaceScriptNode = (node: any) => {
    if (this.isScriptNode(node) && !this.isExternalScript(node)) {
      if (node.parentNode) {
        node.parentNode.replaceChild(this.cloneScriptNode(node), node);
      }
    } else {
      let i = 0;
      const children = node.childNodes;
      while (i < children.length) {
        this.replaceScriptNode(children[i++]);
      }
    }
    return node;
  };

  isScriptNode = (node: HTMLScriptElement) => {
    return node.tagName === "SCRIPT";
  };

  isExternalScript = (node: HTMLScriptElement) => {
    return !!node.src && node.src !== "";
  };

  cloneScriptNode = (node: HTMLScriptElement) => {
    const script = document.createElement("script");
    script.text = node.innerHTML;
    for (let i = node.attributes.length - 1; i >= 0; i--) {
      script.setAttribute(node.attributes[i].name, node.attributes[i].value);
    }
    return script;
  };

  render() {
    return <div id="widget-wrapper" />;
  }
}

# Completing session

Complete session should be called after receiving confirmation from payment system. If session already have details about search address or user choice complete session will just mark session as completed and create order in Ingrid system. If above details were missing complete session will automatically select option based on Customer address.

Detailed information about call can be found in session.complete.

Last Updated: 3/13/2020, 2:31:37 PM