@livechat/chat.io-customer-sdk

    0.9.1 • Public • Published

    Introduction

    Chat.io Customer JS SDK is a set of tools to build a custom chat widget. It allows you to manage multiple chats via chat.io as a customer using JavaScript.

    Is it for me?

    If you need to customize the chat.io widget, using chat.io Customer JS SDK is one of the options to do this. If you need a fully custom solution and you feel brave, dive into chat.io Customer JS SDK: we provide methods and events for deep integration with the chat.io environment.

    Keep in mind, however, that interacting with this API requires some development skills.

    About chat.io Customer JS SDK

    We provide an asynchronous API, where most methods interacting with a server return promises. To get the promise's fulfillment result, subscribe your handler to the promise's then() method. You can also subscribe to the emitted events with on and off methods.

    Not familiar with promises? Read this article to learn more.

    We authenticate your sessions by using chat.io-customer-auth package and expose the created auth object on the returned SDK's instance. In general, you don't have to worry about it nor use the exposed object, but if you need to get the authentication token you can get it through the SDK like this:

    customerSDK.auth.getToken().then(token => console.log(token))

    Examples

    We have prepared a sample chat widget implementation to present the features of chat.io Customer JS SDK:

    How to start

    This tutorial will help you get started with using chat.io Customer JS SDK.

    Create an application

    First, you need to create an application in the Developers Console (select the Web app (frontend, eg. JavaScript) type).

    Install Customer JS SDK

    You can use chat.io Customer JS SDK in two different ways:

    Using npm

    npm install --save @livechat/chat.io-customer-sdk

    Now, you can import SDK in your code:

    import chatIoCustomerSDK from '@livechat/chat.io-customer-sdk'

    or with a node-style require call:

    const chatIoCustomerSDK = require('@livechat/chat.io-customer-sdk')

    Using script tag - UMD module hosted on unpkg's CDN

    <script src="https://unpkg.com/@livechat/chat.io-customer-sdk@0.8.0/dist/chat.io-customer-sdk.min.js"></script>

    If you just want to look around and play with the SDK, check out our sample chat widget implementation.

    For the time being you need to register your application in the Developers Console as a "Web app (frontend, eg. JavaScript)" type. Then, you have to pass the configured redirectUri to the init, along with the regular required properties (license and clientId).

    Use the API

    Now run the init function with the configuration, replacing LICENSE_NUMBER with your chat.io license number. The function will return the customerSDK instance:

    const customerSDK = CustomerSDK.init({
      license: LICENSE_NUMBER,
      clientId: CLIENT_ID,
    })

    With customerSDK, you can attach events:

    customerSDK.on('new_event', newEvent => {
      console.log(newEvent)
    })

    or execute methods:

    const chatId = 'OU0V0P0OWT'
    customerSDK
      .sendMessage(chatId, {
        text: 'Hi!',
      })
      .then(response => {
        console.log(response)
      })
      .catch(error => {
        console.log(error)
      })

    Using the API in React Native

    If you want to use chat.io Customer SDK in React Native, keep in mind that we use cookies to authenticate your sessions, so we need some sort of browser environment for that. We've prepared a special wrapper for you to use in React Native, which opens a WebView component to get an authentication token. All you have to do is to import it from our authentication package (no need to install it - the SDK depends on it, so you have it already) and mount it in your React Native application:

    import { AuthWebView } from '@livechat/chat.io-customer-auth'
    import { init } from '@livechat/chat.io-customer-sdk'
     
    export default class App extends React.Component {
      componentDidMount() {
        const customerSDK = init({
          license: LICENSE_NUMBER,
          clientId: CLIENT_ID,
          redirectUri: REDIRECT_URI,
        })
        // you can start using customerSDK from now
      }
     
      render() {
        return (
          <View>
            <AuthWebView />
          </View>
        )
      }
    }

    Key Concepts

    The chat.io system is based on four basic types of entities - users, chats, events and threads.

    • chats consist of threads and threads consist of events
    • threads are parts of chats,
    • users can add events to chats, which then are automatically added to threads
    • users can participate in many chats at the same time

    Threads are a vital part of chat.io architecture. They provide continuous chat experience (i.e. they never end and you can always add to them) and they group events in smaller logical chunks, e.g. for reporting and caching purposes. However, threads tend to complicate handling various operations like loading more history events. The good part is that you don't have to worry about them most of the time and this SDK is doing the heavy lifting behind the scenes for you. You will get notified about threads' metadata only if you explicitly ask for it - most SDK methods expect only chat IDs.

    User

    {
        id: 'ed9d4095-45d6-428d-5093-f8ec7f1f81b9',
        type: 'agent',
        name: 'Jane Doe',
        email: 'jane.doe@chat.io',
        avatar: 'https://chatio-static.com/assets/images/chatio_logo.ae4271fe1a0a2db838dcf075388ee844.png',
    }

    Chat

    {
        id: 'OU0V0P0OWT',
        users: [{
            id: 'ed9d4095-45d6-428d-5093-f8ec7f1f81b9',
            lastSeenTimestamp: 1503062591000, // might be null
        }],
        threads: ['OU0V0U3IMN'],
    }

    Event

    {
        type: 'message',
        text: 'hi!',
        author: 'ed9d4095-45d6-428d-5093-f8ec7f1f81b9', // assigned by server
        id: 'OU0V0U3IMN_1', // assigned by server
        timestamp: 1503062591000, // assigned by server
        customnId: '814.3316641404942', // optional
        thread: 'OU0V4R0OXP',
    }

    Threads

    {
        id: 'OU0V0U3IMN',
        active: true,
        order: 3,
        users: ['ed9d4095-45d6-428d-5093-f8ec7f1f81b9'],
        events: [ /* events */ ],
    }

    Methods

    closeThread

    customerSDK
      .closeThread('ON0X0R0L67')
      .then(response => {
        console.log(response)
      })
      .catch(error => {
        console.log(error)
      })

    Arguments:

    arguments type description
    chat string Chat's id in which thread should get closed

    Returned value:

    shape type
    success boolean

    destroy

    This method clears any held resources, removes all listeners and disconnects from the network. After using this method you won't be able to use the destroyed SDK's instance.

    customerSDK.destroy()

    disconnect

    customerSDK.disconnect()

    getChatHistory

    This method facilitates loading more history events. You need to get access to the history object for certain chat by calling this method. The returned history object has only one method, next, which gives you a promise of { done, value } pair.

    • done - indicates if there is anything more to load
    • value - it's an array of loaded events

    You can keep calling history.next() multiple times to load more and more history events (useful for infinite scroll feature). Keep in mind, though, that you generally shouldn't call next while the history is being loaded - we queue those requests so the previous one must resolve before we proceed with the next one.

    Such structure like our history object is called an async iterator.

    let wholeChatHistoryLoaded = false
     
    const history = customerSDK.getChatHistory('OU0V0P0OWT')
     
    history.next().then(result => {
      if (result.done) {
        wholeChatHistoryLoaded = true
      }
     
      const events = result.value
      console.log(events)
    })

    Arguments:

    arguments type description
    chat string Chat's id for which history object should be returned

    getChatsSummary

    customerSDK
      .getChatsSummary({
        offset: 0,
        limit: 10
      })
      .then(({ chatsSummary, totalChats }) => {
        console.log(chatsSummary);
        console.log(totalChats);
      })
      .catch(error => {
        console.log(error);
      });

    Arguments:

    arguments shape type default max description
    pagination
    offset number 0
    limit number 10 25

    Returned value:

    shape type shape type description
    chatsSummary object[]
    id string Chat's id
    users string[] Users' ids
    lastEvent object Event
    lastEventsPerType object Map from event types to event objects
    lastSeenTimestamps object Map from Users' ids to optional lastSeenTimestamps
    totalChats number

    getChatThreads

    In most cases you do not need to use this method directly. If you want to load more events, consider using getChatHistory.

    const threads = ["OS0C0W0Z1B", "OS0I0M0J0G", "OT01080705", "OT0E02082U", "OT0E08040G"]
    customerSDK.getChatThreads("ON0X0R0L67", threads)
        .then(threads => {
            console.log(threads)
        })
        .catch(error => {
            console.log(rror
        })

    Arguments:

    arguments shape type
    chat string
    threads page string[]

    Returned value:

    array of shapes type description
    id string Thread's id
    chat string Chat's id
    active string[] Active state
    order number order (can be used for sorting)
    users string[] Users' ids
    events object[] Events

    getChatThreadsSummary

    In most cases you do not need to use this method directly. If you want to load more events, consider using getChatHistory.

    customerSDK
      .getChatThreadsSummary('ON0X0R0L67', {
        offset: 0,
        limit: 10,
      })
      .then(summary => {
        console.log(summary.threadsSummary)
        console.log(summary.totalThreads)
      })
      .catch(error => {
        console.log(error)
      })

    Arguments:

    arguments shape type default max description
    chat string
    pagination
    offset number 0
    limit number 25 1000

    Returned value:

    shape type shape type
    threadsSummary object[]
    id string
    order number
    totalEvents number
    totalThreads number

    off

    This method unsubscribes from emitted events which are described here.

    on

    This method subscribes to emitted events which are described here.

    sendEvent

    const event = {
      type: 'message',
      // ... other properties specific for the event's type
    }
     
    customerSDK
      .sendEvent('ON0X0R0L67', event)
      .then(event => {
        console.log(event)
      })
      .catch(error => {
        console.log(error)
      })

    Arguments:

    arguments shape type description
    chat string Destination chat's id
    event
    type string Type of the event
    ... Other properties

    sendFile

    This method is a little bit special - it returns regular then/catch methods of a Promise and a cancel method which you can use to abort the upload of the file. It also lets you pass onProgress callback function. Keep in mind that the maximum accepted file size is 10 MB.

    customerSDK
      .sendFile(
        'ON0X0R0L67',
        {
          file,
          customId, // optional
        },
        {
          onProgress: progress => console.log(`upload progress: ${progress}`),
        },
      )
      .then(response => {
        console.log(response.url)
      })
      .catch(error => {
        console.log(error)
      })

    Arguments:

    arguments shape type description
    chat string Destination chat's id
    data
    file Blob
    customId string Optional customId for the event
    spec
    onProgress function This callback function will receive a progress value - number between 0 and 1

    Returned value:

    shape type
    url string

    In React Native instead of passing a blob you need to pass an object of such shape:

    const file = {
      uri: uriFromCameraRoll,
      type: 'image/jpeg', // optional
      name: 'photo.jpg', // optional
    }

    sendMessage

    const message = { text: 'Hello' }
     
    customerSDK
      .sendMessage('ON0X0R0L67', message)
      .then(message => {
        console.log(message)
      })
      .catch(error => {
        console.log(error)
      })

    Arguments:

    arguments shape type description
    chat string Destination chat's id
    message
    text string Customer's message

    sendRating - not implemented yet

    customerSDK
      .sendRating('ON0X0R0L67', {
        value: 'good',
        comment: 'Agent helped me a lot!',
      })
      .then(rating => {
        console.log(rating)
      })
      .catch(error => {
        console.log(error)
      })

    Arguments:

    arguments shape type description
    chat Destination chat's id
    rating
    value 'good' / 'bad' Rating value
    comment string Optional comment

    setSneakPeek

    This method doesn't return a promise. It just sets the internal sneak peek value. It will be sent to the server only if the target chat is active and only once per 2 seconds (it's throttled).

    customerSDK.setSneakPeek('ON0X0R0L67', 'what is the price for your ')

    Arguments:

    arguments type description
    chat string Destination chat id
    text string Message preview broadcasted to the agent

    startChat

    customerSDK
      .startChat({
        events: [],
      })
      .then(chat => {
        console.log(chat)
      })
      .catch(error => {
        console.log(error)
      })

    Arguments:

    arguments shape type description
    specification For advanced usage
    scope
    events events[]

    updateChatProperties

    const properties = {
      property_namespace: {
        sample: 'property',
      },
    }
    customerSDK
      .updateChatProperties('ON0X0R0L67', properties)
      .then(response => {
        console.log(response)
      })
      .catch(error => {
        console.log(error)
      })

    Arguments:

    arguments shape type description
    chat string
    properties

    updateChatThreadProperties

    const properties = {
      property_namespace: {
        sample: 'property',
      },
    }
    customerSDK
      .updateChatThreadProperties('ON0X0R0L67', 'OS0C0W0Z1B', properties)
      .then(response => {
        console.log(response)
      })
      .catch(error => {
        console.log(error)
      })

    Arguments:

    arguments shape type description
    chat string
    thread string
    properties

    updateCustomer

    const properties = {
      name: 'John Doe',
      email: 'john.doe@example.com',
      fields: {
        custom_property: 'BasketValue=10usd',
        any_key_is_ok: 'sample custom field',
      },
    }
    customerSDK
      .updateCustomer(properties)
      .then(response => {
        console.log(response)
      })
      .catch(error => {
        console.log(error)
      })

    Arguments:

    arguments shape type description
    properties
    name string Optional name
    email string Optional email
    fields object Optionl custom fields with string values

    Returned value:

    shape type
    success boolean

    updateLastSeenTimestamp

    customerSDK
      .updateLastSeenTimestamp('ON0X0R0L67', 1500646701447)
      .then(response => {
        console.log(response)
      })
      .catch(error => {
        console.log(error)
      })

    Arguments:

    arguments type description
    chat string
    timestamp number optional

    Returned value:

    shape type
    timestamp number

    $$observable

    You can consume all emitted events as a stream with most of stream libraries like in example RxJS. We provide an interop point for this, so you can easily convert our SDK to a stream like this:

    import Rx from '@reactivex/rxjs'
     
    Rx.Observable.from(visitorSDK).subscribe(([eventName, eventData]) => {
      console.log(eventName, eventData)
    })

    Events

    You can listen for emitted events by subscribing to them (using on method) with your custom JavaScript function. For example, your function can be executed every time a message has been received.

    connected

    customerSDK.on('connected', payload => {
      console.log('connected')
      console.log(payload.chatsSummary)
      console.log(payload.totalChats)
    })

    Payload:

    shape type shape type description
    chatsSummary object[]
    id Chat's id
    users string[] Users' ids
    lastEvent object Event
    lastEventsPerType object Map from event types to event objects
    lastSeenTimestamps object Map from Users' ids to optional lastSeenTimestamps
    totalChats number

    connection_lost

    customerSDK.on('connection_lost', () => {
      console.log('connection_lost')
    })

    This event doesn't carry any additional payload.

    connection_restored

    customerSDK.on('connection_restored', payload => {
      console.log('connection_restored')
      console.log(payload.chatsSummary)
      console.log(payload.totalChats)
    })

    Payload:

    shape type shape type description
    chatsSummary object[]
    id Chat's id
    users string[] Users' ids
    lastEvent object Event
    lastEventsPerType object Map from event types to event objects
    lastSeenTimestamps object Map from Users' ids to optional lastSeenTimestamps
    totalChats number

    customer_id

    customerSDK.on('customer_id', id => {
      console.log('customer id is', id)
    })

    Payload:

    argument type
    id string

    disconnected

    customerSDK.on('disconnected', reason => {
      console.log(reason)
    })

    Payload:

    argument type description
    reason string Optional

    chat_properties_updated

    customerSDK.on('chat_properties_updated', payload => {
      console.log(payload.chat)
      console.log(payload.properties)
    })

    Payload:

    shape type description
    chat string Chat's id
    properties object Chat properties

    chat_thread_properties_updated

    customerSDK.on('chat_thread_properties_updated', payload => {
      console.log(payload.chat)
      console.log(payload.thread)
      console.log(payload.properties)
    })

    Payload:

    shape type description
    chat string Chat's id
    thread string Thread's id
    properties object Thread properties

    last_seen_timestamp_updated

    customerSDK.on('last_seen_timestamp_updated', payload => {
      console.log(payload.chat)
      console.log(payload.user)
      console.log(payload.timestamp)
    })

    Payload:

    shape type description
    chat string Chat's id
    user string User's id
    timestamp number

    new_event

    You should distinguish received events by their types.

    customerSDK.on('new_event', ({ chat, event }) => {
      switch (event.type) {
        case 'message':
          console.log('new message - ', event.text)
          break
        default:
          break
      }
    })

    Payload:

    shape type description
    type string Event's type
    ... Other properties

    user_data

    customerSDK.on('user_data', user => {
      console.log(user)
    })

    User:

    shape type description

    user_joined_chat

    customerSDK.on('user_joined_chat', ({ user, chat }) => {
      console.log({ user, chat })
    })

    Payload:

    shape type description
    user string User's ID
    chat string Chat's ID

    user_left_chat

    customerSDK.on('user_left_chat', ({ user, chat }) => {
      console.log({ user, chat })
    })

    Payload:

    shape type description
    user string User's ID
    chat string Chat's ID

    user_is_typing

    customerSDK.on('user_is_typing', payload => {
      console.log(
        'user with ' + payload.user + ' id is writing something in ' + payload.chat,
      )
    })

    Payload:

    shape type description
    chat string Chat's id
    user string User's id

    user_stopped_typing

    customerSDK.on('user_stopped_typing', payload => {
      console.log(
        'user with ' + payload.user + ' id stopped writing in ' + payload.chat,
      )
    })

    Payload:

    shape type description
    chat string Chat's id
    user string User's id

    thread_closed

    customerSDK.on('thread_closed', ({ chat }) => {
      console.log(chat)
    })

    Payload:

    shape type description
    chat string Chat's id

    thread_summary

    customerSDK.on('thread_summary', summary => {
      console.log(summary)
    })

    Payload:

    shape type description
    id string
    chat string Chat's ID
    order number
    totalEvents number

    Changelog

    [v0.9.0] - 2018-03-02

    Changed
    • internal change: upgraded to 0.5 version of server protocol
    Changed

    [v0.8.0] - 2018-01-05

    Added
    • chatsSummary objects (returned from getChatsSummary method and available in payloads of connected/connection_restored events) got a new property - lastEventsPerType, which is an object that maps event types to event objects
    • updateChatProperties method and corresponding chat_properties_updated event
    • updateChatThreadProperties method and corresponding chat_thread_properties_updated event
    Fixed
    • using multiple instances in React Native
    • using in React Native on Android

    [v0.7.0] - 2017-11-24

    Changed
    • sendFile returns { url } now instead of { success: true }
    • events no longer have order property
    • users no longer have present property
    Fixed
    • it's possible now to create 2 independent instances of the SDK
    • file events with url property

    [v0.6.0] - 2017-11-23

    Changed
    • customId is added only if it has been explicitly passed in as part of an event
    • customId is not reused as request's id anymore
    • made it impossible to send 2 requests with identical ids until a response comes in

    [v0.5.0] - 2017-11-22

    Added
    • sendFile method
    Changed
    • UMD export was renamed CustomerSDK

    [v0.4.2] - 2017-11-18

    Fixed
    • server errors handling - promises should get rejected correctly now

    [v0.4.1] - 2017-11-18

    Fixed
    • UMD builds from dist directory

    [v0.4.0] - 2017-11-18

    Added
    • chatSummary object (from getChatsSummary's response and from connected and connection_restored events) got new property: lastSeenTimestamps which is a map from user IDs to optional timestamps
    Changed
    • init now accepts configuration object ({ license, clientId }) instead of just a license number (in React Native the configuration object expects additionally redirectUri)
    • getChatThreads now returns an array of threads instead of { threads, users } object
    • removed lastSeenTimestamp from user objects
    • AuthWebView exposed from @livechat/chat.io-customer-auth for React Native integration no longer needs a license prop

    [v0.3.1] - 2017-11-16

    Fixed
    • parsing server events

    [v0.3.0] - 2017-11-16

    Added
    • support for React Native apps, you can read more in "How to start" section
    • getChatsSummary method
    • destroy method
    • user_joined_chat and user_left_chat events
    • threads and thread summaries got a new property - chat
    Changed
    • updateCustomer now accepts the explicit fields property in its argument
    • thread_metadata event was renamed thread_summary

    Install

    npm i @livechat/chat.io-customer-sdk

    DownloadsWeekly Downloads

    73

    Version

    0.9.1

    License

    UNLICENSED

    Unpacked Size

    454 kB

    Total Files

    37

    Last publish

    Collaborators

    • jawinski
    • andarist
    • konradk
    • walaszczykm
    • klarzynskik
    • bartoszgamza