Skip to main content

How to send dynamic charts with a Slack bot

Slack bots are limited by the Slack API to specific formats: text, images, and special controls. Critically, they cannot send Javascript or other dynamic formats. In order to send a chart or graph to your Slack channel, you must first render it as an image.

A chart on Slack

In this tutorial we'll use the free and open-source QuickChart API to generate chart images. To send these charts to Slack, you must:

  1. Construct the chart image
  2. Include it in your Slack bot's message

This tutorial is written assuming you are using Javascript, but the approach is general enough to work for any language.

Creating a chart image

If you're already showing these charts on a web frontend, your work here might already be done because QuickChart is built on top of Chart.js. You can just use your existing Chart.js config. Otherwise, we have to construct a Chart.js config object.

For example, imagine we have the following data:

RetweetsLikes
1280
542
40215
530

First create an object using the Chart.js format:

const chart = {
type: 'bar',
data: {
labels: ['Week 1', 'Week 2', 'Week 3', 'Week 4'],
datasets: [
{
label: 'Retweets',
data: [12, 5, 40, 5],
},
{
label: 'Likes',
data: [80, 42, 215, 30],
},
],
},
};

This object says that we have two data series, Retweets and Likes, and they each have values. The labels for the X axis are Weeks 1-4.

Next, we turn the JSON chart specification into a string:

const encodedChart = encodeURIComponent(JSON.stringify(chart));

And put it into our URL:

const chartUrl = `https://quickchart.io/chart?c=${encodedChart}`;

This gives a URL that encodes the chart object. Let's render that URL in an image tag:

<img src="https://quickchart.io/chart?c=..." />

We get the image below:

Rendered chart image, ready to go on Slack

To learn more about static chart rendering:

Sending the chart image to Slack

Now that we've generated a chart image, let's send it to Slack.

You have a couple options here:

  • Upload the file to Slack
  • Include the URL in a normal message and have Slack show or "unfurl" it
  • Use the Image Block

We'll go with the third choice because it is the most practical. We construct a block like so, using the image URL from above.

[
{
"type": "image",
"title": {
"type": "plain_text",
"text": "Latest data"
},
"block_id": "quickchart-image",
"image_url": "https://quickchart.io/chart?bkg=white&c=%7B%0A%20%20type%3A%20%27bar%27%2C%0A%20%20data%3A%20%7B%0A%20%20%20%20labels%3A%20%5B%27Week%201%27%2C%20%27Week%202%27%2C%20%27Week%203%27%2C%20%27Week%204%27%5D%2C%0A%20%20%20%20datasets%3A%20%5B%7B%0A%20%20%20%20%20%20label%3A%20%27Retweets%27%2C%0A%20%20%20%20%20%20data%3A%20%5B12%2C%205%2C%2040%2C%205%5D%0A%20%20%20%20%7D%2C%20%7B%0A%20%20%20%20%20%20label%3A%20%27Likes%27%2C%0A%20%20%20%20%20%20data%3A%20%5B80%2C%2042%2C%20215%2C%2030%5D%0A%20%20%20%20%7D%5D%0A%20%20%7D%0A%7D",
"alt_text": "Chart showing latest data"
}
]

You can try this directly in Slack's Block Kit Builder. Have a look at the Slack documentation and play around with the different settings:

Slack block kit builder

In order to send the image blocks from your bot, use Slack's chat.postMessage API endpoint.

Starting with the basics, let's use this boilerplate for our communication with the Slack API. If you're using a helper library you probably already have a way to send messages, but here is the boilerplate I always use:

const request = require('request');

// Put your bot token here.
const SLACK_BOT_USER_TOKEN = 'xyz123';

function sendMessage(data) {
request(
{
url: 'https://slack.com/api/chat.postMessage',
method: 'POST',
json: data,
headers: {
'Content-Type': 'application/json; charset=utf-8',
Authorization: `Bearer ${SLACK_BOT_USER_TOKEN}`,
},
},
function (error, response, body) {
if (error || response.statusCode !== 200) {
console.error('Error sending slack response:', error);
} else if (!response.body.ok) {
console.error('Slack responded with error:', response.body);
} else {
// All good!
}
},
);
}

Now, we'll put it all together and send the message with chart image URL:

sendMessage({
text: 'Chart data update',
blocks: [
{
type: 'image',
title: {
type: 'plain_text',
text: 'Latest data',
},
block_id: 'quickchart-image',
image_url:
'https://quickchart.io/chart?bkg=white&c=%7B%0A%20%20type%3A%20%27bar%27%2C%0A%20%20data%3A%20%7B%0A%20%20%20%20labels%3A%20%5B%27Week%201%27%2C%20%27Week%202%27%2C%20%27Week%203%27%2C%20%27Week%204%27%5D%2C%0A%20%20%20%20datasets%3A%20%5B%7B%0A%20%20%20%20%20%20label%3A%20%27Retweets%27%2C%0A%20%20%20%20%20%20data%3A%20%5B12%2C%205%2C%2040%2C%205%5D%0A%20%20%20%20%7D%2C%20%7B%0A%20%20%20%20%20%20label%3A%20%27Likes%27%2C%0A%20%20%20%20%20%20data%3A%20%5B80%2C%2042%2C%20215%2C%2030%5D%0A%20%20%20%20%7D%5D%0A%20%20%7D%0A%7D',
alt_text: 'Chart showing latest data',
},
],
});

That's it! Our message is sent and the graph appears in Slack.

Graph from a Slack bot

Need more help? Ask questions in our community.


Ian Webster

About the author

Ian Webster is a software engineer and former Googler based in San Mateo, California. He has helped Google, NASA, and governments around the world improve their data pipelines and visualizations. In 2018, Ian created QuickChart, a collection of open-source APIs that support data visualization efforts.

Email · LinkedIn · Twitter