These docs are for v0.0.1. Click to read the latest docs for v1.0.61.

Web Messenger SDK

This page describes how to get started with the Web Messenger SDK

Prerequisites to Implementing Web Messenger SDK

🚧

Download the Web Messenger SDK before proceeding

Make sure you download the Web Messenger SDK here from DevConnect before continuing through this integration guide

Web Messenger Configuration

📘

First: Start with configuring your public path for the Web Messenger SDK

The AvMessagingSdk library is composed of multiple assets fetched at runtime for better performance.
For that reason, the public path (the URL where files are hosted) is hardcoded in multiple places.

To configure the library for your environment, run:

./configure <new-public-path>

The script will generate a folder with the configured project in it.

Examples

Local testing setup

The static files are hosted at http://localhost:8000/static/ and the script is run in the /home/your-name/ folder.

./configure http://localhost:8000/static/

Files will be available at /home/your-name/http:__localhost:8000_static_/.

Production setup

The static files are hosted at https://cdn.acme.org/.

./configure https://cdn.acme.org/

Files will be available at /home/your-name/https:__cdn.acme.org_/.

Installation instructions for the end user

Instructions on how to integrate the library on a website will be available in the README.md file inside the generated folder.

Content Security Policy

In case your customer's deployment requires CSP compatibility, the following meta tag needs to be included on their site. However, keep in mind that for connect-src Smooch domain will appear and cannot be replaced by yours. Other domains (here acme.org) should be replaced by the domain where files are hosted.

<meta
    http-equiv="Content-Security-Policy"
    content="
    connect-src
        wss://*.smooch.io
        https://*.smooch.io;
    font-src
        https://*.acme.org;
    script-src
        https://*.acme.org;
    style-src
        https://*.acme.org;
    img-src
        blob:
        https://*.acme.org;"
/>

Note that an equivalent configuration can be done server side.

According to the channels enabled by your customer, other domains may need to be added (these are used to display QR codes to link the Web Messenger conversation):

Note that the CSP configuration should also include any domains used to host images or files sent in messages.
If a specific deployment requires blob: to be excluded for img-src, image upload must also be disabled via init settings.

Web Messenger Configure Public Path

📘

Second: Deploy the Web Messenger SDK to test your configured public path

Deployment

  1. Put all files from the cdnPackage folder at the root of the storage behind https://{{YOUR_DOMAIN_NAME}}/.
  2. If your storage is behind a CDN, make sure to issue a cache invalidation for https://{{YOUR_DOMAIN_NAME}}/loader.json.
  3. Make sure your server allows CORS requests.
  4. Use the instructions in docs/README.md to test your deployment.

Documentation

Distribute docs/README.md to your users as this document contains everything needed to explain how to initialize and use the Web Messenger.

Web Messenger Customization

📘

Third: Customize the Web Messenger SDK

The AvMessagingSdk Web Messenger will add live web messaging to your website or web app.

Usage

Script Tag

Add the following code towards the end of the head section on your page and replace <integration-id> with your integration id at the end of the script.

<script>
    !function(e,n,t,r){function s(){try{var e;if((e="string"==typeof this.response?JSON.parse(this.response):this.response).url){var t=n.getElementsByTagName("script")[0],r=n.createElement("script");r.async=!0,r.src=e.url,t.parentNode.insertBefore(r,t)}}catch(e){}}var o,p,a,i=[],c=[];e[t]={init:function(){o=arguments;var e={then:function(n){return c.push({type:"t",next:n}),e},catch:function(n){return c.push({type:"c",next:n}),e}};return e},on:function(){i.push(arguments)},render:function(){p=arguments},destroy:function(){a=arguments}},e.__onWebMessengerHostReady__=function(n){if(delete e.__onWebMessengerHostReady__,e[t]=n,o)for(var r=n.init.apply(n,o),s=0;s<c.length;s++){var u=c[s];r="t"===u.type?r.then(u.next):r.catch(u.next)}p&&n.render.apply(n,p),a&&n.destroy.apply(n,a);for(s=0;s<i.length;s++)n.on.apply(n,i[s])};var u=new XMLHttpRequest;u.addEventListener("load",s),u.open("GET","https://{{YOUR_DOMAIN_NAME}}/loader.json",!0),u.responseType="json",u.send()}(window,document,"AvMessagingSdk");
</script>

then initialize the Web Messenger by placing this snippet towards the end of the body section of your page.

<script>
    AvMessagingSdk.init({integrationId: '<integration-id>'}).then(function() {
        // Your code after init is complete
    });
</script>

Browser support

Web Messenger supports all popular browsers.

