Use this library to develop a bot for the Viber platform. The library is available on GitHub as well as a package on npm.
Important notes for bot developers: Please note that since 5.02.24, Viber bots can only be created on commercial terms. Before you start developing your bot in Viber please check how to apply for a bot creation here.
This library is released under the terms of the Apache 2.0 license. See License for more information.
This library is released on npm.
Install with npm install viber-bot --save
If you are already using express or equivalent, you can do the following:
app.use("/viber/webhook", bot.middleware());
Please revisit app.use() documentation. For more information see ViberBot.middleware().
Creating a basic Viber bot is simple:
viber-bot
library to your projectbot.middleware()
setWebhook(url)
with your web server urlFirstly, let’s import and configure our bot:
'use strict';
const ViberBot = require('viber-bot').Bot;
const BotEvents = require('viber-bot').Events;
const bot = new ViberBot({
authToken: YOUR_AUTH_TOKEN_HERE,
name: "EchoBot",
avatar: "https://viber.com/avatar.jpg" // It is recommended to be 720x720, and no more than 100kb.
});
// Perfect! Now here's the key part:
bot.on(BotEvents.MESSAGE_RECEIVED, (message, response) => {
// Echo's back the message to the client. Your bot logic should sit here.
response.send(message);
});
// Wasn't that easy? Let's create HTTPS server and set the webhook:
const https = require('https');
const port = process.env.PORT || 8080;
// Viber will push messages sent to this URL. Web server should be internet-facing.
const webhookUrl = process.env.WEBHOOK_URL;
const httpsOptions = {
key: ...,
cert: ...,
ca: ...
}; // Trusted SSL certification (not self-signed).
https.createServer(httpsOptions, bot.middleware()).listen(port, () => bot.setWebhook(webhookUrl));
We provide an option to use Winston logger with our library. The only requirement is that you use Winston >= 2.0.0.
'use strict';
const ViberBot = require('viber-bot').Bot;
const winston = require('winston');
const toYAML = require('winston-console-formatter'); // makes the output more friendly
function createLogger() {
const logger = new winston.Logger({
level: "debug"
}); // We recommend DEBUG for development
logger.add(winston.transports.Console, toYAML.config());
return logger;
}
const logger = createLogger();
const bot = new ViberBot({
logger: logger,
authToken: ...,
...
});
Well funny you ask. Yes we do. But a word of warning - messages sent to your router callback will also be emitted to the BotEvents.MESSAGE_RECEIVED
event.
const TextMessage = require('viber-bot').Message.Text;
// A simple regular expression to answer messages in the form of 'hi' and 'hello'.
bot.onTextMessage(/^hi|hello$/i, (message, response) =>
response.send(new TextMessage(`Hi there ${response.userProfile.name}. I am ${bot.name}`)));
Have you noticed how we created the TextMessage
instance? There’s a all bunch of message types you should get familiar with.
Creating them is easy! Every message object has its own unique constructor corresponding to its API implementation. Click on each type in the list to find out more. Check out the full API documentation for more advanced uses.
require('viber-bot').Bot
An event emitter, emitting events described here.
promise.JSON
promise.JSON
promise.JSON
promise.JSON
promise.ARRAY
handler
= TextMessageHandlerCallback
handler
= ErrorHandlerCallback
onFinish
= ConversationStartedOnFinishCallback
handler
= SubscribeResponseHandlerCallback
handler
= UnsubscribeResponseHandlerCallback
Param | Type | Description |
---|---|---|
options.logger | object |
Winston logger |
options.authToken | string |
Viber Auth Token |
options.name | string |
Your BOT Name |
options.avatar | string |
Avatar URL. No more than 100kb. |
options.registerToEvents | array |
example: [“message”, “delivered”] |
require('viber-bot').Events
Param | Type |
---|---|
handler | EventHandlerCallback |
message | Message Object |
response | Response Object |
err | Error Object |
Subscribe to events:
function (message, response) {}
)function (message, userProfile) {}
)function (response) {}
)function (response) {}
)function (userProfile, isSubscribed, context, onFinish) {}
)function (err) {}
)Example
bot.on(BotEvents.MESSAGE_RECEIVED, (message, response) => ... );
bot.on(BotEvents.MESSAGE_SENT, (message, userProfile) => ... );
bot.on(BotEvents.CONVERSATION_STARTED, (userProfile, isSubscribed, context, onFinish) => ... );
bot.on(BotEvents.ERROR, err => ... );
bot.on(BotEvents.UNSUBSCRIBED, response => ... );
bot.on(BotEvents.SUBSCRIBED, response =>
response.send(`Thanks for subscribing, ${response.userProfile.name}`));
Returns a promise.JSON
with the following JSON.
bot.getBotProfile().then(response => console.log(`Bot Named: ${response.name}`));
Param | Type | Description |
---|---|---|
userProfile | UserProfile |
UserProfile object |
The getUserDetails
function will fetch the details of a specific Viber user based on his unique user ID. The user ID can be obtained from the callbacks sent to the account regarding user’s actions. This request can be sent twice during a 12 hours period for each user ID.
Returns a promise.JSON
.
bot.onSubscribe(response => bot.getUserDetails(response.userProfile)
.then(userDetails => console.log(userDetails)));
Param | Type | Description |
---|---|---|
viberUserIds | array of strings |
Collection of Viber user ids |
Returns a promise.JSON
.
bot.getOnlineStatus(["a1, "a2"]).then(onlineStatus => console.log(onlineStatus));
Param | Type | Description |
---|---|---|
url | string |
Trusted SSL Certificate |
Returns a promise.JSON
.
bot.setWebhook("https://my.bot/incoming").then(() => yourBot.doSomething()).catch(err => console.log(err));
Param | Type | Description |
---|---|---|
userProfile | UserProfile |
UserProfile object |
messages | object or array |
Can be Message object or array of Message objects |
[optionalTrackingData] | JSON |
Optional. JSON Object. Returned on every message sent by the client |
Note: When passing array of messages to sendMessage
, messages will be sent by explicit order (the order which they were given to the sendMessage
method). The library will also cancel all custom keyboards except the last one, sending only the last message keyboard.
Returns a promise.ARRAY
array of message tokens.
// Single message
const TextMessage = require('viber-bot').Message.Text;
bot.sendMessage(userProfile, new TextMessage("Thanks for shopping with us"));
// Multiple messages
const UrlMessage = require('viber-bot').Message.Url;
bot.sendMessage(userProfile, [
new TextMessage("Here's the product you've requested:"),
new UrlMessage("https://my.ecommerce.site/product1"),
new TextMessage("Shipping time: 1-3 business days")
]);
Returns a middleware implementation to use with http/https
.
const https = require('https');
https.createServer({
key: ...,
cert: ...,
ca: ...
}, bot.middleware()).listen(8080);
Param | Type |
---|---|
regex | regular expression |
handler | TextMessageHandlerCallback |
function (message, response) {}
bot.onTextMessage(/^hi|hello$/i, (message, response) =>
response.send(new TextMessage(`Hi there ${response.userProfile.name}. I am ${bot.name}`)));
Param | Type |
---|---|
handler | ErrorHandlerCallback |
function (err) {}
bot.onError(err => logger.error(err));
Param | Type | Description |
---|---|---|
userProfile | UserProfile |
UserProfile object |
isSubscribed | boolean | Indicates whether a user is already subscribed |
context | String | Any additional parameters added to the deep link used to access the conversation passed as a string |
onFinish | ConversationStartedOnFinishCallback |
When called, a Message will be sent to the client |
Conversation started event fires when a user opens a conversation with the bot using the “message” button (found on the account’s info screen) or using a deep link.
This event is not considered a subscribe event and doesn’t allow the account to send messages to the user; however, it will allow sending one “welcome message” to the user. See sending a welcome message below for more information.
function (responseMessage, optionalTrackingData) {}
The ConversationStartedOnFinishCallback
accepts null
and MessageObject
only. Otherwise, an exception is thrown.
bot.onConversationStarted((userProfile, isSubscribed, context, onFinish) =>
onFinish(new TextMessage(`Hi, ${userProfile.name}! Nice to meet you.`)));
bot.onConversationStarted((userProfile, isSubscribed, context, onFinish) =>
onFinish(new TextMessage(`Thanks`), {
saidThanks: true
}));
The ConversationStartedOnFinishCallback
isn’t compatible with certain keyboard features, and therefore sendMessage
is preferable when sending messages with keyboards.
const KEYBOARD_JSON = {
...
}
const message = new TextMessage("new text",KEYBOARD_JSON,null,null,null,3);
bot.onConversationStarted((userProfile, isSubscribed, context) =>
bot.sendMessage(userProfile,message)
);
Param | Type |
---|---|
handler | SubscribeResponseHandlerCallback |
function (response) {}
bot.onSubscribe(response => console.log(`Subscribed: ${response.userProfile.name}`));
Param | Type |
---|---|
handler | UnsubscribeResponseHandlerCallback |
function (userId) {}
bot.onUnsubscribe(userId => console.log(`Unsubscribed: ${userId}`));
Members:
Param | Type | Notes |
---|---|---|
userProfile | UserProfile |
— |
promise.JSON
Members:
Param | Type | Notes |
---|---|---|
id | string |
— |
name | string |
— |
avatar | string |
Optional Avatar URL |
country | string |
currently set in CONVERSATION_STARTED event only |
language | string |
currently set in CONVERSATION_STARTED event only |
const TextMessage = require('viber-bot').Message.Text;
const UrlMessage = require('viber-bot').Message.Url;
const ContactMessage = require('viber-bot').Message.Contact;
const PictureMessage = require('viber-bot').Message.Picture;
const VideoMessage = require('viber-bot').Message.Video;
const LocationMessage = require('viber-bot').Message.Location;
const StickerMessage = require('viber-bot').Message.Sticker;
const RichMediaMessage = require('viber-bot').Message.RichMedia;
const KeyboardMessage = require('viber-bot').Message.Keyboard;
Common Members for Message
interface:
Param | Type | Description |
---|---|---|
timestamp | string |
Epoch time |
token | string |
Sequential message token |
trackingData | JSON |
JSON Tracking Data from Viber Client |
Common Constructor Arguments Message
interface:
Param | Type | Description |
---|---|---|
optionalKeyboard | JSON |
Writing Custom Keyboards |
optionalTrackingData | JSON |
Data to be saved on Viber Client device, and sent back each time message is received |
Member | Type |
---|---|
text | string |
const message = new TextMessage(text, [optionalKeyboard], [optionalTrackingData]);
console.log(message.text);
Note: to enable features that have an api level requirement in your keyboard, it’s necessary to add the following arguments to the KeyboardMessage constructor:
TextMessage(text, [optionalKeyboard], [optionalTrackingData], null, null, [minApiVersion])
[minApiVersion]
should be an integer value of the desired minimum api version/level for the message.
Member | Type |
---|---|
url | string |
const message = new UrlMessage(url, [optionalKeyboard], [optionalTrackingData]);
console.log(message.url);
Member | Type |
---|---|
contactName | string |
contactPhoneNumber | string |
const message = new ContactMessage(contactName, contactPhoneNumber, [optionalAvatar], [optionalKeyboard], [optionalTrackingData]);
console.log(`${message.contactName}, ${message.contactPhoneNumber}`);
Member | Type |
---|---|
url | string |
text | string |
thumbnail | string |
const message = new PictureMessage(url, [optionalText], [optionalThumbnail], [optionalKeyboard], [optionalTrackingData]);
console.log(`${message.url}, ${message.text}, ${message.thumbnail}`);
Member | Type |
---|---|
url | string |
size | int |
thumbnail | string |
duration | int |
const message = new VideoMessage(url, size, [optionalText], [optionalThumbnail], [optionalDuration], [optionalKeyboard], [optionalTrackingData]);
console.log(`${message.url}, ${message.size}, ${message.thumbnail}, ${message.duration}`);
Member | Type |
---|---|
latitude | float |
longitude | float |
const message = new LocationMessage(latitude, longitude, [optionalKeyboard], [optionalTrackingData]);
console.log(`${message.latitude}, ${message.longitude}`);
Member | Type |
---|---|
stickerId | int |
const message = new StickerMessage(stickerId, [optionalKeyboard], [optionalTrackingData]);
console.log(message.stickerId);
Member | Type |
---|---|
url | string |
sizeInBytes | int |
filename | string |
const message = new FileMessage(url, sizeInBytes, filename, [optionalKeyboard], [optionalTrackingData]);
console.log(`${message.url}, ${message.sizeInBytes}, ${message.filename}`);
Member | Type |
---|---|
richMedia | Object |
const SAMPLE_RICH_MEDIA = {
"ButtonsGroupColumns": 6,
"ButtonsGroupRows": 2,
"BgColor": "#FFFFFF",
"Buttons": [{
"ActionBody": "https://www.website.com/go_here",
"ActionType": "open-url",
"BgMediaType": "picture",
"Image": "https://www.images.com/img.jpg",
"BgColor": "#000000",
"TextOpacity": 60,
"Rows": 4,
"Columns": 6
}, {
"ActionBody": "https://www.website.com/go_here",
"ActionType": "open-url",
"BgColor": "#85bb65",
"Text": "Buy",
"TextOpacity": 60,
"Rows": 1,
"Columns": 6
}]
};
const message = new RichMediaMessage(SAMPLE_RICH_MEDIA, [optionalKeyboard], [optionalTrackingData]);
Member | Type |
---|---|
keyboard | JSON |
const SAMPLE_KEYBOARD = {
"Type": "keyboard",
"Revision": 1,
"Buttons": [
{
"Columns": 3,
"Rows": 2,
"BgColor": "#e6f5ff",
"BgMedia": "https://www.jqueryscript.net/images/Simplest-Responsive-jQuery-Image-Lightbox-Plugin-simple-lightbox.jpg",
"BgMediaType": "picture",
"BgLoop": true,
"ActionType": "reply",
"ActionBody": "Yes"
}
]
};
const message = new KeyboardMessage(SAMPLE_KEYBOARD, [optionalTrackingData]);
Note: to enable features that have an api level requirement in your keyboard, it’s necessary to add the following arguments to the KeyboardMessage constructor:
KeyboardMessage(SAMPLE_KEYBOARD, [optionalTrackingData], null, null, [minApiVersion])
[minApiVersion]
should be an integer value of the desired minimum api version/level for the message.
We’ve created the Is It Up sample project to help you get started.
Join the conversation on Gitter.