Skip to main content

How to deploy Lootly on a headless storefront

Learn how to deploy Lootly on a headless storefront.

Written by Aleksandra Velkova

A headless store separates your ecommerce platform from the storefront your customers see. Your platform still handles products, carts, orders and customer accounts, but the front end is a separate application you build and control.

If your store runs on a headless ecommerce site, you can still integrate it with Lootly. The backend connection is unchanged. What changes is that you add the loyalty widget to your front end yourself, and tell it which customer is signed in.

Please note: this guide involves adding code to your storefront, so you will likely need a developer.


In short:

What keeps working, and what you build

Feature

On a headless storefront

Order and points sync

Automatic

Refund and cancellation handling

Automatic

Points for creating an account

Automatic

Referral tracking and attribution

Automatic

VIP tier progression

Automatic

The loyalty widget

You add it

Signing customers into the widget

You add it

In-cart reward redemption

Not available at this time

Checkout points reminder

Not available at this time

Everything marked automatic runs on your ecommerce platform's backend, so it keeps working no matter what front end sits on top. You do not need to rebuild any of it.


Step 1. Integrate Lootly with your backend ecommerce platform

In a headless setup the backend is usually still one of the standard ecommerce platforms. Connect it to Lootly exactly as you would on a non-headless store, using the setup guide for your platform:

Install and configure the integration as normal, then place a test order and confirm it appears in your Lootly dashboard before moving on. If orders are not arriving, stop here and fix that first. Nothing in the following steps will work without it.

Magento merchants: the Order Status setting has no default value. Until you choose one, no orders are sent to Lootly, no points are earned and no referral ever pays out. Nothing looks broken, so this is easy to miss.

Set it under Stores → Configuration → Lootly Loyalty & Referrals → General API Settings → Order Status. The options are Processing, Invoiced, Shipped, Complete and Custom Event.


Step 2. Add the widget to your front end

On a standard storefront our integration injects the loyalty widget on every page for you. On a headless storefront, that injection never happens, so you add it yourself wherever you want the widget launcher to appear.

Render this container:

```html
<div id="lootly-widget"
class="lootly-init"
style="display: none"
data-shop-domain="https://yourstore.com/"
data-shop-id="COMPUTED_SHOP_ID"
data-customer-id="CUSTOMER_ID_OR_EMPTY"
data-customer-signature="COMPUTED_SIGNATURE_OR_EMPTY">
</div>
```

Then load the widget script once per page:

```html
<script src="https://app.lootly.io/js/integrations/common/script.js?shop=https://yourstore.com/"></script>
```

Use the `common` script on a headless build no matter which platform you are on. The platform-specific scripts only add cart and product helpers that depend on that platform's own storefront, which a headless front end does not have.

Attributes the widget reads

Attribute

Required

Value

`data-shop-domain`

Yes

Your store's base URL

`data-shop-id`

Yes

Generated from your API secret. See step 3

`data-customer-id`

When signed in

The customer's ID in your ecommerce platform. Leave empty when nobody is signed in

`data-customer-signature`

When signed in

Generated from your API secret. See step 3

`data-customer-email`

Optional

The customer's email address. Can be used instead of the customer ID

`data-hide-variable-rewards`

Optional

Set to `1` to hide variable point rewards from the widget

The container is matched by `#lootly-widget`, or by `[data-lootly-widget].lootly-init`, or by `.lootly-init[data-api-key]`.

Using `id="lootly-widget"` is the simplest option.

The widget renders inside an iframe, so it looks and behaves identically regardless of the framework your front end is built in. React, Vue, Svelte, Next.js and plain JavaScript all work the same way.

Match your store URL exactly. `data-shop-domain` is used to build `data-shop-id`, so both must be generated from the same string, trailing slash included. A mismatch means the widget loads but does not recognise your store.


Step 3. Sign your customer into the widget

This is the step most headless builds miss. Without it the widget loads, but every visitor sees it signed out. Nobody can view their points balance, rewards or referral link, even when they are signed into your store.

The widget identifies a customer using two values you generate from your API secret:

```
shop_id = md5( shop_domain + api_secret )
customer_signature = md5( customer_id + api_secret )
```

`customer_id` is the customer's ID in your ecommerce platform, the same ID your platform sends to Lootly with their orders. Your API key and API secret are in your Lootly dashboard, under your platform integration settings.

Generate both values on your server, then pass them through to your front end:

```js
// server side only
const shopId = md5(SHOP_DOMAIN + LOOTLY_API_SECRET);
const signature = md5(platformCustomerId + LOOTLY_API_SECRET);

// send shopId and signature to the front end,
// then render the container from step 2
```

Your API secret must stay on your server. Never include it in your front-end bundle and never expose it through a public endpoint. Anyone who has your API secret can generate a valid signature for any of your customers and read their loyalty account.

Expose only the finished `shop_id` and `customer_signature` values, and only for the customer who is currently signed in.

When no customer is signed in, leave both `data-customer-id` and `data-customer-signature` empty. The widget then shows its signed-out state, which is the correct behaviour and lets visitors join your program.