Desktop versions

  • 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 versions

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

Other browsers

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

API

Individual functions

init(options)

Initializes the AvMessagingSdk widget in the web page using the specified options. It returns a promise that will resolve when the Web Messenger is ready. Note that excepton and off, all methods needs to be called after a successful init.

Options
OptionOptional?Default valueDescription
appIdYes-Your app id
integrationIdNo-Your integration id
regionYes-The target region in which the app is located.
userIdYes-Optional. User's id, which can be passed in init() as an alternative to login() (see below)
jwtYes-Optional. User's authentication token, which can be passed in init() as an alternative to login() (see below)
authCodeYes-An auth code for linking to an existing conversation
localeYesen-USLocale used for date formatting using the <language>-<COUNTRY> format. Language codes can be found here and country codes here.
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.
Note 2: this is only used for date formatting and doesn't provide built-in translations for Web Messenger.
soundNotificationEnabledYestrueEnables the sound notification for new messages
imageUploadEnabledYestrueEnables the image upload feature. (deprecated: use menuItems.imageUpload; if this option is false, it will disable menuItems.imageUpload and menuItems.fileUpload)
fixedIntroPaneYesfalseWhen enabled, the introduction pane will be pinned at the top of the conversation instead of scrolling with it.
embeddedYesFalseTells the widget it will be embedded. (see Embedded section below)
displayStyleYesbuttonChoose how the messenger will appear on your website. Must be either button or tab.
buttonIconUrlYes-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.
buttonWidthYes58pxWhen the displayStyle is button, you have the option of specifying the button width.
buttonHeightYes58pxWhen the displayStyle is button, you have the option of specifying the button height.
businessNameYes-A custom business name.
businessIconUrlYes-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.
backgroundImageUrlYes-A background image url for the conversation. Image will be tiled to fit the window.
integrationOrderYes-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.
customColorsYesSee below.Colors used in the Web Messenger UI.
customTextYesSee the example belowStrings 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.
menuItemsYesSee below.Choose menu items.
notificationChannelPromptEnabledYestrueEnables displaying a prompt to new users after their first message to suggest linking their chat instance with their other 3rd-party apps.
browserStorageYeslocalStorageChoose the storage type to use for storing user identity in the browser. Must be either localStorage or sessionStorage.
delegateYesundefinedSets a delegate on the conversation. See the delegate section for more details.
prechatCaptureYesSee below.Enables automatically capturing a user's name and email via a form before the start of a conversation. Disables the chat input until the form has been submitted.
region

AvMessagingSdk is available in the following regions:

RegionRegion Identifier
United StatesLeave unspecified
European Unioneu-1
customColors
OptionOptional?Default valueDescription
brandColorYes65758eThis 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.
conversationColorYes0099ffThis color will be used for customer messages, quick replies and actions in the footer. Must be a 3 or 6-character hexadecimal color.
actionColorYes0099ffThis 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.

