Disclaimer: This app is not associated with the company Slack, I’m just a fan of it and analytics.
I talk a lot about the measurement protocol and the ways that you can send data to Google Analytics from sensors, CRM systems, and tons of places and devices beside websites. But now I am going to discuss something a little different — how to send data from a bot application to be able to do textual analysis.
Slackalytics is a simple node.js app that I built with Joe Zeoli to monitor my teams slack account.
This is a long post so feel free to jump around
What is Slack?
What does Slackalytics monitor for and do?
Why?
Visualizing the Slackalytics Data
GA Custom Reports
Slackalytics in Google Sheets
Implementing Stackalytics on your account
Setting up GA
The App Code
Grab it from Github and Deploy it with Heroku
Setting it up in Slack
Developer? Jump straight to github.
It’s a great real time messaging app with tons of addon’s and ways to configure it out and hook up integrations and with their robust API’s, a developer’s playground. Read more about it on the slack site
Every message that comes through a channel the bot reads it, and sends the following custom dimensions and custom metrics to GA with the measurement protocol.
Dimensions
User Id
Channel Name
Metrics
Word count
Letter count
Emoticon count
Exclamation point count !!!
Question mark count ???
Ellipse count …
3 Reasons:
1 – I wanted to see the times of days my team was most active and how people used it. In my consulting days with multiple clients I could’ve used this to keep track of when my clients were most active on Slack so I could make sure some one was manning that channel.
2 – I built a couple bots for a couple chat apps I use with my friends and wanted to make sure they were using them and get an easy report of what/when the bot was active.
3 – The most important reason: Why not?! It’s important to learn about different kinds of analysis and measurement. I had fun building a couple giphy bots and love using Google Analytics in new ways.
This one shows Channels by Activity (every event is a message post) and custom metrics.
You can see that Adobe Products channel had the most discussions with about 22 words per message (channel word count/ channel total events). That is because it’s mostly used to explain/ask some difficult questions we uncover. Water cooler is just what it sounds like, our banter channel and people are very excited hence the 55 exclamation points spread out over 55 messages. Someone must have posted some animal pics.
We can also break it down by user:
Above you see the user ID’s which we need to use because PII is not allowed in GA. However, I want to see the data with my team members names so lets move to Google sheets with the Google Analytics Sheets Addon to add the data in there.
Quick tip: In order to match up the users names with their ID’s you need to pull that data out of slack. There are different ways to do that but one easy way is to scrape the data from the team directory. If you’re on {your team name}.slack.com/team and add the following code to the console it will print out all the names and ID’s.
var urls = document.getElementsByClassName('lazy member_preview_link member_image thumb_72') for (var i = 0; i < urls.length; i++) { var ids = urls[i].dataset.memberId var names = urls[i].href.split('/')[4] if (urls[i].dataset.memberId) { console.log(ids + " " + names) } };
It doesn’t fully automate it but it’s a quick fix.
Coming soon! Check back in the next couple days.
I created a new property so it doesn’t mix with my web data and you can follow these steps to do that.
I use 2 custom dimensions and 5 custom metrics so you’ll need to set them in the Admin page of the property you want to use.
Set up the custom dimensions and metrics as follows:
You can also Fork it on Github
/* THIS APP IS OPEN SOURCE UNDER THE MIT LICENSE The MIT License (MIT) Copyright (c) 2015 Nico Miceli Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ //Setup Requirements var express = require('express'); var bodyParser = require('body-parser'); var request = require('request'); var qs = require('querystring'); //Server Details var app = express(); var port = process.env.PORT || 3000; //Set Body Parser app.use(bodyParser.urlencoded({extended: true})); app.use(bodyParser.json()); app.use(bodyParser.json({ type: 'application/vnd.api+json' })); //Routes app.get('/', function(req, res){ res.send('here'); }); //This is where we create the POST request and send the data to GA. app.post('/collect', function(req, res){ //create object for the channel and user id var channel = { id: req.body.channel_id, name: req.body.channel_name }; var user = { id: req.body.user_id }; var msgText = req.body.text; //2 algorithms to count different things in the message text function searchM(regex){ var searchStr = msgText.match(regex); if(searchStr != null){ return searchStr.length; } return 0; }; function searchS(regex){ var searchStr = msgText.split(regex); if(searchStr != undefined){ return searchStr.length; } return 0; }; var wordCount = searchS(/\s+\b/); var emojiCount = searchM(/:[a-z_0-9]*:/g); var exclaCount = searchM(/!/g); var questionMark = searchM(/\?/g); var elipseCount = searchM(/\.\.\./g); //The Structure Data! This is where are the pretty GA data gets gathered //before it is sent to the GA servers for us to analyse at a later time. var data = { v: 1, tid: "UA-XXXXXXX-1", // <-- ADD UA NUMBER cid: user.id, ds: "slack", //data source cs: "slack", // campaign source cd1: user.id, cd2: channel.name, cd3: msgText, cm1: wordCount, cm2: emojiCount, cm3: exclaCount, // note we’re skipping CM4 cm5: elipseCount, cm6: questionMark, //need to set up in GA t: "event", ec: "slack: "+ channel.name + "|" + channel.id, ea: "post by " + user.id, el: msgText, ev: 1 }; console.log(JSON.stringify(data)); console.log(req.body); //Now Make Post Request! request.post("https://www.google-analytics.com/collect?" + qs.stringify(data), function(error, resp, body){ console.log(error); }) }); //Start Server app.listen(port, function () { console.log('Listening on port ' + port); });
You can fork it here or follow the below steps. Note: I am using Heroku because it is so easy but you will need to have a Heroku account and heroku command line tools installed.
If you haven’t deployed anything with git and Heroku you can read the full guide here.
git clone http://github.com/NicoMiceli/slackalytics.git cd slackalytics
Now update the app.js file with your GA Account ID (UA Number)
git init heroku create git add . git commit -m "initial commit" git push heroku master
Get the url endpoint for your app from the command line or from your Heroku account and then add it to a Slack integration.
Go to configure integrations and create a new Outgoing Webhook.
We are going to use the outgoing webhooks to send data to GA. We need to configure them so they collect data in the different channels.
Channel (red circle 1) – Pick the channel that you want this bot to live in. If you have multiple channels that you want to track you will need to create multiple Outgoing webhooks.
Trigger Words (red circle 2) – Leave this blank since we are doing our textual analysis in the node bot.
URLs (red circle 3) – This is where you add the URL endpoints
That’s it!
Save it and open up the real time reports in GA and send some messages to see if they are coming through.
If they are not coming through then you can check the app console logs with the following command.
heroku logs -t
If you see any errors then there is a problem in the app. Try reverting back to original code or commenting out any changes you might have made and then publishing the app again.
Let me know some new metrics that you use on twitter @nicomiceli or in the comments.