Shop Now: Headless On-Store Setup

OVERVIEW

This article details guidance for On-Store setup for merchants who have headless Shopify stores. Headless Shopify stores are when a merchant uses Shopify's backend software, but does not use Shopify's native theme builder. 

Once these steps are complete, you can continue to Step 3. of the regular Shop Now: On-Store Setup article

Setup Instructions 

Before getting started, grab an API key with just the cart scope selected from the Developer Tools (Settings > Developers) in the Loop admin. If you do not have access to this, please email support@loopreturns.com. This should be a completely separate key from any other keys since it will be used client side and therefore visible to anyone.

  • Handle users coming from Loop

    Loop will send users to your site with a set of query parameters (a full list can be found in our docs, as well as an example URL you can copy/paste). On page load, you should look for these parameters and use that to determine whether it's a normal user or if the user is shopping with return credit.

    We recommend looking for a specific param we send or just checking for any param that starts with loop.

    <code style="font-weight: normal;">if (window.location.search.includes('loop_total')) { 	// User is coming from Loop }
    	

    If the user is from Loop:

    • Store the data you received in some form of client-side storage (we recommend localStorage for ease of use).
      <code style="font-weight: normal;">let paramsObject = null;  if (window.location.search.includes('loop_total')) {   const params = new URLSearchParams(window.location.search);    // Remove any non-loop related query params, then convert the query string   // to an object of key/value pairs to make it easier to work with   paramsObject = [...params.entries()]     .filter(([key]) => key.startsWith('loop'))     .reduce((acc, [key, value]) => {       return {         ...acc,         [key]: value       };     }, {});      localStorage.setItem('loopOnstoreParams', JSON.stringify(paramsObject)); }
      		

      If you're using a state management library (Redux, etc.), you may want to track it there as well, especially if you want to use the data to show the user's credit (see step 4).

    • Modify your code that's looking for the query parameters to also look for your stored data. This will ensure that the customer doesn't get lost if they refresh the page or if you're working on a multi-page app.
      <code style="font-weight: normal;">let paramsObject = null; // Check if we already have saved params const savedParams = localStorage.getItem('loopOnstoreParams'); paramsObject = savedParams ? JSON.parse(savedParams) : null;  if (window.location.search.includes('loop_total')) {   const params = new URLSearchParams(window.location.search);    // Remove any non-loop related query params, then convert the query string   // to an object of key/value pairs to make it easier to work with   paramsObject = [...params.entries()]     .filter(([key]) => key.startsWith('loop'))     .reduce((acc, [key, value]) => {       return {         ...acc,         [key]: value       };     }, {});    localStorage.setItem('loopOnstoreParams', JSON.stringify(paramsObject)); }
      		
    • (Optional) Clean up the URL by removing the query params

      This is not required, but we recommend cleaning it up once you have the data saved to localStorage.

      <code style="font-weight: normal;">let paramsObject = null; // Check if we already have saved params const savedParams = localStorage.getItem('loopOnstoreParams'); paramsObject = savedParams ? JSON.parse(savedParams) : null;  if (window.location.search.includes('loop_total')) {   const params = new URLSearchParams(window.location.search);    // Remove any non-loop related query params, then convert the query string   // to an object of key/value pairs to make it easier to work with   paramsObject = [...params.entries()]     .filter(([key]) => key.startsWith('loop'))     .reduce((acc, [key, value]) => {       return {         ...acc,         [key]: value       };     }, {});    localStorage.setItem('loopOnstoreParams', JSON.stringify(paramsObject));   // Remove query params from the URL   window.history.replaceState({}, '', `${window.location.origin}${window.location.pathname}`); }
      		
    • (Optional) Clear the users cart

      We recommend giving the user a clean cart for shopping with their return credit. How you do this is going to depend on how your cart is set up.

  • Handle sending users back to Loop with an on-store cart

    Once you've determined that a user is shopping with return credit in the previous step, they are free to shop like they normally would, and then we'll use the cart on your storefront to create a Loop cart and redirect them back to Loop.

    • When a user clicks on your checkout button, check to see if the user is shopping with return credit, either from your centralized store or from localStorage. If they are, stop the user from going to checkout; we're going to redirect them back to Loop with their current cart instead.
      <code style="font-weight: normal;">// Check if we already have saved params const savedParams = localStorage.getItem('loopOnstoreParams'); paramsObject = savedParams ? JSON.parse(savedParams) : null;  // How you bind this click handler depends heavily on what tech you're using, // this is vanilla JS to show the basic concept // This assumes a link with the id "checkout" is present on the current page document.querySelector('#checkout').addEventListener('click', (e) => {   if (savedParams) {     // Stop the user from going to the checkout page     e.preventDefault();   } });
      		
    • Create a new cart in Loop. You'll need to get a list of Shopify variant ids from your cart to send when creating the cartβ€”how you get this will depend on how your cart is implemented. Once you've successfully created the cart, you will get a token in the response. This is a token for you current cart, from here on out you will use this token to access and modify the cart.
    • Save the token to localStorage along with the return id (this is sent in the query params, it's the loop_return_id param), separate from the params data you saved eariler. We'll use this later to enable users to return back for a second round of shopping.
    • Remove the initial param data you saved at the beginning from localStorage to restore your shop back to the normal shopping flow.
    • Clear your shop's cart.
    • Redirect the user back to Loop, using the token of the cart you've just created. Your redirect should look something like: https://SHOPNAME.loopreturns.com/#/cart/v2/TOKEN
  • Handle return users coming from Loop

    Loop allows the user to continue shopping if they would like. The user will get sent back with the same params as before so the code you've written already will pick that up. The two things you'll need to modify are:

    • While saving the params to localStorage, check to see if you have a cart token saved. If so, check that the return id that goes with that token matches the current return id and if so, use the get cart endpoint to see what's currently in their cart and update your store's cart to match. This way they can pick up right where they left off.
    • When getting ready to send a user back to Loop, check that you have a cart token (that again matches the current return id), and if so, use the update cart endpoint instead of creating a new cart.
  • (Optional) Show the user how much credit they have to shop with

    It's a good idea to give the user some sort of persistent indication that they're shopping with return credit. We recommend some sort of fixed element like a bar at the bottom of the screen that explains that they're shopping with return credit and shows how much credit they have. You can get the amount of credit they have available from the loop_total param. We also recommend that you add a "back to return" button so the user is less likely to get stuck. The loop_redirect_uri param gives you a URL to redirect them to.

If you have any questions along the way, please reach out to support@loopreturns.