OptionDefault value
actionPaymentCompletedPayment Completed
actionPaymentErrorAn error occurred while processing the card. <br> Please try again or use a different card.
actionPostbackErrorAn error occurred while processing your action. Please try again.
clickToRetryMessage not delivered. Click to retry.
clickToRetryFormForm not submitted. Click anywhere on the form to retry.
connectNotificationTextGive us a way to reach out:
connectNotificationSingleTextBe notified when you get a reply.
connectNotificationSingleButtonTextTurn on <name> notifications
connectNotificationOthersTextothers
conversationTimestampHeaderFormatMMMM D YYYY, h:mm A
couldNotConnectCouldn't connect. You can {retry}.
couldNotConnectInnerretry connecting now
couldNotConnectWithRetryCouldn't connect. We'll keep retrying, or you can {retry}.
couldNotConnectWithRetryInnertry now
emailChangeAddressChange my email
emailDescriptionTo be notified by email when you get a reply, enter your email address.
emailFieldLabelYour email
emailFieldPlaceholderYour email address
emailFormButtonContinue
fetchHistoryLoad more
fetchingHistoryRetrieving history...
fileTooLargeErrorMax file size limit exceeded ({size})
fileTypeErrorUnsupported file type.
formErrorInvalidEmailEmail is invalid
formErrorNoLongerThanMust contain no more than ({characters}) characters
formErrorNoShorterThanMust contain at least ({characters}) characters
formErrorUnknownThis doesn't look quite right
formFieldSelectPlaceholderFallbackChoose one...
frontendEmailChannelDescriptionTo talk to us using email just send a message to our email address and we'll reply shortly:
headerTextHow can we help?
imageClickToReloadClick to reload image.
imageClickToViewClick to view {size} image.
imagePreviewNotAvailablePreview not available.
inputPlaceholderType a message...
inputPlaceholderBlockedComplete the form above...
introAppTextMessage us below or from your favorite app.
introductionTextWe're here to talk, so ask us anything!
lineChannelDescriptionTo talk to us using LINE, scan this QR code using the LINE app and send us a message.
linkErrorAn error occurred when attempting to generate a link for this channel. Please try again.
locationNotSupportedYour browser does not support location services or it’s been disabled. Please type your location instead.
locationSecurityRestrictionThis website cannot access your location. Please type your location instead.
locationSendingFailedCould not send location
locationServicesDeniedThis website cannot access your location. Allow access in your settings or type your location instead.
messageErrorAn 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
messageRelativeTimeJustNowJust now
messageRelativeTimeMinute{value}m ago
messageTimestampFormath:mm A
messageSendingSending...
messageDeliveredDelivered
messengerChannelDescriptionConnect your Facebook Messenger account to be notified when you get a reply and continue the conversation on Facebook Messenger.
notificationSettingsChannelsDescriptionYou can also talk to us from your favorite app or service.
notificationSettingsChannelsTitleOther Channels
notificationSettingsConnectedConnected
notificationSettingsConnectedAsConnected as {username}
prechatCaptureGreetingTextHi there 👋\nTo start off, we'd like to know a little bit more about you:
prechatCaptureNameLabelYour name
prechatCaptureNamePlaceholderType your name...
prechatCaptureEmailLabelEmail
prechatCaptureEmailPlaceholder[email protected]
prechatCaptureConfirmationTextThanks for that! What can we help you with?
prechatCaptureMailgunLinkingConfirmationYou'll be notified here and by email at {email} once we reply.
sendButtonTextSend
settingsHeaderTextSettings
shareLocationShare location
smsBadRequestErrorWe were unable to communicate with this number. Try again or use a different one.
smsCancelCancel
smsChangeNumberChange my number
smsChannelDescriptionConnect your SMS number to be notified when you get a reply and continue the conversation over SMS.
smsChannelPendingDescriptionCheck your messages at {number} to confirm your phone number.
smsContinueContinue
smsInvalidNumberErrorYour phone number isn't valid. Please try again.
smsLinkCancelledLink to {appUserNumber} was cancelled.
smsLinkPendingPending
smsPingChannelErrorThere was an error sending a message to your number.
smsSendTextSend me a text
smsStartTextingStart Texting
smsTooManyRequestsErrorA connection for that number was requested recently. Please try again in {minutes} minutes.
smsTooManyRequestsOneMinuteErrorA connection for that number was requested recently. Please try again in 1 minute.
smsUnhandledErrorSomething went wrong. Please try again.
tapToRetryMessage not delivered. Tap to retry.
tapToRetryFormForm not submitted. Tap anywhere on the form to retry.
telegramChannelDescriptionConnect your Telegram account to be notified when you get a reply and continue the conversation on Telegram
uploadDocumentUpload document
uploadInvalidErrorInvalid file
uploadPhotoUpload photo
uploadVirusErrorA virus was detected in your file and it has been rejected
unsupportedMessageTypeUnsupported message type.
unsupportedActionTypeUnsupported action type.
viberChannelDescriptionConnect your Viber account to be notified when you get a reply and continue the conversation on Viber. To get started, scan the QR code using the Viber app.
viberChannelDescriptionMobileConnect your Viber account to be notified when you get a reply and continue the conversation on Viber. To get started, install the Viber app and tap Connect.
viberQRCodeErrorAn error occurred while fetching your Viber QR code. Please try again.
wechatChannelDescriptionConnect your WeChat account to be notified when you get a reply and continue the conversation on WeChat. To get started, scan this QR code using the WeChat app.
wechatChannelDescriptionMobileConnect your WeChat account to be notified when you get a reply and continue the conversation on WeChat. To get started, save this QR code image and upload it <a href=\'weixin://dl/scan\'>QR code scanner</a>.
wechatQRCodeErrorAn error occurred while fetching your WeChat QR code. Please try again.
whatsappChannelDescriptionDesktopSync your account to WhatsApp by scanning the QR code or clicking the link below.\nThen, send the pre-populated message to validate the sync request. (Your code: {{code}}).
whatsappChannelDescriptionMobileSync your account to WhatsApp by clicking the link below.\nThen, send the pre-populated message to validate the sync request. (Your code: {{code}}).
whatsappLinkingErrorAn error occurred while fetching your WhatsApp linking information. Please try again.

See below for an example.

