Competitor Tracker & Co. Docs

Slack

Connect a Slack workspace to Competitor Tracker & Co.: pick the channels that get the Monday brief, expand a competitor into its own thread, run the slash commands and disconnect.

Every Monday a pack of agents files what it found. Connect Slack and that report also lands in the channels you name, next to the people who were going to argue about it anyway. Your guide here is our lead detective C. T. Lucky. For parameter-level detail, see the API reference in the sidebar.

One thing to be straight about up front. Slack does not make anything arrive sooner. We read your competitors once a week and we file the brief once a week, and the Slack post rides the same Monday send as the email. What moves is where the reading happens. A channel the whole team can see, instead of one person's inbox on a busy morning.

Connect a workspace

An admin starts the install, Slack asks them to approve it and the workspace comes back bound to your organization. Nothing else on your account changes.

The binding is one to one. A workspace belongs to one organization and an organization to one workspace. Installing into a workspace that another organization already holds is refused with SlackWorkspaceBoundElsewhere, and connecting a second workspace to an organization that has one is refused with SlackOrgAlreadyConnected. One workspace, one case file.

GET /v1/dispatches/slack

The connected workspace, who connected it and the channels currently on the brief. Members can read it.

# Who are we posting for, and where.
curl "$CT_API/dispatches/slack" \
  -H "Authorization: Bearer $CT_TOKEN"
{
  "teamId": "T0123ABCDEF",
  "teamName": "Acme Workspace",
  "connectedAt": "2026-08-24T09:12:03.000Z",
  "connectedBy": {
    "userId": "01HF...",
    "email": "dana@acme.example",
    "name": "Dana"
  },
  "channels": [
    {
      "id": "C0123ABCDEF",
      "name": "competitors",
      "connectedAt": "2026-08-24T09:13:41.000Z"
    }
  ]
}

Returns 200 OK. 404 SlackInstallationNotFound when your organization has no workspace connected. connectedBy is null when the account that ran the install has since left.

When nobody has an account yet

A team can also install us from the Slack App Directory before anyone here has signed up. We take the installer through email sign-up and send them back to Slack with the workspace connected and their new organization under them, as its owner.

Abandon the sign-up halfway and nothing is left behind. No organization, no half-finished connection, nothing showing as connected to nobody. Come back later and start again from the top.

Choose the channels

The picker lists the workspace's own channels, public and private, minus the archived ones. Pick as many as you like. Every one of them gets the same brief on the same Monday.

A public channel works whether or not you have invited us into it. A private channel has to add the app before we can post there, which is a Slack rule rather than ours. Until it does, you can see the channel in the list and we cannot write to it.

Picking nothing is a real setting, not a mistake. The connection stays and the brief goes nowhere. Removing the last channel does the same thing and leaves the workspace connected, so you can go quiet for a while without tearing the install down.

What lands on Monday

One message per brief per channel. It opens with your organization's name, the week number and the window the brief covers, then a line counting what moved against what we watched. Under that comes a block for each competitor that moved, with the headline change and an Expand button.

Then the shorter lists. The ones that moved a little, by name and counts. The ones that held still, by name only. On a week when nobody moved at all, the message says so in a line and stops there.

Slack limits how much one message can carry, and a busy week hits that limit long before we run out of competitors. So we post what fits, say how many competitors are shown out of how many moved, and link the rest to your browser. The file is thicker than the summary.

Expand a competitor

Each competitor in the posted brief carries an Expand button. Click it and that competitor's detail arrives as a new message in the channel, not as a reply tucked under the brief.

That is deliberate, and it is the reason to have any of this in Slack. One Monday post covers your whole roster. A reply would bury each competitor's detail under a summary about all of them and squeeze the week into a single thread. A separate message gives every competitor a thread of its own. The argument about a rival's new pricing page then runs beside the one about somebody's shipped integration rather than on top of it.

The detail lists up to 12 changes from the window the brief covered and links to your browser when there are more. The original brief stays exactly where it was. Expanding needs a connected account — the next section covers that. A click arriving from a workspace whose connection has been removed is declined rather than answered.

Slash commands

