npm package: @stackchat/web-messenger
Description: Web chat client for the Stackchat Conversation Platform
Author: stackchat
Latest version: 2.3.6-ruby-4

# Stackchat Web Messenger

The Stackchat Web Messenger adds your Stackchat chat app to your website.

# Table of Contents

1. [Usage](#usage)
   - [Script](#script)
   - [NPM](#npm)
2. [Browser Support](#browser-support)
   - [Desktop](#desktop)
   - [Mobile](#mobile)
   - [Other Browsers](#other-browsers)
   - [Voice Support](#voice-support)
3. [API](#api)
   - [Individual Functions](#individual-functions)
   - [Delegates](#delegates)
   - [Events](#events)
   - [Embedded Mode](#embedded-mode)
4. [Proactive Messaging](#proactive-messaging)
5. [Content Security Policy](#content-security-policy)
6. [Acknowledgements](#acknowledgements)

# Usage

## Script

Add the following code towards the end of the `head` section on your page.

```html
<script async="true">
  !function(s,e,a){var c,o,i,p=[],u=[];s[a]={init:function(){c=arguments;var t={then:function(e){return u.push({type:"t",next:e}),t},catch:function(e){return u.push({type:"c",next:e}),t}};return t},on:function(){p.push(arguments)},render:function(){o=arguments},destroy:function(){i=arguments}},s.__onWebMessengerHostReady__=function(e){if(delete s.__onWebMessengerHostReady__,s[a]=e,c)for(var t=e.init.apply(e,c),n=0;n<u.length;n++)var r=u[n],t="t"===r.type?t.then(r.next):t.catch(r.next);o&&e.render.apply(e,o),i&&e.destroy.apply(e,i);for(n=0;n<p.length;n++)e.on.apply(e,p[n])};var t="2.3.6-ruby-4",n=e.getElementsByTagName("script")[0],e=e.createElement("script");e.async=!0,e.src="https://assets.au.stackchat.com/sdk/web-messenger/"+t+"/stackchat."+t+".min.js",n.parentNode.insertBefore(e,n)}(window,document,"stackchat");
</script>
```

And then, initialise the Web Messenger by placing the following code towards the end of the `body` section of your page:

```html
<script>
  stackchat
    .init({
      appId: "<app-id>"
    })
    .then(function () {
      // YOUR CODE AFTER INIT IS COMPLETE
    });
</script>
```

> **Note for users in China**
> If you are using the Stackchat Web Messenger on a Chinese website, then you will need to replace the loader URL in the above script. Please replace `https://assets.au.stackchat.com` with our China CDN: `https://assets.common.stackchat.com.cn`. You will also need to add a `region: "cn"` key/value to your config (along with your app id) that you pass in the `init` method.

## NPM

1. Install via `npm` or a package manager of choice:

```sh
npm install --save @stackchat/web-messenger
```

2. Import the module & initialise messenger

```javascript
import Stackchat from "@stackchat/web-messenger";

Stackchat.init({ appId: "<app-id>" }).then(function () {
  // YOUR CODE AFTER INIT IS COMPLETE
});
```

# Browser Support

Stackchat Web Messenger supports all the popular browsers

## Desktop

- **Chrome** : Latest and one major version behind
- **Edge** : Latest and one major version behind
- **Firefox** : Latest and one major version behind
- **Internet Explorer** : 11+
- **Safari** : Latest and one major version behind

## Mobile

- Stock browser on Android 4.1+
- Safari on iOS 8+

## Other Browsers

Stackchat Web Messenger is likely compatible with other and older browsers but we only test against the versions above.

## Voice Support

Stackchat Web Messenger supports speech recognition where available. This is essentially limited to browsers that have implemented the [W3C Media Stream API](https://www.w3.org/TR/mediacapture-streams/#stream-api) and where access to a recording instrumentation on a device is available. For this reason, if you are using speech recognition, please be aware that there may be compatibility issues with older browsers.

# API

## Individual Functions

### `init(options)`

Initializes the Stackchat Web Messenger widget in the web page using the specified options. It returns a promise that will resolve when the Web Messenger is ready. **Note** that except `on` and `off`, all other methods need to be called **after** a successful `init`.

### `options`

| Option                           | Optional? | Default value                    | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| -------------------------------- | --------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| appId                            | No        | -                                | Your app id                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| voice                            | Yes       | -                                | See `voice` section [below](#voice)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| locale                           | Yes       | `en-US`                          | Locale used for date formatting using the `<language>-<COUNTRY>` format. Language codes can be found [here](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) and country codes [here](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). <br /> **Note 1 : ** The country part is optional, and if a country is either not recognized or supported, it will fallback to using the generic language. If the language isn't supported, it will fallback to `en-US`. <br /> **Note 2:** this is _only_ used for date formatting and doesn't provide built-in translations for Web Messenger. |
| soundNotificationEnabled         | Yes       | `true`                           | Enables the sound notification for new messages                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| imageUploadEnabled               | Yes       | `true`                           | Enables the image upload feature. (deprecated: use menuItems.imageUpload; if this option is `false`, it will disable `menuItems.imageUpload` and `menuItems.fileUpload`)                                                                                                                                                                                                                                                                                                                                                                                                                        |
| fixedIntroPane                   | Yes       | `false`                          | When enabled, the introduction pane will be pinned at the top of the conversation instead of scrolling with it.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| embedded                         | Yes       | False                            | Tells the widget it will be embedded. (see Embedded section below)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| displayStyle                     | Yes       | `button`                         | Choose how the messenger will appear on your website. Must be either `button` or `tab`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| buttonIconUrl                    | Yes       | -                                | When the `displayStyle` is `button`, you have the option of selecting your own button icon. The image must be at least 200 x 200 pixels and must be in either JPG, PNG, or GIF format.                                                                                                                                                                                                                                                                                                                                                                                                          |
| buttonWidth                      | Yes       | `58px`                           | When the `displayStyle` is `button`, you have the option of specifying the button width.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| buttonHeight                     | Yes       | `58px`                           | When the `displayStyle` is `button`, you have the option of specifying the button height.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| businessName                     | Yes       | -                                | A custom business name.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| businessIconUrl                  | Yes       | -                                | A custom business icon url. The image must be at least 200 x 200 pixels and must be in either JPG, PNG, or GIF format.                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| backgroundImageUrl               | Yes       | -                                | A background image url for the conversation. Image will be tiled to fit the window.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| integrationOrder                 | Yes       | -                                | Array of integration IDs. When set, only integrations from this list will be displayed. If an empty array is used, no integrations will be displayed. _Note_: Listing an integration in the array doesn't guarantee that it will be displayed in the Web Messenger.                                                                                                                                                                                                                                                                                                                             |
| customColors                     | Yes       | See [below](#customColors)       | Colors used in the Web Messenger UI.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| customText                       | Yes       | See [below](#customText)         | Strings used in the Web Messenger UI. You can use these to either customize the text or translate it. _Note_: Some strings include variables (surrounded by `{}`) which must remain in your customized text.                                                                                                                                                                                                                                                                                                                                                                                    |
| menuItems                        | Yes       | See below.                       | Choose menu items.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| notificationChannelPromptEnabled | Yes       | `true`                           | Enables displaying a prompt to new users after their first message to suggest linking their chat instance with their other 3rd-party apps.                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| proactiveMessaging               | Yes       | See [below](#proactiveMessaging) | Let's you choose how proactive messaging content appears within the messenger                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |

### `proactiveMessagging`

| Option                | Optional? | Default value | Description                                                                                                        |
| --------------------- | --------- | ------------- | ------------------------------------------------------------------------------------------------------------------ |
| `ttl`                 | Yes       | 2000          | The amount of time each message should live on the screen in milliseconds. By default, its 2s i.e. 2000ms          |
| `author`              | No        | -             | The name displayed at the top of each message. This is what will be used as author name for each proactive message |
| `maxMessages`         | No        | -             | The maximum number of messages that are displayed on the screen at any given time. By default, it is 3             |
| `singularCloseButton` | No        | -             | Determines whether to show one close button for all messages or one for each message                               |

### `customColors`

| Option            | Optional? | Default value | Description                                                                                                                           |
| ----------------- | --------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| brandColor        | Yes       | `65758e`      | This color will be used in the messenger header and the button or tab in idle state. Must be a 3 or 6-character hexadecimal color.    |
| conversationColor | Yes       | `0099ff`      | This color will be used for customer messages, quick replies and actions in the footer. Must be a 3 or 6-character hexadecimal color. |
| actionColor       | Yes       | `0099ff`      | This color will be used for call-to-actions inside your messages. Must be a 3 or 6-character hexadecimal color.                       |

### `customText`

The list of localizable strings. These strings can be modified. _If an option is not given a custom string, the default value will be used._

| Option                              | Default value                                                  |
| ----------------------------------- | -------------------------------------------------------------- |
| clickToRetry                        | Message not delivered. Click to retry.                         |
| connectNotificationText             | Be notified inside your other apps when you get a reply.       |
| connectNotificationSingleText       | Be notified when you get a reply.                              |
| connectNotificationSingleButtonText | Turn on `<name>` notifications                                 |
| connectNotificationOthersText       | others                                                         |
| conversationTimestampHeaderFormat   | MMMM D YYYY, h:mm A                                            |
| fetchHistory                        | Load more                                                      |
| fetchingHistory                     | Retrieving history...                                          |
| headerText                          | How can we help?                                               |
| imageClickToReload                  | Click to reload image.                                         |
| imageClickToView                    | Click to view {size} image.                                    |
| imagePreviewNotAvailable            | Preview not available.                                         |
| inputPlaceholder                    | Type a message...                                              |
| introAppText                        | Message us below or from your favorite app.                    |
| introductionText                    | We\'re here to talk, so ask us anything!                       |
| messageError                        | An error occured while sending your message. Please try again. |
| messageIndicatorTitlePlural         | (`{count}`) New messages                                       |
| messageIndicatorTitleSingular       | (`{count}`) New message                                        |
| messageRelativeTimeDay              | `{value}`d ago                                                 |
| messageRelativeTimeHour             | `{value}`h ago                                                 |
| messageRelativeTimeJustNow          | Just now                                                       |
| messageRelativeTimeMinute           | `{value}`m ago                                                 |
| messageTimestampFormat              | h:mm A                                                         |
| messageSending                      | Sending...                                                     |
| messageDelivered                    | Delivered                                                      |
| sendButtonText                      | Send                                                           |
| settingsHeaderText                  | Settings                                                       |
| tapToRetry                          | Message not delivered. Tap to retry.                           |
| unsupportedMessageType              | Unsupported message type.                                      |
| unsupportedActionType               | Unsupported action type.                                       |
| voiceConnecting                     | Please wait...                                                 |
| voiceListening                      | I'm listening...                                               |
| voiceNoSpeechDetected               | No speech detected.                                            |
| voiceNoMicrophoneAccess             | Microphone access disabled.                                    |

See below for an example:

```javascript
var initPromise = stackchat
  .init({
    appId: "<app-id>",
    // Leave unspecified for US region (default)
    region: "au",
    // For authenticated mode
    jwt: "your_jwt",
    userId: "user_id",
    locale: "en-US",
    customColors: {
      brandColor: "65758e",
      conversationColor: "65758e",
      actionColor: "65758e"
    },

    fixedIntroPane: false,

    customText: {
      clickToRetry: "Message not delivered. Click to retry.",
      connectNotificationText:
        "Be notified inside your other apps when you get a reply.",
      connectNotificationSingleText: "Be notified when you get a reply.",
      connectNotificationSingleButtonText: "Turn on <name> notifications",
      connectNotificationOthersText: "others",
      conversationTimestampHeaderFormat: "MMMM D YYYY, h:mm A",
      fetchHistory: "Load more",
      fetchingHistory: "Retrieving history...",
      headerText: "How can we help?",
      imageClickToReload: "Click to reload image.",
      imageClickToView: "Click to view {size} image.",
      imagePreviewNotAvailable: "Preview not available.",
      inputPlaceholder: "Type a message...",
      introAppText: "Message us below or from your favorite app.",
      introductionText: "We're here to talk, so ask us anything!",
      messageError:
        "An error occured while sending your message. Please try again.",
      messageIndicatorTitlePlural: "({count}) New messages",
      messageIndicatorTitleSingular: "({count}) New message",
      messageRelativeTimeDay: "{value}d ago",
      messageRelativeTimeHour: "{value}h ago",
      messageRelativeTimeJustNow: "Just now",
      messageRelativeTimeMinute: "{value}m ago",
      messageTimestampFormat: "h:mm A",
      messageSending: "Sending...",
      messageDelivered: "Delivered",
      sendButtonText: "Send",
      settingsHeaderText: "Settings",
      tapToRetry: "Message not delivered. Tap to retry.",
      unsupportedMessageType: "Unsupported message type.",
      unsupportedActionType: "Unsupported action type."
    }
  })
  .then(function () {
    // Your code after init is complete
  });

initPromise.then(function () {
  // do something
});

// pass it around...

initPromise.then(function () {
  //do something else
});
```

### `voice`

The web-messenger will support Speech Recognition if the service has been made available to the user, to enable it there is a voice configuration object that can be passed in by the user to the init method.

| Option              | Optional? | Default value | Description                                                                                                                                                                                                                      |
| ------------------- | --------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| voiceOnly           | Yes       | `false`       | Disables the text input and replaces it with a push to talk button                                                                                                                                                               |
| voiceOnlyFallback\* | Yes       | `text`        | If voice only is set to true and the client device does not support voice then this option will handle what to do for those unsupported devices, options are `text`, `destroy` or a function that returns either of those values |
| locale              | Yes       | en_us         | Set the voice support language, must conform to BCP-47                                                                                                                                                                           |

- **`voiceOnlyFallback`** - The two options for fallback are `text` or `destroy`, the `text` fallback will revert the application to a basic keyboard based input, while `destroy` will fail the initialization of the app and prevent the widget from being instantiated, this option is for users that only want to support voice and display nothing in all other instances.

### `open()`

Opens the conversation widget (no-op when embedded)

```javascript
stackchat.open();
```

### `close()`

Closes the conversation widget (no-op when embedded)

```javascript
stackchat.close();
```

### `isOpened()`

Tells if the widget is currently opened or closed.

```javascript
stackchat.isOpened();
```

### `destroy()`

Destroys the Web Messenger and makes it disappear. The Web Messenger has to be reinitialized with `init` to be working again because it also clears up the app id from the Web Messenger. It will also unbind all listeners you might have with `stackchat.on`.

```javascript
stackchat.destroy();
```

### `sendMessage(message)`

Sends a message on the user's behalf

```javascript
stackchat.sendMessage({
  type: "text",
  text: "hello"
});

// OR

stackchat.sendMessage("hello");
```

### `getConversation()`

Returns the conversation if it exists

```javascript
var conversation = stackchat.getConversation();
```

### `getUser()`

Returns a user if the conversation has begun and a user has been created, otherwise returns `undefined`

```javascript
var user = stackchat.getUser();

if (user) {
  // Do something with user data.
}
```

### `startConversation()`

Creates a user and conversation on the server, allowing the business to reach out proactively to the user via the public API.

It is strongly recommended to only call this method in the case where a message is likely to be sent.

This method is called automatically when starting a conversation via the `sendMessage` method, or when a user sends a message via the conversation view.

If a conversation already exists for the current user, this call is a no-op.

```javascript
stackchat.startConversation();
```

### `setPredefinedMessage(message)`

Prefills the user's chat input with a predefined message.

```javascript
stackchat.setPredefinedMessage(message);
```

### `simulateMessage(message, ?avatar)`

Simulates a message to the client without ever sending one to the server, these messages will not be persisted between sessions.

Takes in an optional second parameter for displaying an avatar associated with the message, this will default to gravatar's empty gray user icon if left blank.

```javascript
stackchat.simulateMessage(message);
```

### `simulateMessage(messageObject, ?avatar)`

Simulates a message which has specified predefined reply options.

```javascript
stackchat.simulateMessage({
  message: "Would you like an ice cream?",
  actions: ["Yes", "No"]
});
```

### `triggerCloudFunction(handler, payload, ?metadata)`

Manually invoke a Stackchat cloud function on the users behalf.

```javascript
stackchat
  .triggerCloudFunction("populateSlots", getUserPayload(), {})
  .then(() => {
    console.log("cloud function invoked");
  });
```

### `showActivityIndicator(?avatar)`

Simulates the behaviour of the bot typing. Shows up as flickering three dots in a message bubble.

### `hideActivityIndicator()`

Removes the typing indicator from the conversation so that the conversation may proceed.

### `openSpeechRecognitionModal()`

Opens up the user speech recognition prompt and begins listening for a user command, this can't be called before the messenger client has finished it's initialisation.

```javascript
stackchat.init({...}).then(() => {
    document.getElementById("open-modal").addEventListener("click", () => {
        stackchat.openSpeechRecognitionModal();
    });
})
```

### `closeSpeechRecognitionModal()`

Closes the modal and aborts the current recognition event

```javascript
stackchat.closeSpeechRecognitionModal();
```

### `setDelegate(delegate)`

See the section on [Delegates](#delegates) below

### `updateAnalyticsId`

By default, a user's unique Stackchat ID will be used when your chatbot sends server-side requests to your configured analytics integrations. However, you may want to override this behaviour so that Stackchat uses a different ID, such as the visitor ID that your website has assigned to the user. This is helpful to get a single view of user behaviour across both website and chatbot.

**Adobe Analytics**

If you've configured Adobe Analytics report suite for your Stackchat bot, then you can call `updateAnalyticsId` method with the below parameter in order to override the visitor ID that your chatbot uses when making server-side requests to Adobe Analytics. If you have server-side forwarding to Adobe Audience Manager configured, then you need to include the `regionId`, otherwise it is not required

```javascript
stackchat.updateAnalyticsId({
  adobeAnalytics: {
    experienceCloudVisitorId: "ENTER_YOUR_VISITOR_ID_HERE",
    regionId: "ENTER_YOUR_REGION_ID_HERE"
  }
});
```

- Populate `experienceCloudVisitorId` property with a value fetched from [getMarketingCloudVisitorId](https://docs.adobe.com/content/help/en/id-service/using/id-service-api/methods/getmcvid.html)
- Populate `regionId` property with a value fetched from [getLocationHint](https://docs.adobe.com/content/help/en/id-service/using/id-service-api/methods/getlocationhint.html)
- **Note**: One API call is made to Adobe Analytics for every message received from the user.

### `hasConversationStarted()`

Returns a boolean that when true indicates the a user has previously started a conversation and false when they have not, this is useful for those times when you might want to execute some behaviours depending on whether a user has or has not interacted with the widget yet.

```javascript
const hasStarted = stackchat.hasConversationStarted();

if (hasStarted) {
  // Conversation started, do something...
} else {
  // Converstaion not yet started, do something...
}
```

## Delegates

Stackchat Web Messenger allows you to set a delegate to receive callbacks when important changes happen in the conversation. To set a delegate, use the following `setDelagate` method:

```javascript
stackchat.setDelegate(delegate);
```

Delegates should be set after `stackchat.init` has been called, like so:

```javascript
stackchat.init({ appId: '<app-id>' })
  .then(
    () => {
      stackchat.setDelegate(...)
    }
  )
```

You can use the one or more of the following delegates:

### `beforeDisplay`

The `beforeDisplay` delegate allows a message to be hidden or modified before it is displayed in the conversation. This delegate should return a falsy value such as `null` to hide the message. It can also return a modified message object in order to change what the user will see rendered in their conversation history. **Note** that this change affects the client side rendering only; the server side copy of this message can not be modified by this delegate.

```javascript
stackchat.setDelegate({
  beforeDisplay(message) {
    if (message.metadata && message.metadata.isHidden) {
      return null;
    }

    return message;
  }
});
```

### `beforeSend`

The `beforeSend` delegate method allows you to modify properties of a message before sending it to stackchat. **The modified message must be returned for it to take effect.**

```javascript
stackchat.setDelegate({
  beforeSend(message) {
    // YOUR CODE HERE

    return modifiedMessage;
  }
});
```

### `beforePostbackSend`

The `beforePostbackSend` delegate method allows you to modify properties of a postback before sending it to stackchat. **The modified postback must be returned for it to take effect.**

```javascript
stackchat.setDelegate({
  beforePostbackSend(postback) {
    postback.metadata = {
      any: "info"
    };
    return postback;
  }
});
```

### `beforeWebviewDisplay`

```javascript
stackchat.setDelegate({
  beforeWebviewDisplay(url, message, event) {
    console.log(url);
    return false; // to cancel action
    // return;    // to allow original behavior, e.g. a no-op
    // return 'http://go.here.instead.com?utm=webviewIntercept' // to replace the URL
  }
});
```

The `metadata` parameter has the following structure:

```javascript
metadata = {
  event // The click event from the browser
};
```

## Events

To bind an event, use `stackchat.on(<event name>, <handler>);`. To unbind events, you can either call `stackchat.off(<event name>, handler)` to remove one specific handler, call `stackchat.off(<event name>)` to remove all handlers for an event, or call `stackchat.off()` to unbind all handlers.

**Note**: If you want to make sure your events are triggered, try to bind them before calling `stackchat.init`, like so:

```javascript
stackchat.on('<event-1>', function() { ... });
stackchat.on('<event-2>', function() { ... });
stackchat.on('<event-3>', function() { ... });

stackchat.init(...).then(function() {
    // Your code after init is complete
});
```

### `ready`

This event triggers when init completes successfully

```javascript
stackchat.on("ready", function () {
  console.log("the init has completed!");
});
```

### `destroy`

This event triggers when the widget is destroyed.

```javascript
stackchat.on("destroy", function () {
  console.log("The widget is destroyed!");
});
```

This is triggered in response to `stackchat.destroy()`

### `message:received`

This event triggers when the user receives a message

```javascript
stackchat.on("message:received", function (message) {
  console.log("The user received a message", message);
});
```

### `message:sent`

This event triggers when the user sends a message

```javascript
stackchat.on("message:sent", function (message) {
  console.log("The user sent a message", message);
});
```

### `message`

This event triggers when a message was added to the conversation

```javascript
stackchat.on("message", function (message) {
  console.log("A message was added to the conversation", message);
});
```

### `unreadCount`

This event triggers when the number of unread messages changes

```javascript
stackchat.on("unreadCount", function (unreadCount) {
  console.log("The number of unread messages was updated", unreadCount);
});
```

### `widget:opened`

This event triggers when the widget is opened

```javascript
stackchat.on("widget:opened", function () {
  console.log("Widget is opened!");
});
```

### `widget:closed`

This event triggers when the widget is closed

```javascript
stackchat.on("widget:closed", function () {
  console.log("Widget is closed!");
});
```

### `speech:start`

This event triggers when the widget starts recording voice input

```javascript
stackchat.on("speech:start", function () {
  console.log("Widget is recording now!");
});
```

### `speech:end`

This event triggers when the widget stops recording voice input

```javascript
stackchat.on("speech:end", function () {
  console.log("Widget has stopped recording now!");
});
```

### `speech:error`

This event triggers when the widget encounters an error while recording voice input

```javascript
stackchat.on("speech:error", function (error) {
  console.log(error.type, error.message);
});
```

## Embedded Mode

As describe above, to activate the embedded mode, you need to pass `embedded: true` when calling `stackchat.init`. By doing so, you are disabling the auto-rendering mechanism and you will need to call `stackchat.render` manually. This method accepts a DOM element which will be used as the container where the widget will be rendered.

The embedded widget will take full width and height of the container. You must give it a height, otherwise, the widget will collapse.

# Proactive Messaging

## Introduction

This feature allows you to handle the creation, display and manipulation of messages that are proactively displayed to the user. A user can also interact with these messages eliminating the need of guesswork from the user.

Proactive messages can be triggered automatically during an ongoing conversation in the Stackchat Web Messenger or can be manually triggered as the need arises.

Each proactive message looks like this(_when default styles are used_)

<img alt="Proactive Message" src="https://github.com/stackchat-ai/proactive-messaging/blob/v1.0.5/assets/proactive-message.png?raw=true" width="250" id="proactive-message-without-actions">

or like this with actions:

<img alt="Proactive Message With Actions" src="https://github.com/stackchat-ai/proactive-messaging/blob/v1.0.5/assets/proactive-message-with-actions.png?raw=true" width="250" id="proactive-message-with-actions">

**Note**: Proactive messages are only displayed **if and only if** the messenger widget is not open. If it is open, then all the proactive messages are silently ignored.

### Example

```javascript
// Initialise Web Messenger
Stackchat.init({
  // ...config
  proactiveMessaging: {
		ttl: 4000 // default
		author: "Test Bot"
  }
})
```

## API

### Initialisation Options

See the configuration object at the top for more details.

### Configuring a Proactive Message

As long as the messenger widget is not open, `ProactiveMessaging` any message containing the `proactive` property in its `metadata` that has been set to `true` will displayed proactively.

```javascript
// Therefore the message object should look like this
message = {
  metadata: {
    proactive: true,
    ...otherMetaProps
  },
  ...otherMessageProps
};
```

### Methods

- `addProactiveMessage({text, persona, quickReplies})`

Allows the developer to simulate or display a proactive message to the user without it becoming a part of the ongoing conversation.

For e.g.

```javascript
// Without actions
stackchat.addProactiveMessage({ text: "Hello, world!" });

// With actions
stackchat.addProactiveMessage({
  text: "Hello, world!",
  quickReplies: [
    {
      text: "Hello there!",
      openMessengerOnReply: false
    },
    {
      text: "Hi! What are you up to?",
      openMessengerOnReply: true
    }
  ]
});
```

### Event Binding

`ProactiveMessaging` offers two special methods to allow developers to react to events as they occur.

**Note:** You can add and remove event binding at any time.

- `on(event, handler)`

  Allows you to specify a callback for a event which is called when that aforesaid event occurs.

- `off(event?, handler?)`

  Allows you to remove a callback tied to an event. If no handler is specfied, it removes all the callbacks associated with the event. If no event has been specified, all callbacks for all events are cleared.

#### Events

This is the list of events that you can use with `on` and `off` methods as described above.

- `ready`

  This event is fired when your `ProactiveMessaging` instance is ready. From this point on, it can start displaying proactive messages.

  ```js
  stackchat.on("ready", () => {
    console.log("Proactive Messaging is ready!");
  });
  ```

- `proactive-message:clicked`

  This event is fired when a user clicks on a proactive message. This event is **not** fired when a user dismisses a message or clicks on a quick reply.

  ```js
  stackchat.on("proactive-message:clicked", (event) => {
    console.log("Proactive Message clicked > message", event.message);
  });
  ```

- `proactive-message:dismissed`

  This event is fired when a user dismisses a proactive message. It is not fired if the message auto dismisses after the `ttl`.

  ```js
  stackchat.on("proactive-message:dismissed", (event) => {
    console.log("Proactive Message dismissed > message", event.message);
  });
  ```

- `quick-reply:clicked`

  This event is fired when a user clicks on one of the quick replies in a proactive message.

  ```js
  stackchat.on("quick-reply:clicked", (event) => {
    console.log("Quick reply clicked");
    console.log("Message", event.message);
    console.log("Quick reply", event.quickReply);
  });
  ```

- `messenger:opened`

  This event is fired whenever the Stackchat Web Messenger is opened by your `ProactiveMessaging` instance. Stackchat Web Messenger is opened when a user clicks on a message or clicks on one of the quick replies. Refer to the first part of the [API](#api) section above.

  ```js
  stackchat.on("messenger:opened", () => {
    console.log("Stackchat Web Messenger opened");
  });
  ```

- `clear`

  This event is fired when all the proactive messages have been cleared - by user interaction or otherwise. Consider this as a blank slate similar to right after the `ready` event has occured.

  ```js
  stackchat.on("clear", () => {
    console.log("All proactive messages cleared!");
  });
  ```

## Styling

### Default Styles

This library includes some base styles that display proactive messages in the nice UI as shown above [here](#proactive-message-without-actions) and [here](proactive-message-with-actions).

Consuming default styles depends on the way you integrate this library:

- **Script**

  You can use our CDN hosted stylesheet via a `script` tag

  ```html
  <link
    type="text/css"
    src="https://assets.au.stackchat.com/sdk/proactive-messaging/1.0.4/main.css"
  />
  ```

- **Package Manager**

When using a package manager like `npm` or `yarn`, the default styling is already included within the messenger project. In instances where you want to povide additional styles or override certain styles belonging to proactive messaging classes take a look at the [custom styles](#custom-styles) section below to learn more about applying your specific styles to the proactive messages.

### Custom Styles

The following css sheet is the complete list of proactive messaging styles available, you can extends or override any of these by simply adding your own styles using the same class names, just ensure that your stylesheet is loaded after this sheet has been injected into the head of your document.

```css
.stackchat__proactive-container {
  overflow-y: hidden;
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
  flex-direction: column;
  z-index: 9998;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
.stackchat__proactive-container * {
  outline: none;
}
.stackchat__proactive-container .stackchat__external-close-button {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background-color: #d8d8d8;
  cursor: pointer;
}
.stackchat__proactive-container .stackchat__proactive-message {
  margin-bottom: 8px;
  padding: 4px;
}
.stackchat__proactive-container
  .stackchat__proactive-message
  .stackchat__message {
  background-color: white;
  border-radius: 8px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
  box-shadow: 0 0 4px 1px rgba(0, 0, 0, 0.2);
  width: 232px;
}
.stackchat__proactive-container
  .stackchat__proactive-message
  .stackchat__message
  .stackchat__header {
  position: relative;
  width: 100%;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: flex-start;
}
.stackchat__proactive-container
  .stackchat__proactive-message
  .stackchat__message
  .stackchat__header
  .stackchat__name {
  margin: 0;
  margin-left: 16px;
  margin-right: 8px;
  font-weight: 600;
  font-size: 14px;
  color: #4c0099;
}
.stackchat__proactive-container
  .stackchat__proactive-message
  .stackchat__message
  .stackchat__header
  .stackchat__close-button {
  position: absolute;
  right: 0;
  top: 0;
  width: 40px;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: transparent;
  border: none;
  cursor: pointer;
}
.stackchat__proactive-container
  .stackchat__proactive-message
  .stackchat__message
  .stackchat__content {
  padding: 8px 16px 16px 16px;
}
.stackchat__proactive-container
  .stackchat__proactive-message
  .stackchat__message
  .stackchat__content
  .stackchat__text {
  margin: 0;
  font-size: 14px;
}
.stackchat__proactive-container
  .stackchat__proactive-message
  .stackchat__actions {
  margin-top: 4px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
}
.stackchat__proactive-container
  .stackchat__proactive-message
  .stackchat__actions
  .stackchat__action {
  background: rgba(76, 0, 153, 0.1);
  box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
  border: 1px solid #4c0099;
  border-radius: 4px;
  margin: 2px 0 2px 4px;
  font-size: 14px;
  padding: 11px;
  min-width: 64px;
  font-weight: 600;
  cursor: pointer;
  line-height: 16px;
  color: #4c0099;
}
.stackchat__show-message,
.stackchat__hide-message {
  animation-name: stackchat__animGenie;
  animation-duration: 0.4s;
}
.stackchat__hide-message {
  animation-direction: reverse;
  animation-name: stackchat__animGenieReverse;
}
@keyframes stackchat__animGenie {
  0% {
    opacity: 0;
    transform: translate3d(45%, calc(144%), 0) scale3d(0, 1, 1);
    animation-timing-function: ease-in;
  }
  40% {
    opacity: 0.5;
    transform: translate3d(27%, 0, 0) scale3d(0.02, 1.1, 1);
    animation-timing-function: ease-out;
  }
  70% {
    opacity: 0.6;
    transform: translate3d(9%, -40px, 0) scale3d(0.8, 1.1, 1);
  }
  100% {
    opacity: 1;
    transform: translate3d(0, 0, 0) scale3d(1, 1, 1);
  }
}
@keyframes stackchat__animGenieReverse {
  0% {
    opacity: 0;
    transform: translate3d(45%, calc(144%), 0) scale3d(0, 1, 1);
    animation-timing-function: ease-in;
  }
  40% {
    opacity: 0.5;
    transform: translate3d(27%, 0, 0) scale3d(0.02, 1.1, 1);
    animation-timing-function: ease-out;
  }
  70% {
    opacity: 0.6;
    transform: translate3d(9%, -40px, 0) scale3d(0.8, 1.1, 1);
  }
  100% {
    opacity: 1;
    transform: translate3d(0, 0, 0) scale3d(1, 1, 1);
  }
}
```

# Content Security Policy

If your deployment requires [CSP compatibility](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP), add the following meta tag to your configuration.

```html
<meta
  http-equiv="Content-Security-Policy"
  content="
    connect-src
        wss://*.stackchat.com
        https://*.stackchat.com;
    font-src
        https://*.stackchat.com;
    script-src
        https://*.stackchat.com;
    style-src
        https://*.stackchat.com;
    img-src
        blob:
        https://*.stackchat.com;"
/>
```

Note that an equivalent configuration can be done [server side](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy).

According to the channels you use, other domains may need to be added (these are used to display QR codes to link to the Stackchat Web Messenger conversation):

- LINE: https://qr-official.line.me
- WeChat: https://mp.weixin.qq.com

Note that your CSP configuration should also include any domains used to host images or files sent in messages.
If you require `blob:` to be excluded for `img-src`, you must disable the image upload feature via the [init settings](#initoptions).

# Acknowledgements

https://github.com/lipis/flag-icon-css