An incorrect signature fails silently. Lootly does not return an error for a signature that does not match. The widget loads normally and simply shows no customer data. If your widget always looks signed out, the signature is the first thing to check.


Step 4. Refresh the widget when customers sign in and out

On a standard storefront every page load is a fresh request from the server, so the widget always receives the current customer. A single-page application does not reload between pages, so you have to keep the widget in step yourself.

The widget will not rebuild itself while its iframe is still on the page. You must remove the iframe first, update the attributes, then call the init function:

```js
function refreshLootlyWidget(customerId, signature) {
const widget = document.querySelector('#lootly-widget');
if (!widget) return;

// 1. remove the existing iframe, or init will do nothing
const iframe = widget.querySelector('#lootly_iframe');
if (iframe) iframe.remove();

// 2. update the customer attributes
// (pass empty strings when signing out)
widget.setAttribute('data-customer-id', customerId || '');
widget.setAttribute('data-customer-signature', signature || '');

// 3. re-initialise, passing your Lootly app URL
if (typeof window.lootlyWidgetInit === 'function') {
window.lootlyWidgetInit('https://app.lootly.io');
}
}
```

Call this function whenever a customer signs in, signs out, or creates an account.

Pass the app URL. `window.lootlyWidgetInit` requires your Lootly app URL as its argument and will throw an error if you call it without one. Use the same host you load the script from.

Do not skip the sign-out case. If you only refresh the widget on sign-in, it keeps showing the previous customer's points and rewards after they sign out. On a shared or public computer, the next person sees that account.


Step 5. Test your integration

  1. Open your storefront signed out. The widget appears and invites the visitor to sign in or join

  2. Sign in. The widget shows that customer's points balance without a page refresh

  3. Place a test order and let it reach the status your integration syncs on. The points appear in that customer's Lootly account

  4. Sign out. The widget returns to its signed-out state immediately

  5. Sign in as a different customer. The widget shows the second customer's balance, never the first customer's

  6. Open a referral link in a private window and complete a test order. The referral is attributed and the sender is rewarded

  7. Test 5 is the one most often skipped, and it is the one your customers are most likely to notice if it is wrong.


Platform notes

The widget behaves identically on every platform. What differs is which customer ID you hash in step 3, and a few platform-specific settings.

Platform

Use this as 'customer id'

Shopify

The Shopify customer ID

Woocommerce

The WordPress user ID for that customer

Bigcommerce

The BigCommerce customer ID

Magento 2

The Magento customer entity ID

Maropost (former Neto)

The Neto customer username or ID

Custom API

The customer ID you send to Lootly with your orders

Magento

Keep the Lootly extension installed. It handles order sync, refunds, account creation and referral attribution through Magento's backend events, and all of that continues to work on a headless storefront. Only the storefront display needs replacing.

Your API key, API secret and Order Status can each be set at default, website or store view level. If you run several markets from one Magento instance, you can point each website at its own Lootly account.

Neto and Custom API

On these platforms coupons are not created by Lootly inside your store. You upload coupon codes to Lootly, or your own endpoint issues them. Any restriction on how a coupon can be used has to be configured on the coupon itself in your platform's admin, because Lootly cannot enforce it at your checkout.

Running several stores or markets

Connect each store to its own Lootly account so customers and point balances stay separate. That usually matches how your ecommerce platform already separates customer accounts between storefronts. Customers who register on more than one of your stores will have a separate balance on each.

What is not available on a headless store

In-cart reward redemption and the checkout points reminder are not available on headless storefronts.

Both are rendered by our integration directly into your platform's own cart and checkout templates. A headless front end does not load those templates, so there is nothing for them to attach to.

Your customers can still redeem rewards in the widget and receive a discount code to apply at checkout. This is the standard redemption flow and it works fully on a headless store.

If you want rewards applied to the cart automatically, that has to be built into your front end against our widget API, applying the resulting discount code through your platform's own cart functions. Contact support and we will point your developer at the right endpoints.

Troubleshooting

  1. The widget appears, but always shows as signed out. - The signature is not matching. Confirm you are hashing the customer's ID from your ecommerce platform and not their Lootly customer ID, that the API secret has no leading or trailing whitespace, and that the secret belongs to the same store you are connecting.

  2. The widget does not appear at all. - Check that your container matches one of the selectors in step 2, that the script loaded without a network or content security policy error, and that `data-shop-id` and `data-shop-domain` were built from the identical store URL string.

  3. The widget still shows the previous customer after sign-out. - The iframe is not being removed before re-initialising. See step 4. Removing `#lootly_iframe` is required, updating the attributes alone is not enough.

  4. Points are not awarded for orders. - This is a backend integration problem, not a headless one. Check that orders reach your Lootly dashboard. On Magento, confirm the Order Status setting has been chosen and that your test order actually reached that status.

  5. The widget is blocked by your content security policy. - Allow `app.lootly.io` in your `script-src`, `connect-src` and `frame-src` directives.


Need help?

Email support@lootly.io with your store URL, your ecommerce platform, and where on your site the widget is mounted.

If customers are not being signed in, tell us whether `data-customer-signature` is generated on your server or in the browser. That is the most common cause and it saves a round trip.

Did this answer your question?