# 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>


---

# 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.customerglu.com/sdk/js-web-sdk.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.