menuItems
OptionOptional?Default valueDescription
imageUploadYestrueEnables the image upload menu item.
fileUploadYestrueEnables the file upload menu item.
shareLocationYestrueEnables the share location menu item.

See below for an example.

prechatCapture
OptionOptional?Default valueDescription
enabledYesfalseEnables the prechat capture experience.
enableEmailLinkingYestrueAutomatically links the user's email to the app's Mailgun integration if it exists. If the property fields is defined, the first field of type email will be used.
fieldsYes-Overrides the default Prechat Capture fields to define a custom form.

See below for an example.

prechatCapture uses the following customText options:

OptionDescription
prechatCaptureGreetingTextText for the initial greeting message.
prechatCaptureNameLabelLabel displayed for the default form's first field.
prechatCaptureNamePlaceholderPlaceholder for the default form's first field.
prechatCaptureEmailLabelLabel displayed for the default form's second field.
prechatCaptureEmailPlaceholderPlaceholder for the default form's second field.
prechatCaptureConfirmationTextText for the confirmation message sent when the form is completed.
prechatCaptureMailgunLinkingConfirmationText for the notification message when a user has linked their email address.
Example
var initPromise = AvMessagingSdk.init({
    integrationId: '<integration-id>',

    // Leave unspecified for US region (default)
    region: 'eu-1',

    // For authenticated mode
    jwt: 'your_jwt',
    userId: 'user_id',
    locale: 'en-US',

    customColors: {
        brandColor: '65758e',
        conversationColor: '65758e',
        actionColor: '65758e',
    },

    menuItems: {
        imageUpload: true,
        fileUpload: true,
        shareLocation: true
    },

    fixedIntroPane: false,

    prechatCapture: {
        enabled: true,
        enableEmailLinking: true,
        fields: [
            {
                type: 'email',
                name: 'email',
                label: 'Email',
                placeholder: '[email protected]'
            },
            {
                type: 'text',
                name: 'company-website',
                label: 'Company website',
                placeholder: 'mycompany.com'
            },
            {
                type: 'select',
                name: 'company-size',
                label: 'Company size',
                placeholder: 'Choose a number...',
                options: [
                    {
                        name: '1-10',
                        label: '1-10 employees'
                    },
                    {
                        name: '11-50',
                        label: '11-50 employees'
                    },
                    {
                        name: '51+',
                        label: '51+ employees'
                    }
                ]
            }
        ]
    },

    customText: {
        actionPaymentCompleted: 'Payment Completed',
        actionPaymentError: 'An error occurred while processing the card. <br> Please try again or use a different card.',
        actionPostbackError: 'An error occurred while processing your action. Please try again.',
        clickToRetry: 'Message not delivered. Click to retry.',
        clickToRetryForm: 'Form not submitted. Click anywhere on the form to retry.',
        connectNotificationText: 'Give us a way to reach out:',
        connectNotificationSingleText: 'Be notified when you get a reply.',
        connectNotificationSingleButtonText: 'Turn on <name> notifications',
        connectNotificationOthersText: 'others',
        conversationTimestampHeaderFormat: 'MMMM D YYYY, h:mm A',
        couldNotConnect: 'Couldn\'t connect. You can {retry}. '
        couldNotConnectInner: 'retry connecting now'
        couldNotConnectWithRetry: 'Couldn\'t connect. We\'ll keep retrying, or you can {retry}.',
        couldNotConnectWithRetryInner: 'try now',
        emailChangeAddress: 'Change my email',
        emailDescription: 'To be notified by email when you get a reply, enter your email address.',
        emailFieldLabel: 'Your email',
        emailFieldPlaceholder: 'Your email address',
        emailFormButton: 'Continue',
        fetchHistory: 'Load more',
        fetchingHistory: 'Retrieving history...',
        fileTooLargeError: 'Max file size limit exceeded ({size})',
        fileTypeError: 'Unsupported file type.',
        formErrorInvalidEmail: 'Email is invalid',
        formErrorNoLongerThan: 'Must contain no more than ({characters}) characters',
        formErrorNoShorterThan: 'Must contain at least ({characters}) characters',
        formErrorUnknown: 'This doesn\'t look quite right',
        formFieldSelectPlaceholderFallback: 'Choose one...',
        frontendEmailChannelDescription: 'To talk to us using email just send a message to our email address and we\'ll reply shortly:',
        headerText: 'How can we help?',
        imageClickToReload: 'Click to reload image.',
        imageClickToView: 'Click to view {size} image.',
        imagePreviewNotAvailable: 'Preview not available.',
        inputPlaceholder: 'Type a message...',
        inputPlaceholderBlocked: 'Complete the form above...',
        introAppText: 'Message us below or from your favorite app.',
        introductionText: 'We\'re here to talk, so ask us anything!',
        lineChannelDescription: 'To talk to us using LINE, scan this QR code using the LINE app and send us a message.',
        linkError: 'An error occurred when attempting to generate a link for this channel. Please try again.',
        locationNotSupported: 'Your browser does not support location services or it’s been disabled. Please type your location instead.',
        locationSecurityRestriction: 'This website cannot access your location. Please type your location instead.',
        locationSendingFailed: 'Could not send location',
        locationServicesDenied: 'This website cannot access your location. Allow access in your settings or type your location instead.',
        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',
        messengerChannelDescription: 'Connect your Facebook Messenger account to be notified when you get a reply and continue the conversation on Facebook Messenger.',
        notificationSettingsChannelsDescription: 'You can also talk to us from your favorite app or service.',
        notificationSettingsChannelsTitle: 'Other Channels',
        notificationSettingsConnected: 'Connected',
        notificationSettingsConnectedAs: 'Connected as {username}',
        prechatCaptureGreetingText: 'Hi there 👋\nTo start off, we\'d like to know a little bit more about you:',
        prechatCaptureNameLabel: 'Your name',
        prechatCaptureNamePlaceholder: 'Type your name...',
        prechatCaptureEmailLabel: 'Email',
        prechatCaptureEmailPlaceholder: '[email protected]',
        prechatCaptureConfirmationText: 'Thanks for that! What can we help you with?',
        prechatCaptureMailgunLinkingConfirmation: 'You\'ll be notified here and by email at {email} once we reply.',
        sendButtonText: 'Send',
        settingsHeaderText: 'Settings',
        shareLocation: 'Share location',
        smsBadRequestError: 'We were unable to communicate with this number. Try again or use a different one.',
        smsCancel: 'Cancel',
        smsChangeNumber: 'Change my number',
        smsChannelDescription: 'Connect your SMS number to be notified when you get a reply and continue the conversation over SMS.',
        smsChannelPendingDescription: 'Check your messages at {number} to confirm your phone number.',
        smsContinue: 'Continue',
        smsInvalidNumberError: 'Your phone number isn\'t valid. Please try again.',
        smsLinkCancelled: 'Link to {appUserNumber} was cancelled.',
        smsLinkPending: 'Pending',
        smsPingChannelError: 'There was an error sending a message to your number.',
        smsSendText: 'Send me a text',
        smsStartTexting: 'Start Texting',
        smsTooManyRequestsError: 'A connection for that number was requested recently. Please try again in {minutes} minutes.',
        smsTooManyRequestsOneMinuteError: 'A connection for that number was requested recently. Please try again in 1 minute.',
        smsUnhandledError: 'Something went wrong. Please try again.',
        tapToRetry: 'Message not delivered. Tap to retry.',
        tapToRetryForm: 'Form not submitted. Tap anywhere on the form to retry.',
        telegramChannelDescription: 'Connect your Telegram account to be notified when you get a reply and continue the conversation on Telegram',
        uploadDocument: 'Upload document',
        uploadInvalidError: 'Invalid file',
        uploadPhoto: 'Upload photo',
        uploadVirusError: 'A virus was detected in your file and it has been rejected',
        unsupportedMessageType: 'Unsupported message type.',
        unsupportedActionType: 'Unsupported action type.',
        viberChannelDescription: 'Connect your Viber account to be notified when you get a reply and continue the conversation on Viber. To get started, scan the QR code using the Viber app.',
        viberChannelDescriptionMobile: 'Connect your Viber account to be notified when you get a reply and continue the conversation on Viber. To get started, install the Viber app and tap Connect.',
        viberQRCodeError: 'An error occurred while fetching your Viber QR code. Please try again.',
        wechatChannelDescription: 'Connect your WeChat account to be notified when you get a reply and continue the conversation on WeChat. To get started, scan this QR code using the WeChat app.',
        wechatChannelDescriptionMobile: 'Connect your WeChat account to be notified when you get a reply and continue the conversation on WeChat. To get started, save this QR code image and upload it in the <a href=\'weixin://dl/scan\'>QR code scanner</a>.',
        wechatQRCodeError: 'An error occurred while fetching your WeChat QR code. Please try again.',
        whatsappChannelDescriptionDesktop: 'Sync your account to WhatsApp by scanning the QR code or clicking the link below.\nThen, send the pre-populated message to validate the sync request. (Your code: {{code}}).',
        whatsappChannelDescriptionMobile: 'Sync your account to WhatsApp by clicking the link below.\nThen, send the pre-populated message to validate the sync request. (Your code: {{code}}).',
        whatsappLinkingError: 'An error occurred while fetching your WhatsApp linking information. Please try again.'
    }
}).then(function() {
    // Your code after init is complete
});

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

