← All workflow playbooks

Continuous Competitor Monitoring with Claude Code, Step by Step

Date: July 6, 2026 • Author: Second Axis

Most product teams track competitors with duct tape: Visualping monitors on pricing pages, Google Alerts firing mostly noise, an RSS-to-Slack pipe someone set up two jobs ago. Even paid tooling draws the complaint; as one PM put it, "KLUE... relies on manual input and becomes outdated very quickly". The failure mode is always the same: the tool detects that something changed, and a human still decides whether it matters and what it means.

Can you build the real thing with Claude Code: 15-25 competitors watched continuously, every change diffed against prior state, a weekly brief of only material changes with interpretation, immediate alerts on big moves? Yes. This playbook is the complete build.


What you're building

Every Monday, without you touching anything:

  • A weekly brief covering 15-25 competitors, listing only material changes across pricing, packaging, features, changelogs, positioning, executive hires, press, and funding.
  • Every item diffed against that competitor's prior state. Not "here is their pricing page" but "Pro moved from $39 to $49 per seat, annual-only, first change since March."
  • Interpretation, not just detection. Each item carries a "what this means for us" line grounded in your positioning.
  • A "no material changes" brief when that is the truth. An empty brief that says so builds trust; padding kills it.
  • Immediate alerts for big moves: a pricing change or major launch pings Slack the day it happens, not next Monday.

Why one-off "research competitor X" chats do not compound

Open Claude Code today, ask it to research Acme's pricing and recent launches, and you get a decent answer. Ask next month and you get another decent answer that has no idea what the first one said. One-off research chats fail this job structurally: no prior state, so nothing can be diffed; no diff, so every finding reads as equally new; no record of what was already reported, so week six re-announces the funding round from week two. Continuity is not something you prompt for; you engineer it, as state committed to a repo that every run reads first.

Then the arithmetic. Twenty competitors times 5-8 watched pages is 100-160 pages per week. A marketing page as text runs 5-15K tokens, so naively reading every page weekly pushes 0.5-2.4 million tokens through a model just to notice that mostly nothing changed; raw HTML is several times worse. The fix is the layer this playbook is really about: distill pages into normalized claims, diff the claims, spend model attention only on what moved.


Phase 0: Prerequisites

  • Claude Code installed and authenticated, on a Pro, Max, Team, or Enterprise plan for the scheduling and publishing steps.
  • Your competitor list, written down. Names, domains, and for each the 5-8 URLs worth watching: pricing, changelog, product pages, blog, careers page for exec moves.
  • A useful head start: Anthropic's open-source knowledge-work-plugins include a Product Management plugin with a /competitive-brief command. Good scaffolding for one-off briefs; the state, diffing, and scheduling below are the part it lacks.
  • Python 3.11+ for the crawl scripts Claude Code will write.
  • A dedicated git repo. The recurring design depends on committed state.
  • A conduct decision. The crawl respects robots.txt and fetches at low frequency; stay inside each site's terms of service, and never crawl behind a login.

Phase 1: The repo, with state per competitor

competitor-intel/
├── CLAUDE.md
├── positioning.md              # YOUR strategy; interpretation is graded against it
├── .claude/
│   ├── agents/
│   │   ├── competitor-analyst.md
│   │   ├── materiality-judge.md
│   │   └── synthesizer.md
│   └── skills/
│       ├── competitor-watch/SKILL.md   # weekly full pass
│       └── pricing-check/SKILL.md      # daily light pass
├── scripts/
│   ├── crawl.py                # fetch watched URLs, robots.txt-aware
│   └── distill.py              # page text → normalized claims
├── state/                      # committed: the system's memory
│   └── acme/
│       ├── urls.yaml           # watched URLs
│       ├── known_facts.json    # dated registry of reported facts
│       └── summaries/          # last distilled summary per URL
├── data/                       # gitignored: raw HTML snapshots
└── runs/                       # committed: briefs, diffs, alert log

The design unit is the per-competitor state directory. urls.yaml is the watch list. summaries/ holds the last distilled summary per page, which next week's crawl diffs against. known_facts.json is the registry of everything already reported, dated and sourced: "2026-05-14: raised $30M Series B (press release)". Every run reads it before writing anything, which is what stops the brief from re-announcing old news. All committed; raw HTML snapshots are gitignored and disposable.