One command, /competitortracker. Type it with nothing after it and you get a menu. Type a verb and it runs. Every reply is visible only to the person who typed it, so nobody floods a channel by listing 40 competitors.

CommandWhat it does
add <url> [name]Start tracking a competitor at a URL
list [search]List the competitors your organization tracks
view <competitor-id>Show one competitor's details
timeline <competitor-id>Show what has happened to a competitor
remove <competitor-id>Stop tracking a competitor
changes [competitor]List the changes already found across your competitors
brief [competitor]Count what the recent runs found, by priority
labels list | create <name> [as <color>] | assign <competitor> <label> | unassign <competitor> <label>Create labels, list them and put them on competitors
helpShow what this command can do

Most verbs answer to a second name, if that is what your fingers reach for: track, competitors, show, history, untrack, recent, summary, label and menu. Give a verb arguments it can't read and the reply is that verb's own usage line. Type a verb we don't know at all and you get the whole list back.

add costs a coin a month, the same as adding a competitor anywhere else. Run it with an empty balance and the reply says so and links you to the top-up page rather than failing quietly. See Billing.

The menu

Billing, members and organization settings are not rebuilt here. The menu links to them in your browser, carrying the organization the workspace is bound to, so a person who belongs to two of them can tell which one they are about to open. What the menu shows depends on your role: an owner sees the transfer-and-close entry, an admin doesn't. No money moves and no membership changes inside Slack.

Connect your account

A command runs as you, not as the workspace. The first time you type one we hand you a link and ask you to sign in.

We could skip that. Slack knows a verified email for everyone in the workspace and we could match it to an account in one lookup. We don't, because a workspace administrator can change a member's email address, and these commands reach your competitor list, your labels and the door to your billing. So the link is proved by you signing in to your own account, and what you may then do comes from your role in the organization. Slack vouches for nobody here.

What you typed is held while you go. Sign in, come back and it runs, no retyping. If your role is short of what a verb needs, the reply names the role you'd need instead of handing you an error code.

Language

A brief carries a language, and its Slack posts are written in it.

PATCH /v1/dispatches/{id}

# German for this brief's channel posts. Admin-only.
curl -X PATCH "$CT_API/dispatches/01HF..." \
  -H "Authorization: Bearer $CT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "language": "de" }'

language is en, de or fr, and every brief starts at en. It sets the language of what we post to your channels for that brief. A reply only you can see follows the language on your organization's default brief, since a slash command isn't attached to any one of them.

Said plainly: the brief email is still English whatever you set here. Slack is translated and the mail is not. That is a gap rather than a decision, and it closes in a piece of work of its own. Everything else on the Dispatches page still applies.

Disconnect

DELETE /v1/dispatches/slack

Admin-only. Returns 204 No Content, or 404 SlackInstallationNotFound if there was nothing connected. Your channels stop receiving the brief from the next Monday on, slash commands stop answering and the Expand buttons on old posts go quiet.

Two things disconnecting does not do, both worth knowing before you press it.

Heads up

Disconnecting stops the channels receiving updates. It does not remove the app from your Slack workspace. The app sits there until a Slack admin removes it on that side.

It also doesn't unlink anybody. Connect the workspace again and nobody on the team has to sign in a second time. Moving channels around, replacing a bad install or reinstalling after somebody removed the app in Slack are all routine admin jobs, and none of them should cost the whole team a round of sign-ins.

What we keep

Enough to post your brief and no more: the workspace's id and display name, the channels you picked, which account each Slack identity belongs to and one record per post saying whether it landed. Delivery records show up in the log alongside email and webhook attempts, described on Dispatches.

What we don't take is the longer list. We ask Slack for no permission to read channel history, so we never see what your team says in the channel we post to. We ask for no permission to read Slack profiles either. The only thing we hold about a person is the opaque id Slack uses for them, plus the account they proved they own by signing in.

See also

  • Dispatches for the brief itself: recipients, label scoping, webhooks and the delivery log.
  • Competitors for what the tracking commands act on.
  • Labels for the labels the labels verbs create and assign.
  • Billing for what a coin buys and how to top up.

On this page