Slack Workflow Builder: the Good, the Bad, and the Broken

Slack’s been hyping Workflow Builder since April; now that it’s out, I wanted to see what it can do, figure out how it works, void some warrantees, and try to break it. Not all of my workspaces had workflows enabled, but I found one, and started building workflows.

The first choice you make when creating a new workflow is how it will be triggered. Presumably there will be more options in the future; right now it’s just three: when a user picks it from a menu of workflows (like a macro), when a new user joins a specific channel, or when a user reacts with an emoji. Curiously, you can’t react with a message action (the on each message) which seemed like the preferred trigger over emojis — future work I suppose.

Bonus points if you can even find the “Actions menu”

Once you’ve picked the event source, you specify a sequence of steps. There you have even fewer choices: send a message or post a form.

We have both kinds of wine… white and red.

What’s pretty cool is that both the initial event and subsequent steps produce output values that subsequent steps can reference. For example, you can create a step that posts a message that @mentions the person who triggered the workflow, or you could send a message to a different user that includes a value from a form someone filled out. It’s pretty slick and despite the limited range of actions you can take today, it’s easy to imagine how Slack might extend this in the future with more action types and more outputs.

And that’s really it. It’s like a poor man’s Zapier or IFTTT. Destitute maybe. But you can see the outline of how this could expand: more event sources, more steps, and maybe more complex, branching workflows.


The basic hypothesis of workflows is that non-technical users need a visual builder. Fortunately, it’s all represented as a json object that we can download. The overall structure looks like this:

"source_id": "<looks like some unique timer-based id>",
"version": "1",
"workflow": {
"name": "name of the workflow
"blueprint": {
"version": "1",
"trigger": {
"reaction_added | channel_action | member_joined_channel",
"id": "<uuid>",
"config": {
... trigger-specific data ...
"steps": [
"type": "dialog | message",
"id": "<uuid>",
"config": {
... step-specific data ...

Triggers and steps have an id and type; the type defines the contents of the config member. The id in the trigger and each step be referenced in later steps to pull out certain info. For example, a message step looks like this:

"type": "message",
"id": "<uuid>",
"config": {
"user": {
"ref": "<uuid of trigger>==user"
"has_button": false,
"message_text": "howdy {{<uuid of trigger>==user}}!"

This sends a message to the person who triggered the workflow. Note that the user object can either have a ref member that refers to a value from a previous step or a “value” member that’s a literal value. The message can also make reference to the output from the trigger and previous steps using that mustache-ish syntax.

Let’s break it

You can craft your own json and upload new workflows. It’s pretty easy to sneak stuff past the upload step that violates the rules.

If the various steps don’t have actually unique ids, the editor gets sad without being overly explicit about what’s making it sad:

You can make poorly constructed forms with tons and tons of fields, non-unique ids, etc. The editor doesn’t complain, but when you trigger the action, the form just isn’t shown — there’s probably an entry in a lot somewhere, but there’s nothing visible to the user or the workflow author.

Silently not shown.

Finally — my personal favorite — the visual builder enforces that the number of steps in a workflow be bounded by propriety and good taste. Not so when importing workflows. I wrote a little python script that generates a workflow that sends 500 messages. This is particularly cruel because 1. it forever (about 20 minutes; I don’t know if workflows just run slow or are rate limited) and 2. it appears to be unkillable even if you unpublish the workflow (deleting it does seem to work). It would be easy to write something even more noxious… fortunately workflows do identify the author.

How to lose friends and alienate people.

Starting a workflow instantiates a state machine that walks through each step. It locks in the version of the workflow at the time it was initiated: changes to the published workflow don’t effect instances already in flight. This is a sensible approach and curtailed my plans for mischief. I can’t tell what happens to workflows that are never completed — do they hang around in some database forever or does Slack clean them up after awhile? I called the (undocumented) API, but didn’t want to DoS the new feature. But speaking of APIs…

Missions Impossible

There isn’t a documented API (that I could find) for Workflow Builder. Running Slack from the browser let me sniff out some of the calls:

Missions! That acquisition Slack made in July of 2018. And while it’s been rebranded to Workflow Builder, the name lives on in the API.

The Missions website doesn’t have much info left on it but I was able to dig up some details from the Internet Archive. Here what Missions supported: from the Internet Archive from the Internet Archive

So… a LOT more functionality in Missions than in what we see in the initial launch of Workflow Builder. It probably gives a good sense of the kinds of stuff to come.

Where Workflow Happens

Zapier already supports vastly more functionality than Workflow Builder, but I’m sure being built into Slack is compelling for a bunch of users. Even with the extremely limited functionality, you can see how triggers and steps are built to be generalized. It’s also clear that workflows are an important piece of Slack’s broader platform ambitions. There are going to be more triggers, more steps, and deep, broad integration with the zillions of cloud applications that Slack wants you working with through their collaboration platform.

Also Teams doesn’t have it; that seems pretty important.

Building computers at Oxide; past: DTrace, ZFS, Delphix CTO, Transposit founder, CEO