# Installing Loyalty on Headless Instances

### Overview <a href="#overview" id="overview"></a>

For stores specifically running Shopify Hydrogen 2, please [look here](https://docs.okendo.io/okendo-shopify-hydrogen-support) for further support.

This guide explains how to integrate Okendo Loyalty into your headless Shopify store. The implementation requires 2-3 code snippets depending on your needs.

**Prerequisites:**

* Active Okendo Loyalty subscription
* Headless Shopify storefront
* Customer authentication implemented (via Customer Account API or Storefront API)

**Quick Links:**

* [Required: Loyalty Settings](https://untitled+.vscode-resource.vscode-cdn.net/Untitled-1#1-loyalty-settings-metafield)
* [Required: Customer Authentication](https://untitled+.vscode-resource.vscode-cdn.net/Untitled-1#2-customer-access-token-script-tag)
* [Optional: Additional Widgets](https://untitled+.vscode-resource.vscode-cdn.net/Untitled-1#3-loyalty-landing-page--other-widgets-optional)

### Implementation Steps <a href="#implementation-steps" id="implementation-steps"></a>

To implement Okendo Loyalty, you will need to render two or three snippets on your store:

### 1. Loyalty Settings Metafield <a href="#id-1-loyalty-settings-metafield" id="id-1-loyalty-settings-metafield"></a>

Located in your Shop Metafields, under the `okendo` namespace and `LoyaltySettings` key, you will find a snippet containing 2 script tags (one for the loyalty widget settings, and one for the initialisation script).

**Purpose:** Loads the Loyalty App with your customized settings and displays the Floating Widget.

**Implementation:** Render the metafield content in the `<head>` section of your store pages.

```liquid
<!-- Liquid example -->
{{ shop.metafields.okendo.LoyaltySettings }}
```

```javascript
// GraphQL query example (for Hydrogen/Remix)
query metafields {
  shop {
    metafield(namespace: "okendo", key: "LoyaltySettings") {
      value
    }
  }
}
```

The metafield contains 2 script tags:

1. Widget settings configuration
2. Initialization script

**Result:** The Floating Widget will appear automatically (unless disabled in Okendo Admin settings).

> **⚠️ Important:** This must be rendered on every page where you want loyalty features to appear.

### 2. Customer Access Token Script Tag <a href="#id-2-customer-access-token-script-tag" id="id-2-customer-access-token-script-tag"></a>

**Purpose:** Authenticates the customer to display personalized loyalty information.

**Required for:**

* Logged-in customer experience
* Points balance display
* Rewards redemption
* Member-specific content

Choose **one** implementation method based on your authentication approach:

#### Option A: Customer Account API (Recommended for New Hydrogen Stores) <a href="#option-a-customer-account-api-recommended-for-new-hydrogen-stores" id="option-a-customer-account-api-recommended-for-new-hydrogen-stores"></a>

**When to use:** Your store uses the [Customer Account API](https://shopify.dev/docs/api/customer/2025-01#authentication) for authentication (Shopify's newer authentication method).

**Implementation:**

```html
<script type="application/json" id="oke-loyalty-customer-access-token">
{
  "customerAccessToken": "YOUR_ACCESS_TOKEN_HERE"
}
</script>
```

**Example (React/Hydrogen):**

```tsx
// In your root layout or auth context
export function LoyaltyAuth({accessToken}: {accessToken: string}) {
  return (
    <script
      type="application/json"
      id="oke-loyalty-customer-access-token"
      dangerouslySetInnerHTML={{
        __html: JSON.stringify({customerAccessToken: accessToken}),
      }}
    />
  );
}
```

**Where to get the token:**

* The `access_token` is obtained during your login flow from the Customer Account API
* Typically stored in session/cookies after the OAuth redirect
* Usually already available since it's required for Customer Account API requests

**Token Lifecycle:**

* ✅ **Must** implement automatic token refresh when it expires
* ✅ Remove or update the script tag when customer logs out
* ✅ Check token expiry before rendering

> **💡 Tip:** Most Hydrogen projects already manage this token in an auth context or session.

#### Option B: Storefront API (Legacy Authentication) <a href="#option-b-storefront-api-legacy-authentication" id="option-b-storefront-api-legacy-authentication"></a>

**When to use:** Your store uses the [Storefront API](https://shopify.dev/docs/api/storefront/2025-01/mutations/customerAccessTokenCreate) for authentication (older method).

**Implementation:**

```html
<script type="application/json" id="oke-loyalty-storefront-customer-access-token">
{
  "storefrontCustomerAccessToken": "CUSTOMER_ACCESS_TOKEN",
  "storefrontAccessToken": "STOREFRONT_PUBLIC_TOKEN"
}
</script>
```

**Example (React):**

```tsx
export function LoyaltyAuthStorefront({
  customerToken,
  storefrontToken,
}: {
  customerToken: string;
  storefrontToken: string;
}) {
  return (
    <script
      type="application/json"
      id="oke-loyalty-storefront-customer-access-token"
      dangerouslySetInnerHTML={{
        __html: JSON.stringify({
          storefrontCustomerAccessToken: customerToken,
          storefrontAccessToken: storefrontToken,
        }),
      }}
    />
  );
}
```

**Required Token #1: `storefrontCustomerAccessToken`**

**Source:** Returned from the `customerAccessTokenCreate` mutation.

```graphql
mutation {
  customerAccessTokenCreate(input: {
    email: "customer@example.com"
    password: "password"
  }) {
    customerAccessToken {
      accessToken  # ← Use this value
      expiresAt
    }
  }
}
```

**What you need:** The `accessToken` string from the response.

**Required Token #2: `storefrontAccessToken`**

**Source:** Your Storefront API public access token.

**Where to find it:**

1. Go to `Shopify Admin → Sales channels`
2. Click on your headless storefront
3. Navigate to `Storefront API → Public access token`
4. Copy the token value

**Environment variable:** Usually stored as `PUBLIC_STOREFRONT_API_TOKEN` and used for your `X-Shopify-Storefront-Access-Token` header.

> **💡 Tip:** You're likely already using this token for all Storefront API requests in your project.

### 3. Loyalty Landing Page / Other Widgets (Optional) <a href="#id-3-loyalty-landing-page--other-widgets-optional" id="id-3-loyalty-landing-page--other-widgets-optional"></a>

#### Loyalty Page <a href="#loyalty-page" id="loyalty-page"></a>

To display the Loyalty Page Widget on one of your store pages (e.g. a dedicated loyalty page) all you need to do is render the snippet below:

```
<div data-oke-loyalty-embedded-widget=""></div>
```

When the app initialisation script runs, it will detect this `div` and render the Loyalty Page widget there.

Other valid snippets for rendering individual modules from the Loyalty Page Widget are listed below:

| Module         | Snippet                                         |
| -------------- | ----------------------------------------------- |
| Member Profile | `<div data-oke-loyalty-profile=""></div>`       |
| Redeem Rewards | `<div data-oke-loyalty-redeem=""></div>`        |
| Earn Rewards   | `<div data-oke-loyalty-earn=""></div>`          |
| VIP Tiers      | `<div data-oke-loyalty-vip-tiers=""></div>`     |
| Achievements   | `<div data-oke-loyalty-achievements=""></div>`  |
| Refer A Friend | `<div data-oke-loyalty-refer-friends=""></div>` |
| FAQ            | `<div data-oke-loyalty-faq=""></div>`           |

#### Cart Banner Widget <a href="#cart-banner-widget" id="cart-banner-widget"></a>

Display a banner showing points information at the top of your Cart page or cart drawer.

**Use cases:**

* Cart page header
* Cart drawer header
* Checkout flow

**Implementation:**

```html
<div data-oke-loyalty-banner-widget=""></div>
```

#### Points Preview Widget <a href="#points-preview-widget" id="points-preview-widget"></a>

We also offer a Points Preview widget for products, which can help inform customers how many points they will receive upon purchasing a specific product (usually displayed under the price on the Product Display Page, but also works on product carousels, etc).

This div also accepts other data attributes which will help it identify the correct product, and can also be used to help style it for different use cases on different pages:

| Attribute                          | Description                                                                                                                                                                                                                    |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| data-oke-loyalty-points-preview-id | We will use this Product ID to calculate the reward. If not supplied then we will try to find it elsewhere on the page.                                                                                                        |
| data-oke-loyalty-variant-id        | The Variant ID of the product for the calculation. If not supplied then we will try to find it elsewhere on the page or else use the default for the product.                                                                  |
| data-oke-loyalty-selling-plan-id   | If you offer subscription options for the product then you can use this to tell us which one is currently selected. If not supplied then we will try to find it elsewhere on the page or else use the default for the product. |
| data-oke-loyalty-background        | A Hex Color Code (e.g. `#FFFFFF`) for the background of the widget                                                                                                                                                             |
| data-oke-loyalty-icon              | The name of the Icon to be displayed in the widget. Accepts most Font Awesome icon names                                                                                                                                       |
| data-oke-loyalty-target            | If you are using this widget in the cart, please set this to `"cart"`. If you are using this widget in a cart drawer, please set this to `"cart-drawer"`. This is purely for analytics purposes.                               |

As a simple example, your snippet may look something like this:

```html
<div
    data-oke-loyalty-points-preview=""
    data-oke-loyalty-points-preview-id="8234567890123"
></div>
```

**Complete example with optional attributes:**

```html
<div
    data-oke-loyalty-points-preview=""
    data-oke-loyalty-points-preview-id="8234567890123"
    data-oke-loyalty-variant-id="45678901234567"
    data-oke-loyalty-background="#F5F5F5"
    data-oke-loyalty-icon="gift"
    data-oke-loyalty-target="product"
></div>
```

### Troubleshooting <a href="#troubleshooting" id="troubleshooting"></a>

#### Widget Not Appearing <a href="#widget-not-appearing" id="widget-not-appearing"></a>

**Check:**

1. ✅ Loyalty Settings metafield is rendered in `<head>` as HTML and not text (you may be required to use `dangerouslySetInnerHTML`)
2. ✅ Script tags are loading without errors (check browser console)
3. ✅ Customer access token is valid and not expired
4. ✅ Floating Widget is enabled in Okendo Admin settings

#### Customer Not Logged In to Loyalty <a href="#customer-not-logged-in-to-loyalty" id="customer-not-logged-in-to-loyalty"></a>

**Check:**

1. ✅ Customer access token script tag is present on the page
2. ✅ Token is valid (not expired)
3. ✅ Correct script ID is used (`oke-loyalty-customer-access-token` or `oke-loyalty-storefront-customer-access-token`)
4. ✅ JSON format is valid (use a JSON validator)

#### Points Not Showing on Products <a href="#points-not-showing-on-products" id="points-not-showing-on-products"></a>

**Check:**

1. ✅ Correct product ID is being passed to `data-oke-loyalty-points-preview-id`
2. ✅ Product exists in your Shopify store
3. ✅ Points earning rules are configured in Okendo Admin

#### Console Errors <a href="#console-errors" id="console-errors"></a>

Common errors and solutions:

* **"Cannot find metafield"**: Ensure Loyalty is enabled in Okendo Admin
* **"Invalid token"**: Check token format and expiry
* **"Widget initialization failed"**: Verify settings script is loaded and formatted correctly

### Testing Checklist <a href="#testing-checklist" id="testing-checklist"></a>

Before going live, verify:

* Floating Widget appears on all pages
* Customer can log in to loyalty widget when authenticated
* Points balance displays correctly for logged-in customers
* Products show points preview on product pages
* Loyalty page displays all modules correctly
* Cart banner shows points information
* Widget styling matches your brand
* All widgets work on mobile devices
* Token refresh works correctly when token expires

### Additional Resources <a href="#additional-resources" id="additional-resources"></a>

* [Okendo Admin Dashboard](https://reviews.okendo.io/admin)
* [Shopify Customer Account API Docs](https://shopify.dev/docs/api/customer/2025-01)
* [Shopify Storefront API Docs](https://shopify.dev/docs/api/storefront/2025-01)
* Need help? Contact Okendo Support


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.okendo.io/on-site/advanced-widget-installs/installing-loyalty-on-headless-instances.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