// pass it around...

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

open()

Opens the conversation widget (noop when embedded)

AvMessagingSdk.open();

close()

Closes the conversation widget (noop when embedded)

AvMessagingSdk.close();

isOpened()

Tells if the widget is currently opened or closed.

AvMessagingSdk.isOpened();

login(userId , jwt)

Logs a user in the Web Messenger, retrieving the conversation the user already had on other browsers and/or devices. Note that you don't need to call this after init if you passed the user id and jwt already, it's done internally. This returns a promise that resolves when the Web Messenger is ready again.

AvMessagingSdk.login('some-id', 'some-jwt');

logout()

Logs out the current user and reinitialize the widget with an anonymous user. This returns a promise that resolves when the Web Messenger is ready again.

AvMessagingSdk.logout();

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 integration id from the Web Messenger. It will also unbind all listeners you might have with AvMessagingSdk.on.

AvMessagingSdk.destroy();

sendMessage(message)

Sends a message on the user's behalf

AvMessagingSdk.sendMessage({
    type: 'text',
    text: 'hello'
});

// OR

AvMessagingSdk.sendMessage('hello', '<conversation-id>');

startTyping()

Sends an event indicating the appUser has started typing. When called, a stopTyping timer will be created and will call stopTyping() after 10s, unless stopTyping() has been called manually. Everytime startTyping() is called the timer is reset. If startTyping() is called repeatedly, an event will only be sent if the time since the last sent event is greater then 10s.

