> For the complete documentation index, see [llms.txt](https://docs.customerglu.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.customerglu.com/sdk/js-web-sdk.md).

# Web SDK

{% embed url="<https://youtu.be/0FUzm06InmM>" %}

## Installation

Paste the given snippet in your website’s HTML file just before closing the body (`</body>` ) tag.

```html
<script type="text/javascript">
      window["gluConfig"] = {
        writeKey: "{{WRITE_KEY}}",  //provided by CustomerGlu
        userIdentification: {
          userId: "{{USER_ID}}",
          anonymousId: "{{ANONYMOUS_ID}}",
          userToken: "TOKEN" //using this will make writeKey optional
        },
        userAttributes: {
          gluAttributes: {},        //add CG reserved user properties here (key-value pair)
          customAttributes: {}      //add all your custom user properties here (key-value pair) 
        },
        onLoadError: function () {  //error handling function if SDK fails to load
          console.log("error"); 
        }
      };
</script>

<script type="text/javascript">
  (()=>{"use strict";!function(){const e=window.gluConfig||{},t=[],o={open:{returnPromise:!0,callMethod:"open"},close:{returnPromise:!1,callMethod:"close"},register:{returnPromise:!1,callMethod:"register"},listenToAnalytics:{returnPromise:!1,callMethod:"listenToAnalytics"},getCampaignDetails:{returnPromise:!0,callMethod:"getCampaignDetails"}},r=["open","close","register","listenToAnalytics","getCampaignDetails"],n={};for(let e=0;e<r.length;e++)n[r[e]]=function(){const n=o[r[e]],s=Array.prototype.slice.call(arguments);if(n.returnPromise)return new Promise(((e,o)=>{t.push({callMethod:n.callMethod,arguments:s.concat({resolve:e,reject:o}),isPromise:!0})}));t.push({callMethod:n.callMethod,arguments:s})};let s=document.createElement("script");s.type="text/javascript",s.async=!0,s.src="https://assets.customerglu.com/scripts/sdk/v4.6/sdk.js",s.onload=function(){const o=new window.CustomerGlu(e.writeKey,e.userIdentification,e.userAttributes);for(let e=0;e<t.length;e++)o[t[e].callMethod](...t[e].arguments);window.glu=o},s.onerror=function(){if(t&&t.length){for(let e=0;e<t.length;e++)t[e].isPromise&&t[e].arguments[t[e].arguments.length-1]("GLU_SDK_LOAD_ERROR");e.onLoadError&&e.onLoadError()}},document.getElementsByTagName("body")[0].appendChild(s),window.glu=n}()})();
</script>
```

{% hint style="warning" %}
Replace the variables with correct values.
{% endhint %}

You are now ready to load CustomerGlu UI on your website. You can now use:

* The Nudges section on the dashboard to add dynamic entrypoints like floating launchers, popups, banners, etc.
* The subsequent SDK Functionality to programmatically load campaigns.

## Functionality

On pasting the above script, a global instance `glu` will be available in the window.

The `glu` instance supports the given methods:

## Register User

Use the given method to register a user with CustomerGlu:

```typescript
glu.register(writeKey: string, userIdentification: IUserIdentification, userAttributes: IUserAttributes);
```

:warning: `writeKey` is a string that will be provided by CustomerGlu.

`UserIdentification` follows the given structure:

```typescript
interface IUserIdentification {
  userId?: string;
  anonymousId?: string;
}
```

* If the user is not logged in the platform, `userId` can be null, and `anonymousId` can be passed (an anonympusId will be auto-assigned if not passed explicitly). User progress/state of the campaigns will be linked to the anonymousId
* After the user logs in, the same `anonymousId` and the `userId` can be passed. And progress linked to `anonymousId` will be linked with the `userId`. If user is already logged in, userId can be passed directly.

:warning: At least one function call with both - anonymousId and userId is required to map the anonymousId to the userId after the user logs in.

* `UserAttributes` are used for segmentation. They follow the given structure:

```typescript
interface IUserAttributes {
  gluAttributes?: {
    userName?: string;
    appVersion?: string;
    deviceType?: string;
    deviceName?: string;
    deviceId?: string;
    firebaseToken?: string;
  };
  customAttributes?: {
    [key: string]: string | number;
  };
}
```

* `customAttributes` can hold any extra key-value pair that might be used for user segmentation/other purposes. Example: {"location":"Mumbai""}

## Open

The given function can be used to render CustomerGlu UI fragments on the screen:

```typescript
glu.open(container: IContainer, content: IContent): Promise<string>
```

:warning:  It returns the promise of a string, that can be used to close the UI using [`glu.close`](#2.3-close) method.

#### Function parameters:

* [Container](#containers)
* [Content](#content)

## Containers

* `container` holds the container details. i.e. If the UI is a bottom sheet, pop up or be embedded etc.
* The styling of the container can be customised using the `css` property present in each container type. The container elements are targeted using special class names.
* Different containers can have same class names for styling, but the styles gets scoped to only the targeted container.
* Media queries and your custom CSS variables can also be used inside the string.

All supported `container` types are listed down below:

{% tabs %}
{% tab title="Popup" %}

![](/files/O2G9zUm2BewOEplXxkFA)

#### Code

```typescript
/* interface */
interface IPopUp {
  typeId: "POP_UP";
  css: string;
}

/* example */
const container: IPopUp = {
  typeId: "POP_UP",
  css: `
    .__glu_container {
      border-radius: 10px;
      background-color: #000;
      cursor: pointer;
    }
    .__glu_backdrop {
      background-color: #000;
      opacity: 0.5;
    }
    @media screen and (max-width: 700px) {
      .__glu_container {
          height: 400px;
          width: 40p0x;
      }
    }`
}
```

#### Sandbox

{% embed url="<https://codesandbox.io/embed/m84w8s?hidenavigation=1&module=/index.html&view=Preview>" %}

{% endtab %}

{% tab title="Bottom Sheet" %}
![](/files/6NM8LpoEIygHkHoUMdiv)

#### Code

```typescript
/* interface */
interface IBottomSheet {
  typeId: "BOTTOM_SHEET";
  css: string;
  height: string;         // <- in px or % 
}

/* example */
const container: IBottomSheet = {
  typeId: "BOTTOM_SHEET",
  height: "60%",
  css: `
    .__glu_container {
        border-top-left-radius: 20px;
        border-top-right-radius: 5px;
        background-color: #fff;
    }
    .__glu_backdrop {
	background-color: #000;
          opacity: 0.5;
    }`
}
```

#### Sandbox

{% embed url="<https://codesandbox.io/embed/tmvlg3?hidenavigation=1&module=/index.html&view=Preview>" %}
{% endtab %}

{% tab title="Floating Icon Button" %}
![](/files/N4E24DNQGL47mh6Wl85m)

#### Code

```typescript
/* interface */
interface IIconButton {
  typeId: "ICON_BUTTON";
  css: string;
}

/* example */
const container: IIconButton = {
  typeId: "ICON_BUTTON",
  css: `
    .__glu_container {
	border-radius: 50%;
        background-color: #000;
        cursor: pointer;
    }
    @media screen and (max-width: 450px) {
      .__glu_container {
          height: 40px;
          width: 40px;
      }
    }`
}
```

{% endtab %}

{% tab title="Chat Box" %}

![](/files/4i831Mk8qifxMQW6SkO7)

#### Code

```typescript
/* interface */
interface IChatBox {
  typeId: "CHAT_BOX";
  css: string;
}

/* example */
const container: IChatBox = {
  typeId: "CHAT_BOX",
  css: `
    .__glu_container {
        border-radius: 12px;
        background-color: #000;
        cursor: pointer;
    }
    @media screen and (max-width: 450px) {
        .__glu_container {
            height: 100vh;
            width: 100vw;
          }
    }`
}
```

#### Sandbox

{% embed url="<https://codesandbox.io/embed/fxhdzy?hidenavigation=1&module=/index.html&view=Preview>" %}
{% endtab %}

{% tab title="Embed" %}

![](/files/LCtXIc0qpvsBlRHX6PgD)

#### Code

```typescript
/* interface */
interface IEmbedded {
  typeId: "EMBEDDED";
  css: string;
  elementHookId: string;  // <- HTML elelemt selector (eg: .class, #id, main, body)
}

/* example */
const embedded: IEmbedded = {
  typeId: "EMBEDDED",
  elementHookId: "#app",
  css: `
      .__glu_container {
          width: 500px;
          margin: 0 auto;
          height: 1000px;
          overflow: scroll;
        }`
}
```

:warning: `elementHookId` should be a valid html selector or element on the page. The glu container will be appended inside the that element

#### Sandbox

{% embed url="<https://codesandbox.io/embed/jm6ml7?hidenavigation=1&module=/index.html&view=Preview>" %}
{% endtab %}
{% endtabs %}

## Content

`content` holds details regarding what gets rendered inside the [`container`](#containers).&#x20;

All supported `content` types are listed down below:

{% tabs %}
{% tab title="Wallet" %}

![](/files/K5MSZNoOvYix8hFnszqD)

**Code**

```tsx
/* interface */
interface IWallet {
  typeId: "WALLET";
}

/* example */
const content: IWallet = {
  typeId: string
}
```

####

#### Sandbox

{% embed url="<https://codesandbox.io/embed/9c7vyy?hidenavigation=1&module=/index.html&view=Preview>" %}
{% endtab %}

{% tab title="Campaign" %}

![](/files/JM6FWKXPP680E6PFy9Ea)

#### Code

```tsx
/* interface */
interface ICampaign {
  typeId: "CAMPAIGN";
  conditions: {
    campaignId?: string[];
    type?: "referral" | "gamechallenge" | "streak" | "multistep" | "spinthewheel" | "scratchcard" | "slotmachine" | "giftbox" | "tossthecoin" | "memorygame" | "catchinggame" | "quiz" | "direct" [];     
    status?: "pristine" | "in-progress" | "completed" [];     
  };
}

/* example #1: select a single campaign */
const content: ICampaign = {
  typeId: "CAMPAIGN",
  conditions: {
    campaignId: ["asd283mkla-3890njakd-jkandsk3-kjadnjk3"]
  }
}

/* example #2: select a scratch card if present else a spin the wheel campaign if present */
const content: ICampaign = {
  typeId: "CAMPAIGN",
  conditions: {
    type: ["scratchcard", "spinthewheel"]
  }
}
```

* `conditions` property inside the `ICampaign` is in key-value pair format. Key is the property that needs to be filtered for. Value is an array of acceptable set of values.
* The first campaign that satisfies all the conditions is selected.
* If the campaign is not found, an error `CAMPAIGN_NOT_FOUND` is thrown.

#### Sandbox

{% embed url="<https://codesandbox.io/embed/8r362x?hidenavigation=1&module=/index.html&view=Preview>" %}
{% endtab %}

{% tab title="Static Image" %}

![](/files/kGHRuK2EpZg2BemY2x1q)

#### Code

```tsx
/* interface */
interface IStaticImage {
  typeId: "STATIC";
  src: string;
  action: IAction; // <- on click action
}

/* example #1: on click redirect */
const content: IStaticImage = {
  typeId: "STATIC",
  src: "https://uploads-ssl.webflow.com/60ae16f0e20bce50d40c3c7e/61efce5c2ab738e60fd0856f_Group%2027.png",
  action: {
    type: "REDIRECT",
    data: {
      url: "https://website.com/rewards"
    }
  }
}

/* example #2: on click open wallet in a pop up */
const content: IStaticImage = {
  typeId: "STATIC",
  src: "https://uploads-ssl.webflow.com/60ae16f0e20bce50d40c3c7e/61efce5c2ab738e60fd0856f_Group%2027.png",
  action: {
    type: "TOGGLE_FRAME_CONTENT";
    id: string;
    container: {
      typeId: "POP_UP",
      css: `
        .__glu_container {
	  border-radius: 10px;
          background-color: #000;
          cursor: pointer;
        }
   `},
    content: {
      typeId: "WALLET"
    }
  }
}

/* example #3: on click open a campaign in a bottom sheet */
const content: IStaticImage = {
  typeId: "STATIC",
  src: "https://uploads-ssl.webflow.com/60ae16f0e20bce50d40c3c7e/61efce5c2ab738e60fd0856f_Group%2027.png",
  action: {
    type: "TOGGLE_FRAME_CONTENT";
    id: string;
    container: {
      typeId: "BOTTOM_SHEET",
      css: `
        .__glu_container {
	  border-radius: 10px;
          background-color: #000;
          cursor: pointer;
        }
     `},
    content: {
      typeId: "CAMPAIGN",
      conditions: {
        campaignId: ["asd283mkla-3890njakd-jkandsk3-kjadnjk3"]
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

## Close

The [`glu.open`](#open) method returns a unique string. Following method can be used to close the frame:

```tsx
glu.close(id: string);
```

#### Function parameters:

**id:** unique string returned by [`glu.open`](#open) method

## Get Campaign Details

`glu.getCampaignDetails` can be used to get the campaign details. The result include the campaign details and the **array** of rewards earned for that campaign.

```
glu.getCampaignDetails(filter: IFilter, config: IConfig): Promise<ICampaignDetailsResult>
```

* It accepts 2 arguments: `filter` and `config`
  * `filter` helps in identifying the campaign for which the details are needed.
  * `config` has configurations like: should the reward details also exist with the details of the campaign.

```typescript
/* filter interface */   
interface ICampaingDetailsFilter {
  campaignId?: (string | boolean | number)[] | string;
  [key: string]: (string | boolean | number)[] | string;
}

/* config interface */   
interface ICampaingDetailsConfig {
  includeRewards: boolean;
}

/* RESULT interface */ 
interface ICampaignDetailsResult {
  details: {
	  campaignId: string;
	  status: "pristine" | "completed";
	  type: string;
	  url: string;
	  banner?: any;
	};
  rewards?: {
	  game_name?:
	    | "spinthewheel"
	    | "memorygame"
	    | "scratchcard"
	    | "slotmachine"
	    | "quiz"
	    | "direct"
	    | "giftbox"
	    | "not_available"
	    | "swipeui"
	    | "tossthecoin"
	    | "unitygame"
	    | "rollthedice";
	  state?: "pristine" | "complete" | "expired" | "not_available";
	  campaign_id?: string;
	  reward_user_id?: string;
	  user_id?: string;
	  status?: string;
	  selected_slot_index?: number | "not_available";
	  reward_name?: string;
	  reward_type?: string;
	  code?: string;
	  reward_amount?: string | number;
	  details?: { [key: string]: string } | "not_available";
	}[];
}

/* example */
glu
   .getCampaignDetails(
      { campaignId: "f8cca67-596e-4b28-a173-8a018cdb2cf8" },
      { includeRewards: true }
    )
    .then((res) => {
      document.querySelector("#app").textContent = JSON.stringify(res);
    }).catch(err => console.log(err));
```

{% embed url="<https://codesandbox.io/embed/jfk7mn?hidenavigation=1&module=/index.html&view=Preview>" %}

## Listen to Analytics

You can listen to the analytics events triggered from the glu ui by registering a callback with the SDK’s `addAnalyticsListener` method.

```typescript
glu.addAnalyticsListener(listener: (analyticsEvent: any) => void)
```

* `glu.addAnalyticsListener` accepts a callback function as an argument. & whenever an analytics event is triggered, it is passed on to the callback as the first argument.
* Schema can be found here:<https://docs.customerglu.com/schema/analytics-schema-v4>
