KOLens
All posts
·KOLens teamWatchlistMonitoringAlerts

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

Pre-redesign: watchlist showed "who I'm watching" with stats + a sparkline. Post-redesign: signal badges, latest-video thumbnail, outreach status pill, brand-fit stars, rows sorted by priority. Open on Monday → top rows are the ones that actually moved over the weekend.

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_kol alert under 14 days old. Label format: "+12K followers".
  • 📈 trending_video — unread trending_video alert. 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_contactDBContact.fetched_at is after the watchlist entry's added_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

  1. Avatar + handle + verification + inline brand-fit stars
  2. Signal badge row (the centrepiece)
  3. Latest video strip — thumbnail (via the /api/img proxy so CORS is sane), caption, view count, recency colour- coded green / amber based on freshness
  4. Compact stats row (followers / ER / avg views) + a smaller sparkline below it
  5. Outreach pill — status + days-since-last-touch + event count, linked to /crm/{conversation_id}. Falls back to a mailto when no conversation exists yet
  6. 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 + .note columns so operators can stash 🔥 hot / ⏳ pending / ❌ skip
  • ER-drop signal — heavier query (joins DBVideoSnapshot trend) 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.

READY?

Try it now — 50 free credits on signup.

Open your Watchlist

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

Watchlist as a monitoring dashboard, not a bookmark list · KOLens | KOLens