# BOGOS JS/SDK

## Version source <a href="#version-source" id="version-source"></a>

```env
  BOGOS_JS_SDK=https://cdn.bogos.io/bogos-app-ext/20250905-1757090109/core.min.js
```

## Requirements <a href="#requirements" id="requirements"></a>

* Your store must be built using the [Storefront API](https://shopify.dev/docs/api/storefront).
* Always create a cart after applying BOGOS to ensure the [cart ID](https://shopify.dev/docs/api/storefront/latest/queries/cart#returns-Cart.fields.id) is received correctly. [*Example*](https://github.com/krycek-fengdx/bogos-headless-js/blob/f17a2faab77baa85413af3fa3ad36bf28019d97a/app/root.tsx#L79)
* For advanced customization in your Headless store, refer to the [BOGOS API documentation](https://bogos-api-integration.gitbook.io/bogos-api-integration).

## Installation <a href="#installation" id="installation"></a>

### Step 1: Getting started <a href="#step-1-getting-started" id="step-1-getting-started"></a>

1. Add the following script to your project:

   ```html
   <script id="bogos-core" src={{BOGOS_JS_SDK}} defer
     data-storefront-api-token={{PUBLIC_STOREFRONT_API_TOKEN}}
     data-api-version={{PUBLIC_STOREFRONT_API_VERSION}}
     data-myshopify-domain={{MYSHOPIFY_DOMAIN}}
     data-bogos-key={{BOGOS_KEY}}
   />
   ```

   | **Property**                             | **Description**                                                                                                                            | **Example**                                        |
   | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------- |
   | `VERSION_SOURCE: String!`                | The script URL for the current version                                                                                                     | <https://cdn.bogos.io/\\{{version\\}}/core.min.js> |
   | `PUBLIC_STOREFRONT_API_TOKEN: String!`   | [Public Storefront API token](https://shopify.dev/docs/api/storefront/latest#token-based-authentication)                                   | abcd...                                            |
   | `PUBLIC_STOREFRONT_API_VERSION: String!` | [Storefront API version](https://shopify.dev/docs/api/storefront/latest#versioning)                                                        | 2025-04                                            |
   | `MYSHOPIFY_DOMAIN: String!`              | [Myshopify domain](https://shopify.dev/docs/api/storefront/latest#endpoints-and-queries) (found in **Shopify Admin > Settings**)           | bogos.myshopify.com                                |
   | `BOGOS_KEY: String!`                     | [Key generated by the BOGOS app](https://bogos-api-integration.gitbook.io/bogos-api-integration/integration-requirements#id-4.-middleware) | bogoskey...                                        |

   > 💡 **Example Available**\
   > 👉 [root.tsx](https://github.com/krycek-fengdx/bogos-headless-js/blob/f17a2faab77baa85413af3fa3ad36bf28019d97a/app/root.tsx#L164)
2. Update your project with the required BOGOS data:

   ```javascript
   typeof window !== 'undefined' && typeof window.BOGOS_CORE !== 'undefined' &&
     window.BOGOS_CORE?.helper?.updateCore(option: BOGOSOptions)
   ```

   ```typescript
   export type BOGOSOptions = {
     cart?: Cart;
     customer?: string | Customer;
     locale?: string; https://shopify.dev/docs/api/storefront/latest#@inContext-(Language)
     country?: string; https://shopify.dev/docs/api/storefront/latest#@inContext-(Country-Code)
     currency?: {
       active: string;
       rate: number;
     };
   };
   ```

   Note:

   * You must provide at least one of the above properties.

   * If you provide the full Cart object, BOGOS will not fetch the cart again.

   * If only the Cart ID is provided, BOGOS will fetch the cart again.

   * The customer parameter can be either a [customer access token](https://shopify.dev/docs/api/storefront/latest/queries/customer) or [customer object](https://shopify.dev/docs/api/storefront/latest/objects/Customer)

   > 💡 **Example Available**\
   > 👉 [root.tsx](https://github.com/krycek-fengdx/bogos-headless-js/blob/f17a2faab77baa85413af3fa3ad36bf28019d97a/app/root.tsx#L131)\
   > 👉 [Layout.tsx](https://github.com/krycek-fengdx/bogos-headless-js/blob/f17a2faab77baa85413af3fa3ad36bf28019d97a/app/components/Layout.tsx#L86)\
   > 👉 [Cart.tsx](https://github.com/krycek-fengdx/bogos-headless-js/blob/f17a2faab77baa85413af3fa3ad36bf28019d97a/app/components/Cart.tsx#L27)

### Step 2: Gift Offer <a href="#step-2-gift-offer" id="step-2-gift-offer"></a>

1. Trigger the gift logic whenever the cart is updated:

   ```javascript
     typeof document !== 'undefined' && document.dispatchEvent(new CustomEvent('bogos:gifts', { detail: cart }));
   ```

   Note:

   * cart: [Cart](https://shopify.dev/docs/api/storefront/latest/objects/Cart)

   * If you provide the full Cart, it won’t fetch again.

   * If only the Cart ID is provided, it will fetch again.

   > 💡 **Example Available**\
   > 👉 [Cart.tsx](https://github.com/krycek-fengdx/bogos-headless-js/blob/f17a2faab77baa85413af3fa3ad36bf28019d97a/app/components/Cart.tsx#L24)
2. Add prepareCheckout to your checkout process to validate gift items before proceeding to checkout:

   ```javascript

   async function {your_function_checkout} (args) {
       ...
       typeof window !== 'undefined' && typeof window.BOGOS_CORE !== 'undefined' &&
         await BOGOS_CORE?.helper?.gift?.prepareCheckout();
       ...
   }
   ```

   > 💡 **Example Available**\
   > 👉 [Cart.tsx](https://github.com/krycek-fengdx/bogos-headless-js/blob/f17a2faab77baa85413af3fa3ad36bf28019d97a/app/components/Cart.tsx#L135)
3. Customize

   3.1. Gift Icon & Gift thumbnail

   * On the product page Add class "fg-secomapp-product-title" where you want to display gift icon Add class "bogos-gift-thumbnail-view" where you want to display gift thumbnail

   ```javascript
   typeof window !== 'undefined' && window.BOGOS_CORE?.helper?.gift?.renderCustomizeForProduct([{ id: product_id }], { product: true });
   ```

   or

   ```javascript
   // An event is triggered for all customizations on the product page
   typeof document !== 'undefined' && document.dispatchEvent(new CustomEvent("bogos:product-change", {
     detail: {
       products: [{ id: product_id }],
       options: { product: true, selectedVariants?: [{ product_id: product_id, id: selected_variant_id }] }
     }
   }));
   ```

   > 💡 **Example Available**\
   > 👉 [products.$handle.tsx](https://github.com/krycek-fengdx/bogos-headless-js/blob/f17a2faab77baa85413af3fa3ad36bf28019d97a/app/routes/products.%24handle.tsx#L164)

   * For collection page Add class "fg-secomapp-collection-img" to where you want to display gift icon on product card

   ```javascript
   typeof window !== 'undefined' && window.BOGOS_CORE?.helper?.gift?.renderCustomizeForProduct([{ id: product.id }], { collection: true });
   ```

   > 💡 **Example Available**\
   > 👉 [collections.$handle.tsx](https://github.com/krycek-fengdx/bogos-headless-js/blob/f17a2faab77baa85413af3fa3ad36bf28019d97a/app/routes/collections.%24handle.tsx#L97)

   3.2. Cart message

   Add the class "bogos-cart-message-view" to the element where you want the message displayed

   ```html
   <div class="bogos-cart-message-view"></div>
   ```

   3.3. Gift slider

   To embed the gift slider instead of displaying as a popup, include the following code:

   ```html
   <div id="freegifts-main-page-container"></div>
   ```

### Step 3: Bundle Offer <a href="#step-3-bundle-offer" id="step-3-bundle-offer"></a>

1. Classic bundle

   Add the following element to where you want to display the bundle offer.

   ```html
     <div id="bogos-bundle-view" data-product-handle={{product_handle}} data-product-id={{product_id}} data-offer-id={{offer_id}}></div>

     /* 
       product_id: number; legacy product id
       offer_id: number; BOGOS offer id
     */
   ```

   Dispatch this element to render the bundle offer

   ```javascript
     typeof document !== "undefined" && document.dispatchEvent(new CustomEvent("bogos:bundle-init"));
   ```

   or

   ```javascript
   // An event is triggered for all customizations on the product page
   typeof document !== 'undefined' && document.dispatchEvent(new CustomEvent("bogos:product-change", {
     detail: {
       products: [{ id: product_id }],
       options: { 
         product?: true, 
         selectedVariants?: [{ product_id: product_id, id: selected_variant_id }] 
       }
     }
   }));
   ```

   > 💡 **Example Available**\
   > 👉 [products.$handle.tsx](https://github.com/krycek-fengdx/bogos-headless-js/blob/f17a2faab77baa85413af3fa3ad36bf28019d97a/app/routes/products.%24handle.tsx#L164)
2. Mix-match

   Add the following element to where you want to display the bundle offer.

   ```html
     <div id="bogos-mix-match-view" data-product-handle={{product_handle}} data-product-id={{product_id}} data-offer-id={{offer_id}}></div>

     /* 
       product_id: number; legacy product id
       offer_id: number; BOGOS offer id
     */
   ```

   Dispatch this element to show bundle offer

   ```javascript
     typeof document !== "undefined" && document.dispatchEvent(new CustomEvent("bogos:bundle-init"));
   ```

   or

   ```javascript
   // An event is triggered for all customizations on the product page
   typeof document !== 'undefined' && document.dispatchEvent(new CustomEvent("bogos:product-change", {
     detail: {
       products: [{ id: product_id }],
       options: { 
         product?: true, 
         selectedVariants?: [{ product_id: product_id, id: selected_variant_id }] 
       }
     }
   }));
   ```

   > 💡 **Example Available**\
   > 👉 [products.$handle.tsx](https://github.com/krycek-fengdx/bogos-headless-js/blob/f17a2faab77baa85413af3fa3ad36bf28019d97a/app/routes/products.%24handle.tsx#L164)

### Step 4: Bundle Page <a href="#step-4-bundle-page" id="step-4-bundle-page"></a>

Add the following element to where you want to display the bundle offer.

```html
  <div id="bogos-bundle-page-view" data-offer-id={{offer_id}}></div>

  /* offer_id: number; BOGOS offer id */
```

Dispatch this element to render the bundle offer.

```javascript
  typeof document !== "undefined" && document.dispatchEvent(new CustomEvent("bogos:bundle-page-init"));
```

> 💡 **Example Available**\
> 👉 [bundle-page.$id.tsx](https://github.com/krycek-fengdx/bogos-headless-js/blob/f17a2faab77baa85413af3fa3ad36bf28019d97a/app/routes/bundle-page.%24id.tsx#L24)

### Step 5: Upsell Offer <a href="#step-5-upsell-offer" id="step-5-upsell-offer"></a>

1. Frequently Bought Together (FBT)

   Add the following element to where you want to display the upsell offer

   ```html
     <div id="bogos-fbt-upsell-view" data-product-handle={{product_handle}} data-product-id={{product_id}} data-offer-id={{offer_id}}></div>

     /* 
       product_id: number; legacy product id
       offer_id: number; BOGOS offer id
     */
   ```

   Dispatch this element to render the upsell offer

   ```javascript
     typeof document !== "undefined" && document.dispatchEvent(new CustomEvent("bogos:upsell-init"));
   ```

   > 💡 **Example Available**\
   > 👉 [products.$handle.tsx](https://github.com/krycek-fengdx/bogos-headless-js/blob/f17a2faab77baa85413af3fa3ad36bf28019d97a/app/routes/products.%24handle.tsx#L164)

### Step 6: Discount Offer <a href="#step-6-discount-offer" id="step-6-discount-offer"></a>

1. Volume Discount

   Add the following element to where you want to display the discount offer

   ```html
     <div id="bogos-volume-discount-view" data-product-handle={{product_handle}} data-product-id={{product_id}} data-offer-id={{offer_id}}></div>

     /* 
       product_id: number; legacy product id
       offer_id: number; BOGOS offer id
     */
   ```

   Dispatch this element to render the discount offer

   ```javascript
     typeof document !== "undefined" && document.dispatchEvent(new CustomEvent("bogos:discount-init"));
   ```

   or

   ```javascript
   // An event is triggered for all customizations on the product page
   typeof document !== 'undefined' && document.dispatchEvent(new CustomEvent("bogos:product-change", {
     detail: {
       products: [{ id: product_id }],
       options: { 
         product?: true, 
         selectedVariants?: [{ product_id: product_id, id: selected_variant_id }] 
       }
     }
   }));
   ```

   > 💡 **Example Available**\
   > 👉 [products.$handle.tsx](https://github.com/krycek-fengdx/bogos-headless-js/blob/f17a2faab77baa85413af3fa3ad36bf28019d97a/app/routes/products.%24handle.tsx#L164)

### Step 7: Other integration <a href="#step-7-other-integration" id="step-7-other-integration"></a>

1. Hide gift (cloned product) from appearing in your headless store

   * If you use [products](https://shopify.dev/docs/api/storefront/lastes/queries/products) query, you should add : `query: "tag_not:bogos-gift"`

   ```graphql
   products (
       ...,
       query: "tag_not:bogos-gift"
   ) {
   ...
   }
   ```

   * For collection and product page, you can import **`checkItemIsGift`** and use returned value to skip gift products or replace to other pages

   ```typescript
   export type ProductObject = {
       handle: string;
       tags: string[];
       variant_id: number;
   };

   /* item can be product handle */
   checkItemIsGift: (item: string | ProductObject) => boolean;
   ```

   > 💡 **Example Available**\
   > 👉 [collections.$handle.tsx](https://github.com/krycek-fengdx/bogos-headless-js/blob/f17a2faab77baa85413af3fa3ad36bf28019d97a/app/routes/collections.%24handle.tsx#L107)\
   > 👉 [products.$handle.tsx](https://github.com/krycek-fengdx/bogos-headless-js/blob/f17a2faab77baa85413af3fa3ad36bf28019d97a/app/routes/products.%24handle.tsx#L193)
2. Customize gift popup/slider

   Hide all default gift slider elements, and override with your custom implementation.

   ```css
     #freegifts-main-popup-container, #freegifts-main-page-container {
       display: none !important;
     }
   ```

   ```typescript
   type GiftItem = {
       id: number;
       discount_type: 'percentage' | 'fixed_amount';
       discount_value: number;
       original_price: number;  // Original price - price before discount
       price: number;           // Discount price - price after discount
       title: string;
       thumbnail?: string;
   };

   type GiftProduct = {
       id: number;
       title: string;
       handle: string;
       thumbnail?: string;
       belongs_to_offer: string;
       variants: GiftItem[];
   };

   document.addEventListener("fg-gifts:show-slider", (e) => {
       console.log((e as CustomEvent).detail);
       /* render gift slider with detail {
           addGiftToCartFunc: (variant_id: number, quantity: number, offer_id: number) => {};
           gifts?: GiftProduct[]; // show all gifts
           giftsOffer?: { // show gifts by offer
             arrGiftShow: GiftProduct[];
           }
       } */
   });

   ```
3. Details of additional event listeners.

   * `fg-gifts:updated`

   ```typescript
   document.addEventListener("fg-gifts:updated", (e) => {
       /* use this function to re-render cart */
       console.log((e as CustomEvent).detail);
   });
   ```

   > 💡 **Example Available**\
   > 👉 [Layout.tsx](https://github.com/krycek-fengdx/bogos-headless-js/blob/f17a2faab77baa85413af3fa3ad36bf28019d97a/app/components/Layout.tsx#L61)

   * `fg-cart:auto-updated`: Event gift auto add

   ```typescript
   document.addEventListener("fg-cart:auto-updated", (e) => {
       console.log((e as CustomEvent).detail);
   });
   ```

   * `fg-gifts:added`: Event add gift from slider, will not work if you [customize gifts popup](https://file+.vscode-resource.vscode-cdn.net/Users/dongxuanphong/Documents/secomus/secomapp/hydrogen-bogos/freegifts-hydrogen/js-sdk/README.md#customize-popup)

   ```typescript
   document.addEventListener("fg-gifts:added", (e) => {
       console.log((e as CustomEvent).detail);
   });
   ```

   You can log to view detail data

   * `fg-gifts:gift-icon`: Show gift icons
   * `bogos:message`: Show cart message
4. Some features are not yet available on this version yet
   * Draft-Order API
   * Automatic volume discount
   * Bundle page button block
   * Some Shopify object-based params (if only id provided, BOGOS will fetch the rest).

## Notice <a href="#notice" id="notice"></a>

### Publish Gift/Cloned Products <a href="#publish-giftcloned-products" id="publish-giftcloned-products"></a>

* After creating or editing an offer, ensure that the gift/cloned product is published to your Headless channel (or any channel where you want BOGOS to run).

### Additional Customization <a href="#additional-customization" id="additional-customization"></a>

* For deeper customization, please contact our support team.

## Support <a href="#support" id="support"></a>

[BOGOS: Free Gift](https://apps.shopify.com/freegifts) - <help@bogos.io>

OR

You can also reach our live chat support directly within the app from your Shopify Admin.
