# Javascript SDK - Storefront API

***

### Introduction

If you're using a headless storefront instead of Shopify's default theme, you'll need to integrate the Joy Subscription SDK to enable subscription features on your store.

This guide uses Next.js (App Router) for code examples, but the SDK works with any JavaScript framework. Adapt the code patterns to your specific framework as needed.

{% hint style="info" %}
This feature available for **Custom** plan.[ See all pricing options](https://joysubscription.com/pricing/)
{% endhint %}

#### SDK Features Overview

| Feature              | Description                                                     | For                             |
| -------------------- | --------------------------------------------------------------- | ------------------------------- |
| **Product Widget**   | Displays subscription plan selector on product pages            | All merchants                   |
| **Product Bundle**   | Allows customers to purchase bundles with subscription          | Merchants with bundles          |
| **Subscription Box** | Dedicated page for customers to build custom subscription boxes | Merchants with subscription box |
| **Customer Portal**  | Subscription management page for customers                      | All merchants                   |

#### Choose Your Integration Scope

Depending on your needs, you can choose one of the following integration levels:

| Need                                            | Sections to Complete | Estimated Time |
| ----------------------------------------------- | -------------------- | -------------- |
| **Widget only** (display plans on product page) | Part 1 → 4           | \~2 hours      |
| **Widget + Customer Portal**                    | Part 1 → 5           | \~3 hours      |
| **All features**                                | Part 1 → 7           | \~5 hours      |

***

### Table of Contents

**Part 1: Prerequisites** — System requirements and SDK installation

**Part 2: Basic Configuration** — Environment variables and TypeScript

**Part 3: Product Subscription Widget** — Display plan selector on product pages

**Part 4: Connect Widget to Cart** — Handle Add to Cart for subscriptions

**Part 5: Customer Portal** — Subscription management page for customers

**Part 6: Product Bundle** — Integrate bundles with subscription

**Part 7: Subscription Box** — Build subscription box page

**Part 8: Shopify Admin Configuration** — Set up redirects and customer accounts

**Part 9: Deployment** — Deploy to your hosting platform

Take a view our demo site: <https://headless-demo-five.vercel.app/search>

***

### Part 1: Prerequisites

#### System Requirements

Before you begin, make sure you have:

* A Shopify store with the [Joy Subscription](https://apps.shopify.com/joy-subscription?search_id=3823b151-8fe1-44a5-862f-16d6419db161\&surface_detail=subscription\&surface_inter_position=1\&surface_intra_position=11\&surface_type=search) app installed
* Products with selling plans configured in Shopify Admin
* A headless storefront built with a JavaScript framework (Next.js, Gatsby, Nuxt, Remix, etc.)
* Storefront API access token from Shopify Admin
* Node.js version 18 or higher

#### Get Your Storefront API Access Token

1. Go to **Shopify Admin** → **Settings** → **Apps and sales channels**
2. Click **Develop apps** → **Create an app**
3. Name your app (e.g., "Headless Storefront")
4. Go to **Configuration** → **Storefront API** → Select required permissions
5. Click **Install app** and copy the **Storefront API access token**

#### Install the SDK

Run the following command in your project directory:

```bash
pnpm add joy-subscription-sdk
```

Or if you're using npm/yarn:

```bash
npm install joy-subscription-sdk
# or
yarn add joy-subscription-sdk
```

***

### Part 2: Basic Configuration

#### 2.1. Environment Variables

Create a `.env.local` file (or equivalent for your framework) at your project root:

```env
# Store info
COMPANY_NAME="Your Store Name"
SITE_NAME="Your Site Name"

# Shopify credentials (server-side)
SHOPIFY_STORE_DOMAIN="your-store.myshopify.com"
SHOPIFY_STOREFRONT_ACCESS_TOKEN="your-storefront-access-token"

# Shopify credentials (client-side - used by SDK)
NEXT_PUBLIC_SHOPIFY_DOMAIN="your-store.myshopify.com"
NEXT_PUBLIC_STOREFRONT_TOKEN="your-storefront-access-token"
```

> **Important**: The SDK runs on the client side and needs access to your Shopify domain and Storefront token. Make sure these variables are exposed to the browser (in Next.js, use the `NEXT_PUBLIC_` prefix; other frameworks may have different conventions).

#### 2.2. TypeScript Declarations

The SDK doesn't include TypeScript definitions. Create a declaration file to avoid type errors:

**Create file: `types/joy-subscription-sdk.d.ts`**

```typescript
declare module 'joy-subscription-sdk' {
  export class SubscriptionSDK {
    static configure(config: {
      shopDomain: string;
      storefrontAccessToken: string;
      apiVersion?: string;
      apiBaseUrl?: string;
    }): void;
  }
}

declare module 'joy-subscription-sdk/widget' {
  export class WidgetSDK {
    constructor(config?: { shopDomain: string; storefrontAccessToken: string });
    initProduct(handle: string, options?: Record<string, unknown>): void;
    setVariant(variantId: string): void;
    setQuantity(quantity: number): void;
    on(event: string, callback: (data: any) => void): () => void;
    getSelectedPlan(): any;
    destroy(): void;
  }
}

declare module 'joy-subscription-sdk/portal' {
  export class PortalSDK {
    constructor(config?: { shopDomain: string; storefrontAccessToken: string });
    initCustomerPortal(options?: Record<string, unknown>): void;
    destroyCustomerPortal(): void;
    on(event: string, callback: (data: any) => void): () => void;
    destroy(): void;
  }
}

declare module 'joy-subscription-sdk/box' {
  export class BoxSDK {
    constructor(config?: { shopDomain: string; storefrontAccessToken: string });
    initSubscriptionBox(options?: Record<string, unknown>): void;
    destroySubscriptionBox(): void;
    on(event: string, callback: (data: any) => void): () => void;
    destroy(): void;
  }
}

declare module 'joy-subscription-sdk/productBundle' {
  export class ProductBundleSDK {
    constructor(config?: { shopDomain: string; storefrontAccessToken: string });
    initProductBundle(handle: string, options?: Record<string, unknown>): void;
    on(event: string, callback: (data: any) => void): () => void;
    destroy(): void;
  }
}
```

***

### Part 3: Product Subscription Widget

The widget allows customers to select subscription plans directly on the product page.

#### 3.1. Create Subscription Context

This context shares state between the Widget, Add to Cart button, and Variant Selector.

**Create file: `components/subscription/subscription-context.tsx`**

```tsx
'use client';

import { createContext, useCallback, useContext, useRef, useState } from 'react';
import type { ReactNode } from 'react';

type PlanSelection = {
  productId: string;
  variantId: string;
  sellingPlanId: string | null;
  plan: Record<string, unknown> | null;
};

type SubscriptionContextType = {
  selectedPlan: PlanSelection | null;
  setSelectedPlan: (plan: PlanSelection | null) => void;
  registerSetVariant: (fn: (variantId: string) => void) => void;
  notifyVariantChange: (variantId: string) => void;
};

const SubscriptionContext = createContext<SubscriptionContextType | null>(null);

export function SubscriptionProvider({ children }: { children: ReactNode }) {
  const [selectedPlan, setSelectedPlan] = useState<PlanSelection | null>(null);
  const setVariantRef = useRef<((variantId: string) => void) | null>(null);

  const registerSetVariant = useCallback((fn: (variantId: string) => void) => {
    setVariantRef.current = fn;
  }, []);

  const notifyVariantChange = useCallback((variantId: string) => {
    setVariantRef.current?.(variantId);
  }, []);

  return (
    <SubscriptionContext.Provider
      value={{ selectedPlan, setSelectedPlan, registerSetVariant, notifyVariantChange }}
    >
      {children}
    </SubscriptionContext.Provider>
  );
}

export function useSubscription() {
  const ctx = useContext(SubscriptionContext);
  if (!ctx) throw new Error('useSubscription must be used within SubscriptionProvider');
  return ctx;
}

export function useSubscriptionOptional() {
  return useContext(SubscriptionContext);
}
```

#### 3.2. Create Widget Component

**Create file: `components/subscription/subscription-widget.tsx`**

```tsx
'use client';

import { useEffect, useRef } from 'react';
import { WidgetSDK } from 'joy-subscription-sdk/widget';
import { useSubscription } from './subscription-context';

export function SubscriptionWidget({ productHandle }: { productHandle: string }) {
  const sdkRef = useRef<WidgetSDK | null>(null);
  const { setSelectedPlan, registerSetVariant } = useSubscription();

  useEffect(() => {
    // Initialize SDK with credentials
    const sdk = new WidgetSDK({
      shopDomain: process.env.NEXT_PUBLIC_SHOPIFY_DOMAIN!,
      storefrontAccessToken: process.env.NEXT_PUBLIC_STOREFRONT_TOKEN!,
    });
    sdkRef.current = sdk;

    // Listen for plan selection events
    const unsubscribe = sdk.on('plan:selected', (data: any) => {
      setSelectedPlan({
        productId: data.productId,
        variantId: data.variantId,
        sellingPlanId: data.sellingPlanId || null,
        plan: data.plan || null,
      });
    });

    // Register function to sync variant from Variant Selector
    registerSetVariant((variantId: string) => {
      sdk.setVariant(variantId);
    });

    // Initialize widget for the product
    sdk.initProduct(productHandle);

    // Cleanup on component unmount
    return () => {
      unsubscribe();
      sdk.destroy();
    };
  }, [productHandle, setSelectedPlan, registerSetVariant]);

  // Container element where SDK will render the widget
  return <div className="Avada-SubscriptionWidget-Block" />;
}
```

> **Important**: You **must** pass `shopDomain` and `storefrontAccessToken` directly to the constructor. Standalone bundles (`joy-subscription-sdk/widget`, etc.) do **not** read config from `SubscriptionSDK.configure()`.

#### 3.3. Add Widget to Product Page

Wrap your product description with `SubscriptionProvider` and place the widget:

**Update file: `components/product/product-description.tsx`**

```tsx
import { SubscriptionProvider } from 'components/subscription/subscription-context';
import { SubscriptionWidget } from 'components/subscription/subscription-widget';

export function ProductDescription({ product }: { product: Product }) {
  return (
    <SubscriptionProvider>
      {/* Product title, price, etc. */}
      <VariantSelector options={product.options} variants={product.variants} />
      
      {/* Widget renders here */}
      <SubscriptionWidget productHandle={product.handle} />
      
      {/* Product description */}
      <AddToCart product={product} />
    </SubscriptionProvider>
  );
}
```

***

### Part 4: Connect Widget to Cart

#### 4.1. Update Add to Cart Button

Modify your Add to Cart button to support subscription purchases:

**Update file: `components/cart/add-to-cart.tsx`**

```tsx
'use client';

import { useSubscriptionOptional } from 'components/subscription/subscription-context';

export function AddToCart({ product }: { product: Product }) {
  const subscription = useSubscriptionOptional();
  const selectedPlan = subscription?.selectedPlan;
  const isSubscription = !!selectedPlan?.sellingPlanId;

  // Build cart payload
  const payload = isSubscription
    ? { variantId: selectedVariantId, sellingPlanId: selectedPlan.sellingPlanId }
    : selectedVariantId;

  return (
    <button onClick={() => addItem(payload)}>
      {isSubscription ? 'Subscribe' : 'Add To Cart'}
    </button>
  );
}
```

#### 4.2. Update Server Action

**Update file: `components/cart/actions.ts`**

```tsx
export async function addItem(
  prevState: any,
  payload: { variantId: string; sellingPlanId?: string } | string | undefined
) {
  const cartId = cookies().get('cartId')?.value;
  if (!cartId) {
    return 'Missing cart ID';
  }

  const variantId = typeof payload === 'object' ? payload.variantId : payload;
  const sellingPlanId = typeof payload === 'object' ? payload.sellingPlanId : undefined;

  if (!variantId) return 'Missing variant ID';

  const line: CartLineInput = {
    merchandiseId: variantId,
    quantity: 1,
    ...(sellingPlanId && { sellingPlanId }),
  };

  await addToCart([line]);
  revalidateTag(TAGS.cart);
}
```

#### 4.3. Connect Variant Selector to Widget

When a customer selects a different variant, notify the SDK:

**Update file: `components/product/variant-selector.tsx`**

```tsx
import { useSubscriptionOptional } from 'components/subscription/subscription-context';

export function VariantSelector({ options, variants }: Props) {
  const subscription = useSubscriptionOptional();

  const handleOptionChange = (variantId: string) => {
    // ... existing URL update logic ...

    // Notify SDK of variant change
    subscription?.notifyVariantChange(variantId);
  };
}
```

#### 4.4. Add Discount Code Support

Create server actions for SDK events:

**Create file: `components/subscription/cart-actions.ts`**

```tsx
'use server';

import { TAGS } from 'lib/constants';
import { addToCart, updateCartDiscountCodes } from 'lib/shopify';
import { CartLineInput } from 'lib/shopify/types';
import { revalidateTag } from 'next/cache';

export async function addSubscriptionItems(lines: CartLineInput[]) {
  await addToCart(lines);
  revalidateTag(TAGS.cart);
}

export async function applyDiscountCodes(discountCodes: string[]) {
  await updateCartDiscountCodes(discountCodes);
  revalidateTag(TAGS.cart);
}
```

***

### Part 5: Customer Portal

A page where logged-in customers can manage their subscriptions.

#### 5.1. Create Customer Portal Component

**Create file: `components/subscription/customer-portal.tsx`**

```tsx
'use client';

import { useEffect, useRef } from 'react';
import { PortalSDK } from 'joy-subscription-sdk/portal';
import { addSubscriptionItems, applyDiscountCodes } from './cart-actions';

export function CustomerPortal() {
  const sdkRef = useRef<PortalSDK | null>(null);

  useEffect(() => {
    const sdk = new PortalSDK({
      shopDomain: process.env.NEXT_PUBLIC_SHOPIFY_DOMAIN!,
      storefrontAccessToken: process.env.NEXT_PUBLIC_STOREFRONT_TOKEN!,
    });
    sdkRef.current = sdk;

    // Listen for add-to-cart events from portal
    const unsubscribe = sdk.on('add-to-cart', async (data: any) => {
      if (data.items?.length) {
        await addSubscriptionItems(
          data.items.map((item: any) => ({
            merchandiseId: item.variantId,
            quantity: item.quantity || 1,
            ...(item.sellingPlanId && { sellingPlanId: item.sellingPlanId }),
          }))
        );
      }
      if (data.discountCodes?.length) {
        await applyDiscountCodes(data.discountCodes);
      }
    });

    sdk.initCustomerPortal();

    return () => {
      unsubscribe();
      sdk.destroy();
    };
  }, []);

  return <div id="Avada-SubscriptionManagement__Container" />;
}
```

#### 5.2. Create Customer Portal Page

**Create file: `app/pages/joy-subscription/[[...slug]]/page.tsx`**

```tsx
import { CustomerPortal } from 'components/subscription/customer-portal';

export const metadata = {
  title: 'My Subscriptions',
  description: 'Manage your subscriptions',
};

export default function CustomerPortalPage() {
  return (
    <div className="mx-auto max-w-screen-2xl px-4">
      <CustomerPortal />
    </div>
  );
}
```

> **Note**: The `[[...slug]]` catch-all route allows the portal to handle sub-pages like `/pages/joy-subscription/orders`.

***

### Part 6: Product Bundle (Optional)

For stores using the Product Bundle feature.

#### 6.1. Create Product Bundle Component

**Create file: `components/subscription/product-bundle-widget.tsx`**

```tsx
'use client';

import { useEffect, useRef } from 'react';
import { ProductBundleSDK } from 'joy-subscription-sdk/productBundle';
import { addSubscriptionItems, applyDiscountCodes } from './cart-actions';

export function ProductBundleWidget({ productHandle }: { productHandle: string }) {
  const sdkRef = useRef<ProductBundleSDK | null>(null);

  useEffect(() => {
    const sdk = new ProductBundleSDK({
      shopDomain: process.env.NEXT_PUBLIC_SHOPIFY_DOMAIN!,
      storefrontAccessToken: process.env.NEXT_PUBLIC_STOREFRONT_TOKEN!,
    });
    sdkRef.current = sdk;

    const unsubscribe = sdk.on('add-to-cart', async (data: any) => {
      if (data.items?.length) {
        await addSubscriptionItems(
          data.items.map((item: any) => ({
            merchandiseId: item.variantId,
            quantity: item.quantity || 1,
            ...(item.sellingPlanId && { sellingPlanId: item.sellingPlanId }),
          }))
        );
      }
      if (data.discountCodes?.length) {
        await applyDiscountCodes(data.discountCodes);
      }
    });

    sdk.initProductBundle(productHandle);

    return () => {
      unsubscribe();
      sdk.destroy();
    };
  }, [productHandle]);

  return (
    <div
      className="Avada-ProductBundleData-Block"
      data-product={JSON.stringify({ handle: productHandle })}
    />
  );
}
```

#### 6.2. Add to Product Page

```tsx
// app/product/[handle]/page.tsx
import { ProductBundleWidget } from 'components/subscription/product-bundle-widget';

export default async function ProductPage({ params }) {
  return (
    <>
      <ProductDescription product={product} />
      <ProductBundleWidget productHandle={params.handle} />
    </>
  );
}
```

***

### Part 7: Subscription Box (Optional)

For stores using the Subscription Box feature.

#### 7.1. Create Subscription Box Component

**Create file: `components/subscription/subscription-box.tsx`**

```tsx
'use client';

import { useEffect, useRef } from 'react';
import { BoxSDK } from 'joy-subscription-sdk/box';
import { addSubscriptionItems, applyDiscountCodes } from './cart-actions';

export function SubscriptionBox() {
  const sdkRef = useRef<BoxSDK | null>(null);

  useEffect(() => {
    const sdk = new BoxSDK({
      shopDomain: process.env.NEXT_PUBLIC_SHOPIFY_DOMAIN!,
      storefrontAccessToken: process.env.NEXT_PUBLIC_STOREFRONT_TOKEN!,
    });
    sdkRef.current = sdk;

    const unsubscribe = sdk.on('add-to-cart', async (data: any) => {
      if (data.items?.length) {
        await addSubscriptionItems(
          data.items.map((item: any) => ({
            merchandiseId: item.variantId,
            quantity: item.quantity || 1,
            ...(item.sellingPlanId && { sellingPlanId: item.sellingPlanId }),
          }))
        );
      }
      if (data.discountCodes?.length) {
        await applyDiscountCodes(data.discountCodes);
      }
    });

    sdk.initSubscriptionBox();

    return () => {
      unsubscribe();
      sdk.destroy();
    };
  }, []);

  return <div className="Avada-SubscriptionBox__Wrapper" />;
}
```

#### 7.2. Create Subscription Box Page

**Create file: `app/pages/subscription-box/page.tsx`**

```tsx
import { SubscriptionBox } from 'components/subscription/subscription-box';

export const metadata = {
  title: 'Subscription Box',
  description: 'Build your custom subscription box',
};

export default function SubscriptionBoxPage() {
  return (
    <div className="mx-auto max-w-screen-2xl px-4">
      <SubscriptionBox />
    </div>
  );
}
```

***

### Part 8: Shopify Admin Configuration

#### 8.1. Create Selling Plans

1. Go to **Shopify Admin** → **Apps** → **Joy Subscription**
2. Create a subscription plan (e.g., "Monthly Subscription - Every 1 month")
3. Assign the selling plan to your products

#### 8.2. Verify Product Has Selling Plan

Go to **Products** → Select a product → Check the **Purchase options** section. You should see your selling plan listed.

#### 8.3. Redirect from Shopify Theme (Optional)

If customers might land on your Shopify theme (e.g., after checkout), you can redirect them to your headless storefront:

1. Go to **Online Store** → **Themes** → **Edit code**
2. Open `layout/theme.liquid`
3. Add the following code right after `<link rel="preconnect" ...>`:

```liquid
{% if request.path == '/' or request.path == '' %}
  <script>
    window.location.href = 'https://your-headless-store-domain.com';
  </script>
{% endif %}
```

Replace `your-headless-store-domain.com` with your actual headless storefront domain.

#### 8.4. Customer Account (Optional)

If you want to use Shopify's New Customer Accounts:

```tsx
<a href={`https://${process.env.NEXT_PUBLIC_SHOPIFY_DOMAIN}/account`}>
  Account
</a>
```

***

### Part 9: Deployment

#### 9.1. Environment Variables

Before deploying, ensure all required environment variables are configured in your hosting platform:

| Variable                          | Required      | Description                             |
| --------------------------------- | ------------- | --------------------------------------- |
| `SHOPIFY_STORE_DOMAIN`            | Yes           | Your Shopify store domain               |
| `SHOPIFY_STOREFRONT_ACCESS_TOKEN` | Yes           | Storefront API token (server-side)      |
| `NEXT_PUBLIC_SHOPIFY_DOMAIN`      | **Yes (SDK)** | Your Shopify store domain (client-side) |
| `NEXT_PUBLIC_STOREFRONT_TOKEN`    | **Yes (SDK)** | Storefront API token (client-side)      |

> **Important**: Client-side environment variables (like `NEXT_PUBLIC_*` in Next.js) are typically injected at **build time**. If you add or change them after deployment, you'll need to **rebuild and redeploy** for changes to take effect. Refer to your hosting platform's documentation for specific instructions.

#### 9.2. Build and Deploy

Build your project and deploy to your hosting platform of choice. Common options include:

* **Vercel** — Optimized for Next.js
* **Netlify** — Supports multiple frameworks
* **AWS Amplify** — Full-stack deployment
* **Cloudflare Pages** — Edge-first deployment
* **Self-hosted** — Any Node.js-capable server

Follow your hosting platform's deployment guide for specific instructions.

#### 9.3. Verify After Deployment

After deployment, verify the integration is working:

1. Visit a product page → Subscription widget should appear
2. Select a plan → Button changes to "Subscribe"
3. Click "Subscribe" → Item is added to cart with selling plan
4. Visit `/pages/subscription-box` → Subscription box loads (if configured)
5. Visit `/pages/joy-subscription` → Customer portal loads (if configured)

***

### Troubleshooting

#### Widget Not Showing on Product Page

| Cause                                     | Solution                                                                        |
| ----------------------------------------- | ------------------------------------------------------------------------------- |
| Client-side environment variables not set | Add them in your hosting platform's dashboard → Rebuild and redeploy            |
| Config not passed to SDK                  | Pass `{ shopDomain, storefrontAccessToken }` directly to `new WidgetSDK({...})` |
| Product has no selling plan               | Add a selling plan to the product in Shopify Admin                              |
| Wrong product handle                      | Verify the handle matches Shopify                                               |

#### "Subscribe" Button Not Appearing

* Ensure `SubscriptionProvider` wraps both `SubscriptionWidget` and `AddToCart`
* Use `useSubscriptionOptional()` in AddToCart (not `useSubscription()`)

#### Console Error: "SDK requires configuration"

Config was not passed to the constructor. Do **NOT** use `SubscriptionSDK.configure()` — standalone bundles have separate module scopes.

```tsx
// ✅ Correct
const sdk = new WidgetSDK({
  shopDomain: process.env.NEXT_PUBLIC_SHOPIFY_DOMAIN!,
  storefrontAccessToken: process.env.NEXT_PUBLIC_STOREFRONT_TOKEN!,
});

// ❌ Wrong - standalone bundles don't read global config
SubscriptionSDK.configure({ shopDomain: '...', storefrontAccessToken: '...' });
const sdk = new WidgetSDK(); // config is empty!
```

#### Checkout Redirects to Shopify Theme

Add the JavaScript redirect in `layout/theme.liquid` as described in [Part 8.3](https://claude.ai/chat/656b6c6a-9c68-44f9-b6ff-2ad2ff6cd5a2#83-redirect-from-shopify-theme-optional).

#### Variant Change Not Reflected in Widget

Ensure your Variant Selector calls `subscription?.notifyVariantChange(variantId)` when the variant changes.

#### Environment Variables Not Taking Effect

Client-side environment variables are typically baked into the JavaScript bundle at build time. If you've added or changed them:

1. Verify the variables are set correctly in your hosting platform
2. Trigger a new build/deployment
3. Clear your browser cache and refresh

***

### Quick Reference

#### SDK Events

| SDK              | Event           | Data                                            | Purpose                              |
| ---------------- | --------------- | ----------------------------------------------- | ------------------------------------ |
| WidgetSDK        | `plan:selected` | `{ productId, variantId, sellingPlanId, plan }` | Update context when plan is selected |
| ProductBundleSDK | `add-to-cart`   | `{ items: [...], discountCodes: [...] }`        | Add bundle to cart                   |
| BoxSDK           | `add-to-cart`   | `{ items: [...], discountCodes: [...] }`        | Add box to cart                      |
| PortalSDK        | `add-to-cart`   | `{ items: [...], discountCodes: [...] }`        | Add items from portal                |

#### Container Elements

| SDK              | HTML Element                                           |
| ---------------- | ------------------------------------------------------ |
| WidgetSDK        | `<div class="Avada-SubscriptionWidget-Block" />`       |
| ProductBundleSDK | `<div class="Avada-ProductBundleData-Block" />`        |
| BoxSDK           | `<div class="Avada-SubscriptionBox__Wrapper" />`       |
| PortalSDK        | `<div id="Avada-SubscriptionManagement__Container" />` |

***

### Need Help?

If you encounter any issues during integration, please contact the Joy Subscription support team:

* **Email**: <support@avada.io>
* **Live chat**: Within the Joy Subscription app in Shopify Admin
