Security News
Cloudflare Adds Security.txt Setup Wizard
Cloudflare has launched a setup wizard allowing users to easily create and manage a security.txt file for vulnerability disclosure on their websites.
@livechat/chat.io-customer-sdk
Advanced tools
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.
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.
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.
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))
We have prepared a sample chat widget implementation to present the features of chat.io Customer JS SDK:
This tutorial will help you get started with using chat.io Customer JS SDK.
First, you need to create an application in the Developers Console (select the Web app (frontend, eg. JavaScript) type).
You can use chat.io Customer JS SDK in two different ways:
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')
<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.
redirectUri
to the init
, along with the regular required properties (license
and clientId
).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)
})
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>
)
}
}
The chat.io system is based on four basic types of entities - users, chats, events and threads.
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.
{
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',
}
{
id: 'OU0V0P0OWT',
users: [{
id: 'ed9d4095-45d6-428d-5093-f8ec7f1f81b9',
lastSeenTimestamp: 1503062591000, // might be null
}],
threads: ['OU0V0U3IMN'],
}
{
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',
}
{
id: 'OU0V0U3IMN',
active: true,
order: 3,
users: ['ed9d4095-45d6-428d-5093-f8ec7f1f81b9'],
events: [ /* events */ ],
}
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 |
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()
customerSDK.disconnect()
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 loadvalue
- it's an array of loaded eventsYou 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 |
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 |
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 |
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 |
This method unsubscribes from emitted events which are described here.
This method subscribes to emitted events which are described here.
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 |
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
}
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 |
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 |
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 |
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[] |
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 |
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 |
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 | |
string | Optional email | ||
fields | object | Optionl custom fields with string values |
Returned value:
shape | type |
---|---|
success | boolean |
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 |
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)
})
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.
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 |
customerSDK.on('connection_lost', () => {
console.log('connection_lost')
})
This event doesn't carry any additional payload.
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 |
customerSDK.on('customer_id', id => {
console.log('customer id is', id)
})
Payload:
argument | type |
---|---|
id | string |
customerSDK.on('disconnected', reason => {
console.log(reason)
})
Payload:
argument | type | description |
---|---|---|
reason | string | Optional |
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 |
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 |
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 |
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 |
customerSDK.on('user_data', user => {
console.log(user)
})
User:
shape | type | description |
---|---|---|
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 |
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 |
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 |
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 |
customerSDK.on('thread_closed', ({ chat }) => {
console.log(chat)
})
Payload:
shape | type | description |
---|---|---|
chat | string | Chat's id |
customerSDK.on('thread_summary', summary => {
console.log(summary)
})
Payload:
shape | type | description |
---|---|---|
id | string | |
chat | string | Chat's ID |
order | number | |
totalEvents | number |
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 objectsupdateChatProperties
method and corresponding chat_properties_updated
eventupdateChatThreadProperties
method and corresponding
chat_thread_properties_updated
eventsendFile
returns { url }
now instead of { success: true }
order
propertypresent
propertyfile
events with url
propertycustomId
is added only if it has been explicitly passed in as part of an eventcustomId
is not reused as request's id anymoresendFile
methodCustomerSDK
dist
directorychatSummary
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 timestampsinit
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 }
objectlastSeenTimestamp
from user objectsAuthWebView
exposed from @livechat/chat.io-customer-auth
for React Native
integration no longer needs a license propgetChatsSummary
methoddestroy
methoduser_joined_chat
and user_left_chat
eventschat
updateCustomer
now accepts the explicit fields
property in its argumentthread_metadata
event was renamed thread_summary
FAQs
SDK for connecting to chat.io as a customer
The npm package @livechat/chat.io-customer-sdk receives a total of 11 weekly downloads. As such, @livechat/chat.io-customer-sdk popularity was classified as not popular.
We found that @livechat/chat.io-customer-sdk demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Cloudflare has launched a setup wizard allowing users to easily create and manage a security.txt file for vulnerability disclosure on their websites.
Security News
The Socket Research team breaks down a malicious npm package targeting the legitimate DOMPurify library. It uses obfuscated code to hide that it is exfiltrating browser and crypto wallet data.
Security News
ENISA’s 2024 report highlights the EU’s top cybersecurity threats, including rising DDoS attacks, ransomware, supply chain vulnerabilities, and weaponized AI.