ClaudeLoops
/
Nightly competitor scan → Slack digest
All loops
GrowthEasy 8 min· claude-sonnet-4-5

Nightly competitor scan → Slack digest

Wake up to a 5-bullet diff of every competitor page that changed overnight.

NOT DEPLOYEDNOT DEPLOYED
0182ms
Trigger
cron(0 7 * * *) fired · every day · 07:00
021262ms
Agent
claude-sonnet-4-5 · in 1162 tok · out 587 tok
03292ms
Tools
fetch-mcp/slack:files.upload → 200 OK · 222ms
0472ms
Verify
schema check · pydantic v2 passed
05162ms
Output
notion page updated · Competitor Radar
0642ms
Notify
audit log written · runbook link attached
SUCCESS
0%
0 runs
P50
0ms
median
P95
0ms
tail
AVG COST
per run
LAST OK
never
LAST FAIL
never
none
Latency · last 30 runs0 samples
no runs yet
Latest output · what your users see
Slack· #growth-radarnow · via ClaudeLoops
Competitor diff · Thu, Jul 2
  • Linear shipped a new pricing tier ($49/mo Team) — added seat-based caps.
  • Clerk rewrote the homepage hero; H1 changed to "Ship in a weekend".
  • PlanetScale published a changelog: 4 new MCP tools, incl. `workspace.search`.
  • 2 competitors added an "AI" nav link since yesterday.
  • No pricing changes across 14 tracked pages.
scanned 14 pages · 3 diffs · 11 unchanged · next run 07:00
// press Test to run once · Watch live to keep streaming · Deploy to make it real
The problem

Manually checking competitor pricing, changelogs, and landing pages is a tax. Most days nothing meaningful changes, but you still have to look.

The outcome

A single Slack message every morning. If competitors shipped something, you see it in the first bullet. If they didn't, the message says so in one line.

Ingredients & skills

Secrets
  • ANTHROPIC_API_KEY
  • SLACK_WEBHOOK_URL
Providers
  • Anthropic
  • Slack
MCP servers
  • fetch-mcp
#growth#cron#slack

How it works

A cron-scheduled Claude agent fetches a list of competitor URLs, diffs them against yesterday's snapshot, and posts a five-bullet summary to Slack at 07:00 in your timezone.

Step 1

1 — Create the locker

In ClaudeLoops, create a locker called `competitor-radar` and add the two secrets. They are scoped to this stack only.

bash
locker create competitor-radar
locker set competitor-radar ANTHROPIC_API_KEY=sk-ant-...
locker set competitor-radar SLACK_WEBHOOK_URL=https://hooks.slack.com/...
Step 2

2 — Drop in the agent

Single file. Reads `competitors.json`, fetches each page through the fetch-mcp tool, asks Claude to diff against the previous snapshot, posts the result.

agent.ts
import Anthropic from "@anthropic-ai/sdk";
import { readFile, writeFile } from "node:fs/promises";

const client = new Anthropic();
const targets: string[] = JSON.parse(await readFile("competitors.json", "utf8"));

const snapshots = Object.fromEntries(
  await Promise.all(targets.map(async (url) => [url, await (await fetch(url)).text()]))
);
const previous = JSON.parse(await readFile("snapshot.json", "utf8").catch(() => "{}"));

const msg = await client.messages.create({
  model: "claude-sonnet-4-5",
  max_tokens: 800,
  messages: [{
    role: "user",
    content: `Diff today vs yesterday for each URL. 5 bullets max, only meaningful changes.\n\nTODAY:\n${JSON.stringify(snapshots)}\n\nYESTERDAY:\n${JSON.stringify(previous)}`,
  }],
});

await writeFile("snapshot.json", JSON.stringify(snapshots));
await fetch(process.env.SLACK_WEBHOOK_URL!, {
  method: "POST",
  body: JSON.stringify({ text: (msg.content[0] as any).text }),
});
Step 3

3 — Schedule it

Use the platform scheduler — no separate cron host. The locker is bound at runtime.

bash
locker schedule competitor-radar agent.ts --cron '0 7 * * *' --tz America/Los_Angeles
One-line deploy

The button above runs the same command with your saved config. This is the raw CLI form.

bash
npx claudeloops deploy competitor-radar

Related loops