Integrating Hangouts Chat and Salesforce

One of the exciting benefits of the Google and Salesforce partnership is the tight integration between your Salesforce org and G Suite. The newly released messaging platform Hangouts Chat opens up yet another opportunity for developers to create engaging integrations for their users. This blog post will show you how to build your first integrations using node.js, Apex and Einstein Intent.

Chat provides several options how a third-party system like Salesforce can be integrated:

In this post we’ll focus on examples for the most common use cases: webhooks and bots.

Pre-conditions for using Chat is having a G Suite account, and if you’re not an administrator, permissions for the Google Developer Console. From there you enable the Hangouts Chat API.

Scenario 1 – Sending on-off webhook messages

In the first scenario we’re sending a message to a Chat room via a webhook. This capability allows you to send messages directly into a Chat room, without having a bot associated with that room.

In this example (available here on GitHub) a Process Builder action is executed after a new account record is created. The action calls an invocable method. That method calls a future method, which then performs the callout to the webhook. This snippet shows how:

@future(callout=true)
public static void sendOutputMessageToRoom(String webhookUrl,
                                           String accountId,
                                           String accountName,
                                           String accountNo) {
    HttpRequest req = new HttpRequest();
    req.setEndpoint(webhookUrl);
    req.setMethod('POST');
    req.setHeader('Content-Type', 'application/json;charset=UTF-8');
    
    String url = System.Url.getSalesforceBaseUrl().toExternalForm();
    String accountUrl = url + '/lightning/r/Account/' + accountId + '/view'; // Using the new URL format!
    
    // Send formatted card message
    String message = '{"cards":..<abbreviated>...}]}';
    
    req.setBody(message);
    
    Http http = new Http();
    HttpResponse res = http.send(req);
}

Code explanation:

  • Line 7: The target webhook URL doesn’t need any authentication.
  • Line 11+12: By combining the external form of the Salesforce base url with the new Lightning URL format, we’re adding a clickable action to the message.
  • Line 14: Using the concept of a formatted card an interactive notification is sent to the Chat room.

Scenario 2 – Basic Chat bot

Webhooks are great for 1-way notifications, now let’s see an interactive integration. As outlined before, Chat provides the ability to implement bots for either one-on-one conversations or group rooms. This chart describes the communication phases:

For implementing a basic bot we’re using a node.js app running on Heroku as endpoint. Google recommends a hard-to-guess URL for security purposes. In addition to that a verification token is sent with every incoming message, that should be validated by your bot app (line 6 in the following snippet).

exports.securityCheck = (req, res) => {
  let host = req.headers["x-forwarded-for"] || req.connection.remoteHost; // Allow only Google host
  let token = req.body.token; // Get verification token
  if (
    host.indexOf(googleHost) > 0 &&
    token === process.env.GOOGLE_CHAT_TOKEN
  ) {
    return true;
  }
  res.sendStatus(401)
  return false;
};

After the security check the node.js app processes the incoming Chat messages, performs a regex match on pre-defined phrases and, in case of a successful match, performs a query against the associated org using the nforce library.


You can see in the following snippet how this is implemented:

exports.processChat = (msg, res) => {
  var answer = {};
  if (msg.type === 'ADDED_TO_SPACE' && msg.space.type === 'ROOM') {
    answer.text = infoMessage;
  } else if (msg.type === 'MESSAGE') {
    answer = processBasicChat(msg.message.text);
  }
  res.end(JSON.stringify(answer));
};

processBasicChat = (message) => {
  if (message.match("list accounts .*")) {
    let search = message.replace("list accounts ", "");
    return salesforce.listAccounts(search);
  } else if (message.match("list opportunities .*")) {
    let search = message.replace("list opportunities ", "");
    return salesforce.listOpportunities(search);
  } else {
    return commandMessage;
  }
}

Code explanation:

  • Line 4: When the bot gets added to a room a simple welcome message is returned.
  • Line 6: We’re calling the processBasicChat method with the user’s Chat text for further processing.
  • Lines 12/15: By performing a regex check on the passed Chat message, the associated search action is called.

Scenario 3 – Bot powered by Einstein Intent

If you want to provide your users a more conversational experience, compared to fixed commands, you can add Einstein Intent to the mix. Einstein Intent is a service that categorizes given text into custom labels, helping you understand what users are trying to accomplish using natural language patterns.


The intent service processes the incoming text message and determines the action type based on the trained data model. The Einstein Intent Quick Start gives you an overview of the capabilities and guides you how to train your custom intent model. By replacing the previous processBasicChat method with a new method processConversationalChat, as in this node.js app, you can implement a natural language interface for your Hangouts Chat users.

processConversationalChat = (message) => {
    if (!hasIntentAssigned(message)) {
        let label = einstein.processIntent(message);
        if (label === 'AccountSearch') {
            return 'Please specify the account name(s).';
        } else if (label === 'OpportunitySearch') {
            return 'Please specify the account name(s).';
        } else {
            return intentMessage;
        }
    } else {
        message = answerIntent(message);
    }
}

Code explanation:

  • Line 2: We’re checking if for the incoming message (identified by user mail address and Chats thread id) an intent has been identified and assigned.
  • Line 3: By calling a helper method, the incoming text message gets processed by Einstein Intent and the resulting label gets stored as a variable. Based on the variable value, an appropriate message gets sent back to the user, like asking for an account name.
  • Line 6: If an intent has already been assigned to this user, the associated action is performed.

For using this scenario you have to train Einstein Intent with the appropriate intents. You can do this by using the Einstein Language REST APIs or with the Einstein Playground.

Your next steps

These are just a few of the ways you can implement Chat connecting to your Salesforce org, and with that, take productivity for your users to the next level. So enable the API in your G Suite organization and get hands-on with the examples in this blog post:

If you don’t have G Suite yet, you can sign up for the promotion. Once you’ve explored the examples you should start building your own solutions, like with interactive cards or by directly integrating the Chat REST API.

About the Author

René Winkelmeyer works as Principal Developer Evangelist at Salesforce. He focuses on enterprise integrations, mobile, and security with the Salesforce Platform. You can follow him on Twitter @muenzpraeger.

Published
March 19, 2018

Leave your comments...

Integrating Hangouts Chat and Salesforce