CLAUDE.md carries the standing rules: work from summaries and diffs, never raw HTML in context; every claim cites a diff line or URL; check known_facts.json before calling anything new; never edit scripts/ in a scheduled run.


Phase 2: Crawl and distill

Have Claude Code write both scripts in an interactive session of real back-and-forth.

crawl.py reads every urls.yaml, checks robots.txt, fetches each allowed page with a descriptive user agent and delays between requests, and writes raw snapshots to data/<competitor>/<date>/. Specify: timeouts and retries, a dead-URL report (a 404 on a watched page is itself a finding), and an HTML-to-text step.

distill.py is the load-bearing trick. Do not diff raw HTML: marketing pages churn constantly for cosmetic reasons (rotating testimonials, A/B copy, new hero images), and diffing them drowns you in noise. Instead, an extraction pass normalizes each page's text into flat, comparable claims:

pricing: Pro plan: $49/seat/month
packaging: SSO moved from Enterprise to Pro
feature: "AI summaries" listed under Analytics
positioning: headline targets "revenue teams" (was "sales teams")

A 10K-token page becomes a 300-600 token claim summary, and the diff becomes semantic: a changed line means something actually changed. Extraction runs through Claude Code during the weekly session (about 120 pages at this scale), or a small-model API script if you want it decoupled; either way the summaries, not the raw pages, get committed to state/<competitor>/summaries/.


Phase 3: Diff, then judge

The weekly run diffs each new distilled summary against the committed prior one; whatever changed becomes a candidate with its diff attached. Then the judge kills the noise.

.claude/agents/materiality-judge.md

---
name: materiality-judge
description: Filters candidate changes down to material ones
tools: Read
---
A change survives ONLY if it concerns pricing, packaging,
features, positioning, people, or money. Kill on sight:
hero images, testimonial rotation, blog cadence, layout,
copy tweaks that change no claim.

Each survivor must have: evidence (diff line or URL),
a date, and no match in that competitor's known_facts.json.
Return the filtered list plus a kill log with one-line
reasons, so a human can audit what was suppressed.

The judge makes the brief readable. Without it, "Acme changed their homepage" appears every week, and the week Acme actually reprices, nobody notices.


Phase 4: Analysts in parallel, then one brief

.claude/agents/competitor-analyst.md

---
name: competitor-analyst
description: Analyzes one competitor's changes since the last run
tools: Read, Bash, WebSearch
model: inherit
---
You analyze exactly ONE competitor, named in your task prompt.
Read only state/<competitor>/ and this run's diffs for it.

1. Interpret each surviving diff: what changed, since when,
   what it signals.
2. Web-search news, funding, and exec hires since the
   last_checked date in known_facts.json. Attach URLs.
3. Cross-check against known_facts.json. Already registered
   means not news. Drop it.
4. Per material item, one "what this means for us" line
   grounded in positioning.md. No generic commentary.

The weekly skill fans these out, one per competitor, in parallel. Each analyst has its own context window and reads only its competitor's state and new snapshots; twenty competitors never compete for one context. This is the multi-agent fan-out, and where web search earns its keep: page diffs catch what competitors publish on their own sites; search catches funding, press, and hires that never touch a watched URL.

.claude/agents/synthesizer.md merges the outputs into the brief, ordered by materiality. Two standing rules: every item carries evidence and a date, and if nothing material survived, the brief says exactly that in one paragraph and stops. The week your brief says "no material changes across all 20" and a spot-check confirms it is the week the system earns permanent trust.

The final step writes new summaries into state/, appends facts to known_facts.json, saves the brief to runs/<date>/, and commits. Committed state is next week's prior state.


Phase 5: Scheduling, weekly and daily

Two cadences:

  • /competitor-watch, weekly: full crawl of all watched pages, distill, diff, judge, analyst fan-out, synthesize, commit, publish.
  • /pricing-check, daily: a light pass crawling only the pricing pages (20-25 fetches), distill, diff. On a material pricing or packaging change it posts an immediate Slack alert with the diff, and registers the fact so the weekly brief references it instead of re-breaking it. With changelogs on the daily list, big launches surface the same way.

The managed path is cloud routines: run /schedule in Claude Code and create both. Each run executes in a cloud sandbox that clones the repo's default branch; cloning is the state-passing mechanism, which is why state lives in git. Check that the sandbox's network access mode permits the crawl and web search, and decide who merges the claude/-prefixed branches. Routine runs draw on plan usage; this pair is a modest draw, but watch /usage early.

