Omniscope Custom Blocks › Connectors/Slack-API-WebClient

Slack API WebClient

Calls any Slack Web API method, such as conversations.list or chat.postMessage, and turns the answer into records, following every page.

Connectors › Slack Python

Open the demo in Omniscope Download demo.ioz Sample data: placeholder.csv Source on GitHub

Omniscope custom block · Connectors

Which channels are busiest, who is in them, what was said? Any Slack Web API method, with every page of the answer turned into records.

Python · requests, pandas · requests installed on first run if missing

The problem it solves

A Slack workspace holds useful operational data: how many channels there are and how big, which are archived or private, who belongs where, how active a support channel is. Slack shows these one channel at a time; the Web API has them all, as JSON in pages of up to a few hundred items, each page pointing to the next with a cursor.

This block makes the call, follows the cursor to the last page, and writes the list as records with nested values flattened into fields.

How it works

What goes in

Nothing from the workflow: the block calls Slack. The demo uses an invented conversations.list answer for a small company's workspace, so it runs without a Slack token; sample-data/placeholder.csv holds the Records output for it.

The options

Option Demo setting What it does
Slack token (empty) A bot or user token with the scopes the method needs.
API method conversations.list Any Slack Web API method.
HTTP method GET GET reads (Query Params); POST changes something (JSON Payload).
Query Params (GET) {} The method's arguments, such as {"types": "public_channel,private_channel"}.
JSON Payload (POST) (not used) The arguments for a POST, such as a channel and a message text.
Records from (empty) The list to use; empty takes the first list in the answer (channels).
Follow pages ticked Follows Slack's cursor to the last page.

What comes out

Records (first 6 channels, some fields)

id name is_private is_archived num_members topic.value purpose.value
C01000EXAMPLE general false false 212 Talk about general
C01001EXAMPLE random false false 198 About #random Talk about random
C01002EXAMPLE sales-uk false false 14 About #sales-uk Talk about sales uk
C01003EXAMPLE sales-europe false false 11 Talk about sales europe
C01004EXAMPLE support false false 37 About #support Talk about support
C01005EXAMPLE support-escalations false false 9 About #support-escalations Talk about support escalations

24 records in all, from two pages. #office-leeds is archived with no members; #finance and #hiring are private. previous_names (a list in Slack's answer) is JSON text: ["sales"] for #sales-uk.

Raw response

Two records, one per page, each holding that page's full JSON answer in Text Response.

Where it pays off

Workspace administrators: Channel housekeeping

List every channel with its size, creation time and archive state, and find empty or duplicate channels to tidy up.

Support teams: Channel activity

Load a support channel's messages with conversations.history and count questions per day, or replies per person.

Operations: Notifications from a workflow

Post a summary to a channel with chat.postMessage at the end of a scheduled workflow, after a Validate data block confirms there is something to say.

Internal communications: Membership

With conversations.members and users.list, see who is in which channels, and who has not joined an announcement channel.

Use cases describe typical scenarios and are illustrative; the sample data is invented.

Why do this in Omniscope

How it fits into an Omniscope workflow

Slack API WebClient (conversations.list) → Record Filter (not archived) → Join (owners list) → Report

Use one block per method: one for channels, another for members (conversations.members, with the channel id in Query Params), and join them on the channel id.

Try it

  1. Open the demo project (demo.iox on the demo server, or import demo.ioz from this folder). It holds the Slack block, without a token, and a File block with placeholder.csv, the 24 channels the block writes for the invented answer.
  2. The question: which channels are largest, and which are archived or empty?
  3. Follow the File block into the rest of the workflow: channels by num_members, and the archived ones.
  4. To use your own workspace: create a Slack app with the channels:read scope, enter its token in the block, run it, and connect its Records output where the File block was.

Running in Omniscope

Omniscope workflow
Omniscope workflow

The demo project's workflow: the placeholder data, the block, and a Validate data check on the output.

Language and libraries

Python. It uses requests (Apache License 2.0) and pandas (BSD 3-Clause).

pandas is part of Omniscope's Python environment. requests is listed in the block's dependencies, so Omniscope installs it with pip on first run if it is missing.

Tested

The block is covered by automated tests that run its script against a stand-in for Omniscope's Python API and invented Slack answers (no live calls): two pages combined, the requests sent for GET and POST (address, arguments, cursor, token header), an answer without a list, a chosen list and the first page only, a list of plain values, an empty list, Slack's error answers, bad JSON in the options, a rate-limited call, and 100 pages of 200 channels.

Reference

Options

NameTypeWhat it does
Slack tokenPasswordThe bot or user token (xoxb-... or xoxp-...) from your Slack app's OAuth & Permissions page. It needs the scopes of the method you call.
API methodTextThe Slack Web API method, such as conversations.list, users.list, conversations.history or chat.postMessage. See https://api.slack.com/methods.
HTTP methodChoiceGET for methods that read (arguments from Query Params); POST for methods that change something, such as chat.postMessage (arguments from JSON Payload).
JSON Payload (POST)TextArguments for a POST, as a JSON object, for example {"channel": "C0123456789", "text": "Report is ready"}.
Query Params (GET)TextArguments for a GET, as a JSON object, for example {"types": "public_channel,private_channel", "limit": 200}.
Records fromTextThe list in the answer to turn into records, such as channels, members or messages. Leave empty to use the first list in the answer.
Follow pagesYes / noRepeat the call with Slack's next cursor until the last page, and combine the records. Untick to read the first page only.

Outputs

OutputWhat it holds
RecordsOne record per item of the list in the answer (or the answer itself), all pages combined
Raw responseThe JSON text of each page Slack returned, one record per page