If conversationId is not provided, the currently loaded conversation will be used.

AvMessagingSdk.startTyping();

stopTyping()

Sends an event indicating the appUser has stoped typing.

AvMessagingSdk.stopTyping();

triggerPostback(actionId, conversationId)

Trigger a postback action on the user's behalf.
The actionId is the _id property of the targeted action.

If you have the _id of the targetted postback action, you can pass it directly to triggerPostback.

If conversationId is not provided, the currently loaded conversation will be used.

const actionId = '5a747faa065bbe4e7804f2a4';
AvMessagingSdk.triggerPostback(actionId, '62565b5c2b4039adff80b7fd');

Otherwise, you can get the _id of an action by using AvMessagingSdk.getConversation(), e.g.

const conversation = AvMessagingSdk.getConversation();

console.log(conversation.messages);
// [
//     {
//         "text": "Do you want to continue?",
//         "actions": [
//             {
//                 "payload": "text:continue",
//                 "text": "Continue conversation",
//                 "_id": "5a7c65211aaa9b61f69c95e3",
//                 "type": "postback"
//             }
//         ],
//         "type": "text",
//         "role": "appMaker",
//         "_id": "5a7c65211aaa9b61f69c95e2",
//         // ...
//     }
// ]

// Indicate that the user has clicked on the "Continue conversation" postback action.
AvMessagingSdk.triggerPostback(conversation.messages[0].actions[0]._id);

updateUser(user)

Updates user information

AvMessagingSdk.updateUser({
    givenName: 'Updated',
    surname: 'Name',
    email: '[email protected]',
    properties: {
      'justGotUpdated': true
    }
});

getUser()

Returns the current user.

var user = AvMessagingSdk.getUser()

getConversation()

Returns the conversation if it exists

var conversation = AvMessagingSdk.getConversation();

// Data object
conversation = {
    _id: '<conversation-id>',
    unreadCount: 0,
    lastUpdatedAt: 1581010017.596,
    type: "personal",
    participants: [
        {
            _id: '<participant-id>',
            appUserId: '<appUser-id>',
            unreadCount: 0,
            lastRead: 1581010017.596
        }
    ],
    metadata: {},
    messages: [
        {
            role: 'appUser',
            authorId: '6ac41c8b32e704f3cdb9052d',
            name: 'Some user',
            _id: '5e6022c9cb55158bfd53f845',
            type: "text",
            received: 1583358665.139,
            text: 'Hello',
            source: {
                type: 'web',
                id: 'c38ae913af7c4ef3800b339ee529c579',
                integrationId: '5d8274d4aa780a5483f0ee56'
            }
        }
    ]
}

loadConversation(conversationId)

Loads a conversation into the current session

AvMessagingSdk.loadConversation('<conversation-id>');

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.

AvMessagingSdk.startConversation();

markAllAsRead()

Marks all unread messages as read.

AvMessagingSdk.markAllAsRead();

showNotificationChannelPrompt()