Self-hosted alternative: system cron running headless mode (claude -p "/competitor-watch" with --allowedTools scoped to the pipeline), or a GitHub Actions cron with the official claude-code-action, whose docs include a scheduled daily-report example. You gain control; you own the babysitting.

Either way, add a Stop hook posting run status to Slack. A monitoring system that silently died three weeks ago is worse than none: everyone believes it is still watching.


Phase 6: Sharing with the team

  • Artifact publish. Claude Code renders the weekly brief as a hosted page on claude.ai; subsequent publishes reuse the URL, so "this week's competitive brief" is a stable link, org-scoped on Team/Enterprise plans. The series-wide caveat: publishing works from the CLI and desktop app, not every automated surface, so the publish step may be where a human stays in the loop.
  • Slack. The daily alert path posts pricing and launch events; the weekly post carries the top three items and a link to the full brief.
  • Downstream, when ready: the same state can feed sales enablement, with talk tracks and battlecard objections updated when pricing or packaging changes. An extension, not week one.

Phase 7: Maintenance (what you own now)

  • Watched-URL rot. The crawl's dead-URL report is a weekly review item: fix or drop, in a PR to urls.yaml.
  • Redesigns break extraction. A relaunch can garble distilled claims, which then diff as a false wall of change. When a diff touches most of a page, re-check the extraction before believing it.
  • Competitor list churn. Startups die, get acquired, or fade; new ones appear. Quarterly, prune and add state directories.
  • Materiality threshold tuning. Read the kill log for the first month. Too strict misses a quiet packaging change; too loose bloats the brief until nobody reads it.
  • Known-facts registry hygiene. A registry nobody audits slowly poisons the "is this new?" check. Skim each file quarterly; correct facts a competitor has walked back.

What this costs

The crawl is nearly free: 100-160 weekly fetches plus 20-25 daily ones, trivial bandwidth, zero tokens. The money is in the model layers. Assumptions: 20 competitors, 6 pages each, 5-15K tokens per page as text.

  • Extraction: roughly 0.6-1.8M input tokens weekly if every page is re-distilled, less if you skip pages whose raw text hash is unchanged. Inside the weekly session this is subscription usage; as a small-model API script, a metered line item sized from those token counts and current published rates.
  • Analysis: twenty analysts each reading a few KB of state and diffs plus targeted searches, then a judge and synthesizer. This scales with how much changed, not how much you watch, and most weeks little changes; it fits within subscription usage. The risk, as ever, is an agent wandering off its rails into raw snapshots.
  • Plan tier: routines and org-scoped artifact sharing need the same tiers as the rest of the series.
  • The invoice nobody prints: URL curation, threshold tuning, registry hygiene, redesign triage. Cheaper in time than the manual-input treadmill the Reddit thread complains about, but not zero, and someone owns it by name.

The four practical challenges

  1. Setup at scale: the distill-then-diff architecture (Phases 2-3), because 100-160 churning pages a week must become semantic claims before any model attention is spent.
  2. Sharing with the team: artifact publish plus the two-speed Slack path (Phase 6), with the automation caveat on publishing.
  3. Maintenance: URL rot, redesigns, list churn, threshold tuning, registry hygiene (Phase 7). The recurring human duties are the system.
  4. Cost: cheap crawl, modest and mostly-subscription token spend that scales with change volume, plus curation time that never appears in /usage.

The managed alternative

The competitive-intelligence category is real: Klue and Crayon are the established platforms, and page monitors like Visualping cover the change-detection slice alone. The fair trade: a supported product, integrations, and battlecard tooling on day one, none of the build above. The known gap is the one this post opened with: platforms leaning on manual curation go stale quickly, as the Reddit complaint about Klue describes, and interpretation in your strategic context, the "what this means for us" line graded against your own positioning, is not in the box.

Doing this with Second Axis

Everything above is the do-it-yourself path. On Second Axis, competitor monitoring is a workflow in the marketplace: connect your competitor list and Slack, choose the workflow, and set the goal ("weekly material-changes brief on these 20 companies, instant alert on pricing moves"). It runs on schedule from there, with per-competitor memory built in, and it monitors itself: dead URLs, failed crawls, and failed runs get found and alerted instead of silently rotting the brief.