Watchlist as a monitoring dashboard, not a bookmark list
The old watchlist answered 'who am I watching'. The new one answers the question that actually matters: 'of the KOLs I'm watching, who needs my attention right now?'
The shift
Why the old watchlist underperformed
The watchlist had the data — KOLens already runs a growth detector that produces rising_kol and trending_video alerts; the dossier already knows when someone last posted; the CRM already tracks outreach conversations. None of it surfaced on the watchlist card. Operators had to open each dossier separately to discover what changed.
The redesign is essentially a UI surface for data we were already computing. No new pipelines, no new credit costs — just a different aggregation layer that turns the watchlist into the triage entry point it always should have been.
The six signals
- 🔥 rising_kol — unread
rising_kolalert under 14 days old. Label format:"+12K followers". - 📈 trending_video — unread
trending_videoalert. Label:"Trending video · 2.3M views". - 💤 dormant — last post >14 days ago. Label carries the day count so the badge is informative even without a tooltip.
- 💰 new_sponsored — at least one#ad / #sponsored post in the last 14 days. Tells you the creator is taking collabs without you having to scroll their grid.
- 📧 new_contact —
DBContact.fetched_atis after the watchlist entry'sadded_at. The creator had no email when you starred them; one was surfaced since. - 💬 no_outreach — no conversation in the active workspace, OR last event >30 days ago. The watchlist is supposed to drive action; this badge nags you when it's not.
What each card now shows
- Avatar + handle + verification + inline brand-fit stars
- Signal badge row (the centrepiece)
- Latest video strip — thumbnail (via the
/api/imgproxy so CORS is sane), caption, view count, recency colour- coded green / amber based on freshness - Compact stats row (followers / ER / avg views) + a smaller sparkline below it
- Outreach pill — status + days-since-last-touch + event count, linked to
/crm/{conversation_id}. Falls back to a mailto when no conversation exists yet - Footer: "Watching for N days" + "View profile →" link
Server-side priority sort
Rows with high-severity signals bubble to the top. The score function lives in the page component (deliberately client- readable for ops debugging):
- rising_kol / trending_video → 100 each
- new_contact → 60
- dormant → 40
- new_sponsored → 30
- no_outreach → 10
Ties broken by recency (most-recently-starred first). The result: on a 30-row watchlist with two creators that hit viral videos last week, those two land at the top of the page on every load until the operator acknowledges or contacts them.
The API change is additive
GET /api/watchlist takes a new ?signals=true query. Default off, so existing callers (CLI plugin, MCP list_watchlist) see the same response shape they always saw. The web /watchlist page opts in.
Coming next (PR-B)
- Sort / filter UI on the page — "show only rows with new signals"
watchlist_entries.tags+.notecolumns so operators can stash 🔥 hot / ⏳ pending / ❌ skip- ER-drop signal — heavier query (joins
DBVideoSnapshottrend) so we deferred it
Drop comments / requests in the channel that's most natural for your team — we'll cycle them into the next iteration.
Frequently asked
- What signals fire automatically?
- Six kinds: rising_kol and trending_video pull from the existing DBGrowthAlert table (the growth detector that's been running for months). The other four are computed at request time — dormant from DBVideo.created_at, new_sponsored from is_sponsored / is_ad in last 14 days, new_contact when DBContact.fetched_at is after DBWatchlistEntry.added_at, no_outreach when there's no conversation or last_event_at is >30d ago.
- Does this slow the page down on big watchlists?
- Signal computation is one batched query per signal kind, not N×6 round-trips. The expensive ones (growth alerts + outreach status) are workspace-scoped joins; the cheap ones (dormant / sponsored ratio) read DBVideo with the existing author_username index. A 50-row watchlist renders in <300ms typical.
- What about the brand-fit star rating?
- Pulled FREE from the cached Creator Overview row — no LLM call. If the workspace brand profile is set AND we've already generated an overview for this KOL in the past 30 days, the star rating shows inline next to the handle. Tiny visual cue that adds zero credit cost.
- Can I sort or filter?
- Server-side sorting by signal priority (rising / trending / new_contact first, then dormant / sponsored, then no_outreach) is the current default. Explicit sort dropdowns and filter chips (e.g. 'show only with new signals') are on the next-iteration list — PR-B from the watchlist proposal.
- Is the API change backwards-compatible?
- Yes. GET /api/watchlist still returns the old shape by default. ?signals=true opts into the enriched payload, which adds signals[] / latest_video / outreach / recommendation_score fields. Existing CLI/MCP callers stay on the cheap path.
Read next
Push KOLens growth alerts to Slack, your inbox, or any webhook URL
KOLens alerts now ship to email + webhook the moment the detector fires. Slack inbound URLs, Zapier, custom endpoints — same JSON payload, configurable per-channel mute, throttle to avoid burst spam.
The brand-fit dossier — Creator Overview, Deep Analysis, and Background Research
Three layered LLM reads on every creator: a free scored Creator Overview gated on the brand profile, a 5-credit Deep Analysis premium tier, and web-grounded Background Research with citations. All cached, all locale-aware.