Displays a prompt to the user suggesting the linking of the current chat instance with other 3rd-party apps.

AvMessagingSdk.showNotificationChannelPrompt();

setPredefinedMessage(message)

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

AvMessagingSdk.setPredefinedMessage(message);

setDelegate(delegate)

Sets a delegate on the conversation. AvMessagingSdk must be initialized before calling this method. See the delegate section for more details.

AvMessagingSdk.setDelegate(delegate);

Delegate

AvMessagingSdk allows you to set a delegate to receive callbacks when important changes happen in the conversation.
To set a delegate, pass the delegate parameter in to init options, or use the setDelegate method. The delegate object may optionally contain beforeDisplay, beforeSend, beforePostbackSend and onInvalidAuth delegate functions.

A data object is passed down with all the delegate events except onInvalidAuth. This is a read-only object containing a truncated version of the conversation associated with the event.

const delegate = {
    beforeDisplay(message, data) {
        if (data.conversation._id === '<my-conversation-id>') {
            message.name = 'Acme Blank';
        }

        return message;
    },
    beforeSend(message, data) {
        return message;
    },
    beforePostbackSend(postback, data) {
        return postback;
    },
    onInvalidAuth() {
        return new Promise((resolve) =>
            resolve('<my-new-auth-token>')
        )
    }
}

// Passing delegate as an init parameter
AvMessagingSdk.init({
    integrationId: '<integration-id>',
    delegate
});

// Using setDelegate
AvMessagingSdk.init({ integrationId: '<integration-id>' }).then(() => {
    AvMessagingSdk.setDelegate(delegate);
});

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.

AvMessagingSdk.init({
    integrationId: '<integration-id>',
    delegate: {
        beforeDisplay(message, data) {
            if (data.conversation._id === '<conversation-id>' && 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 AvMessagingSdk.
The modified message must be returned for it to take effect.

Note that when a file or an image is uploaded, only the message metadata may be updated. Other message properties such as type or text won't be considered.

AvMessagingSdk.init({
    integrationId: '<integration-id>'
    delegate: {
        beforeSend(message, data) {
            if (data.conversation._id === '<conversation-id>') {
                message.metadata = {
                    any: 'info'
                };
            }

            return message;
        }
    }
});

beforePostbackSend

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

AvMessagingSdk.init({
   integrationId: '<integration-id>',
   delegate: {
       beforePostbackSend(postback) {
           if (data.conversation._id === '<conversation-id>') {
               postback.metadata = {
                   any: 'info'
               };
           }

           return postback;
       }
   }
});

onInvalidAuth

The onInvalidAuth delegate notifies the delegate of a failed request due to invalid credentials and allows the implementer to set a new auth token in order to retry the request. The delegate must return a new JWT token as a string or Promise<string> that will resolve into the JWT.

AvMessagingSdk.init({
    integrationId: '<integration-id>',
    delegate: {
        onInvalidAuth() {
            return '<my-new-auth-token>';
        }
    }
});

Events

If you want to make sure your events are triggered, try to bind them before calling AvMessagingSdk.init.

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

ready

// This event triggers when init completes successfully... Be sure to bind before calling init!
AvMessagingSdk.on('ready', function(){
    console.log('the init has completed!');
});

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

destroy

// This event triggers when the widget is destroyed.
AvMessagingSdk.on('destroy', function(){
    console.log('the widget is destroyed!');
});

AvMessagingSdk.destroy();

participant:added

// This event triggers when a participant is added to a conversation
AvMessagingSdk.on('participant:added', function(participant, data) {
    console.log(`A participant was added to conversation ${data.conversation._id}: `, participant);
});

participant:removed

// This event triggers when a participant is removed from a conversation
AvMessagingSdk.on('participant:removed', function(participant, data) {
    console.log(`A participant was removed from conversation ${data.conversation._id}: `, participant);
});

conversation:added

// This event triggers when a conversation is added
AvMessagingSdk.on('conversation:added', function(participants, data) {
    console.log(`Conversation ${data.conversation._id} was added with following participants: `, participants);
});

conversation:read

// This event triggers when a participant in a sdkGroup chat reads a message
AvMessagingSdk.on('conversation:read', function(payload, data) {
    if (data.role === 'appMaker') {
        console.log(`Conversation ${data.conversation._id} was read by appMaker`);
    } else if (data.role === 'appUser') {
        console.log(`Conversation ${data.conversation._id} was read by appUserId: ${payload.appUserId}`);
    }
});

// Data object, if the conversation was read by the appMaker, the appUser property will not exist
payload = {
    appUserId: '<appUser-id>',
    lastRead: 1581010017.596,
    role: 'appUser'
}

data = {
    conversation: {
        _id: '<conversation-id>'
    }
}

conversation:removed

// This event triggers when a conversation is removed
AvMessagingSdk.on('conversation:removed', function(data) {
    console.log(`Conversation ${data.conversation._id} was removed`);
});

// data object
data = {
    conversation: {
        _id: '<conversation-id>'
    }
}

message:received

// This event triggers when the user receives a message
AvMessagingSdk.on('message:received', function(message, data) {
    console.log(`The user received a message in conversation ${data.conversation._id}: `, message);
});

// data object
data = {
    conversation: {
        _id: '<conversation-id>'
    }
}

message:sent

// This event triggers when the user sends a message
AvMessagingSdk.on('message:sent', function(message, data) {
    console.log(`The user sent a message in conversation ${data.conversation._id}: `, message);
});

// data object
data = {
    conversation: {
        _id: '<conversation-id>'
    }
}

message

// This event triggers when a message was added to the conversation
AvMessagingSdk.on('message', function(message, data) {
    console.log(`A message was added in the conversation ${data.conversation._id}: `, message);
});

// data object
data = {
    conversation: {
        _id: '<conversation-id>'
    }
}

unreadCount

// This event triggers when the number of unread messages changes
AvMessagingSdk.on('unreadCount', function(unreadCount, data) {
    console.log(`the number of unread messages was updated for conversation ${data.conversation._id}:`, unreadCount);
});

// data object
data = {
    conversation: {
        _id: '<conversation-id>'
    }
}

widget:opened

// This event triggers when the widget is opened
AvMessagingSdk.on('widget:opened', function() {
    console.log('Widget is opened!');
});

widget:closed

// This event triggers when the widget is closed
AvMessagingSdk.on('widget:closed', function() {
    console.log('Widget is closed!');
});

connected

// This event triggers when an active connection has been established for the first time,
// or when the connection has been re-established after a `disconnect` event.
AvMessagingSdk.on('connected', function(e) {
    console.log('Connected');
});

disconnected

// This event triggers when an active connection is lost
// While disconnected, the client will not be able to recieve messages
AvMessagingSdk.on('disconnected', function(e) {
    console.log('Disonnected');
});

typing:start

// This event triggers when appMaker starts typing. The associated conversation is passed in the argument.
AvMessagingSdk.on('typing:start', function(data) {
    console.log(`${data.name} started typing!`, data.conversation._id);
});

// If the name and avatarUrl for the typing user is known it will be available as properties in the data object

// Data object
data = {
    conversation: {
        _id: '<conversation-id>',
    },
    avatarUrl: 'http://path.com/to/avatar-url-of-user',
    name: 'Name of Typing User',
}

typing:stop

// This event triggers when appMaker stops typing. The associated conversation is passed in the argument.
AvMessagingSdk.on('typing:stop', function(data) {
    console.log(`${data.name} stopped typing!`, data.conversation._id);
});

// data object
data = {
    conversation: {
        _id: '<conversation-id>'
    }
}

Embedded mode

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

AvMessagingSdk.init({
    integrationId: '<integration-id>',
    embedded: true
});

AvMessagingSdk.render(document.getElementById('chat-container'));

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

Authenticating the user: init() vs login()

For authenticated user scenarios, a user's credentials can be passed in to either init() or login(). The question remains: when should you use which?

When init() is called without a userId and jwt, the UI will be initialized in an anonymous user context, and the user will be able to send messages as an anonymous user. After init() has completed, login() may be called to authenticate the user and resume any existing conversation. This is useful if you want your users to be able to send messages before they've logged in to your website. Once a user does login and the browser is issued a valid jwt, login() may be called so that the user may continue the conversation in an authenticated session.

If however your use case requires that all users be logged in before they may send messages, then you should consider passing userId and jwt directly to the init() call upfront.

Content Security Policy

If your deployment requires CSP compatibility, add the following meta tag to your configuration.

<meta
    http-equiv="Content-Security-Policy"
    content="
    connect-src
        wss://*.{{YOUR_DOMAIN_NAME}}
        https://*.{{YOUR_DOMAIN_NAME}};
    font-src
        https://*.{{YOUR_DOMAIN_NAME}};
    script-src
        https://*.{{YOUR_DOMAIN_NAME}};
    style-src
        https://*.{{YOUR_DOMAIN_NAME}};
    img-src
        blob:
        https://*.{{YOUR_DOMAIN_NAME}};"
/>

Note that an equivalent configuration can be done server side.

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.

Acknowledgements

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

Version

This is version 1.0.1 of AvMessagingSdk.