Channel Authenticity

Detect non-organic views / fake engagement / bot comments on a YouTube channel before booking (or after delivering) a sponsorship.

How to use it

Claude Code
  1. Run the line below. It pulls the whole folder into ~/.claude/skills/tl-channel-authenticity, including the files SKILL.md points to.
  2. Describe your job in plain words. Claude Code follows the skill from there.
Claude Code — installs the whole folder, not just SKILL.md
npx degit ThoughtLeaders-io/thoughtleaders-cli/skills/tl-channel-authenticity#main ~/.claude/skills/tl-channel-authenticity

For one project only, change the path to .claude/skills/tl-channel-authenticity. This skill also uses tl_cli.py, analyze_channel.py, engagement_ratios.py, peer_cohort.py, view_curves.py, anomaly_detector.py — copying SKILL.md alone won't be enough. See the folder on GitHub.

Claude (web or desktop app)
  1. On this page open ⋯ → Download .md.
  2. Save it as SKILL.md in a folder, zip the folder, then Customize → Skills → + → Create skill → Upload a skill.
  3. Pick the file and Save. Claude shows the name and description and runs a security scan.
  4. Check the skill is switched on.
  5. Start a new chat and describe your job in plain words. The AI follows the skill from there.
ChatGPT or another app
  1. ChatGPT: make a Project and paste it into Instructions.
  2. Neither? Paste it at the top of a new chat — it works for that chat.
Not working?
  • Check which app you pasted it into — the steps above name the right one.
  • Some skills need the paid tier of Claude or ChatGPT.
Step-by-step guide with screenshots · Ask in the forum

Paste into Claude, ChatGPT or Cursor.

Source of Channel Authenticity

Show the full text129 lines
nametl-blurbdescription
tl-channel-authenticityvet a channel for fake views> Detect non-organic views / fake engagement / bot comments on a YouTube channel before booking (or after delivering) a sponsorship. Use when asked to vet a channel, check if views/comments are real, investigate suspicious engagement, audit a sponsorship delivery, or whenever someone shares a YouTube channel/handle/URL and asks "is this real / safe to buy an ad on". Triggers: "fake views", "bot comments", "non-organic", "is this channel legit", "vet this channel", "engagement looks off", "audit this sponsorship".

Channel Authenticity

Takes a channel (handle / URL / numeric id / name) — or adlink:<id> for a sponsorship drill-down — and returns a 0–100 authenticity score plus ranked red-flag findings. Built and calibrated from real bought-view and comment-farm investigations.

Hard rules

  • One mode. Every run does everything. No flags, no opt-in tiers. Groups A, B, and C all run, every time.
  • Comment scraping (Group C) is mandatory and never skipped. Metrics and view-curves can be hand-waved ("the algorithm", "we ran ads"); reading what the audience actually says is the only direct proof. A run without it is invalid.
  • Data access is CLI-only. Everything goes through tl_cli.py and the tl CLI (tl db pg/fb/es, tl channels similar).
  • Do all data processing with the "utf-8" encoding explicitly in all scripts you create.

Setup check

cd .claude/skills/tl-channel-authenticity/scripts
python3 tl_cli.py preflight        # must print "OK"

If this errors with cli_unavailable, tell the user to run tl auth login (or set TL_API_KEY). Comment scraping additionally needs yt-dlp (pip install yt-dlp) — it uses the android InnerTube client so no cookies or API key are required.

How to run (three phases — a classifier subagent sits between two CLI passes)

Phase 1 — collect. From the scripts/ dir:

python3 analyze_channel.py "<handle|url|id|name|adlink:ID>"

This runs Groups A + B + C(rule-based), scrapes ≥10 latest longforms (+ highest-view + most-recently-sponsored), and prints a JSON envelope with state_path, llm_batch_path, and llm_batch_size.

If the ref matches multiple channels (common for names with localized dupes), Phase 1 exits (code 4) with {"error":"ambiguous_channel", "candidates":[{id,name,subscribers}…]} instead of guessing. Show the candidates to the user — they're ordered by subscriber count, highest first (the most likely intended) — let them pick, then re-run Phase 1 with that numeric id.

Phase 2 — classify comments (run the subagent TWICE). Read llm_batch_path (a JSON array of {i, text, author}) and send it to the youtube-comment-classifier agent via the Agent tool (subagent_type: youtube-comment-classifier) twice — two separate calls on the same batch. Prepend one context line: channel niche: cat <content_category>, language <language> (both values are in the envelope). Each call returns a strict JSON array [{"i":N,"label":"organic|generic-template|bot-like|promotional|spam"}]; save each reply verbatim to its own file (e.g. /tmp/ca_llm1.json, /tmp/ca_llm2.json).

Why twice: single-pass LLM labeling wobbles ±10pts, so finalize majority-votes the two passes to keep the reported organic share stable. Sophisticated AI-comment farms read as clean English at normal volume — only the classifier catches them, so this pass is essential.

If the batch is empty (channel had almost no comments), skip the subagent and pass an empty array [] — near-zero comments is itself the loudest signal, and Group C already penalizes it.

Phase 3 — finalize (pass both classifier files):

python3 analyze_channel.py --finalize <state_path> /tmp/ca_llm1.json /tmp/ca_llm2.json

This applies the LLM verdict, computes the composite score, writes the final JSON + markdown report to /tmp, and prints the report. Present that report to the user (it's already formatted — peer comparison, group scores, ranked flags, verdict).

Scoring (see references/scoring.md)

Three groups, each scored 0–100 independently (start at 100, subtract fixed per-flag penalties). Final = simple mean of the three. Two hard overrides force FRAUD_LIKELY (score capped at 39) regardless of the mean: (1) Group C — non-organic audience (<30% organic from the classifier, or a dead comment section); (2) Group B — concealed/misrepresented performance (≥2 sold+published sponsored videos deleted/unlisted, or one with ≥5k views; or ≥3 high-view videos scrubbed with ≥15% of tracked views gone).

Bands: ≥90 CLEAN · ≥70 MINOR_FLAGS · ≥40 MIXED · <40 FRAUD_LIKELY.

What each group checks

  • Group A — engagement & peer ratios (engagement_ratios.py, peer_cohort.py): like/comment rates measured against a niche-matched peer baseline, plus audience-size sanity checks across longforms vs shorts.
  • Group B — view-curve anomalies + video integrity (view_curves.py, anomaly_detector.py, video_integrity.py): view-over-time curves that don't behave like organic growth (bursts without engagement, guarantee cliffs at round numbers, frozen likes, subs flat while views surge), plus intent-aware detection of deleted/unlisted videos used to conceal or misrepresent performance (benign re-uploads are excluded).
  • Group C — comment content (comment_scraper.py, comment_analyzer.py
    • classifier subagent): whether the comments are a real, engaged audience — scarcity vs views, templating and near-duplicates, language mismatch, bot-handle patterns, and the classifier's organic-share verdict.

Full catalogue + thresholds: references/red-flags.md. The exact tl queries each check issues live in the scripts; the underlying channel/video/adlink schema is documented in the tl skill (skills/tl/references/).

After a run

Offer to log the verdict (channel, score, top flags, date) to a "Channel Vetting Log" sheet via the gws skill if the user wants an audit trail. If you discover a new robust signal, add it to references/red-flags.md and a penalty to references/scoring.md (self-improvement).

1---
2name: tl-channel-authenticity
3tl-blurb: vet a channel for fake views
4description: >
5 Detect non-organic views / fake engagement / bot comments on a YouTube
6 channel before booking (or after delivering) a sponsorship. Use when asked
7 to vet a channel, check if views/comments are real, investigate suspicious
8 engagement, audit a sponsorship delivery, or whenever someone shares a
9 YouTube channel/handle/URL and asks "is this real / safe to buy an ad on".
10 Triggers: "fake views", "bot comments", "non-organic", "is this channel
11 legit", "vet this channel", "engagement looks off", "audit this sponsorship".
12---
13 
14# Channel Authenticity
15 
16Takes a channel (handle / URL / numeric id / name) — or `adlink:<id>` for a
17sponsorship drill-down — and returns a 0–100 authenticity score plus ranked
18red-flag findings. Built and calibrated from real bought-view and comment-farm
19investigations.
20 
21## Hard rules
22 
23- **One mode. Every run does everything.** No flags, no opt-in tiers. Groups
24 A, B, and C all run, every time.
25- **Comment scraping (Group C) is mandatory and never skipped.** Metrics and
26 view-curves can be hand-waved ("the algorithm", "we ran ads"); reading what
27 the audience actually says is the only direct proof. A run without it is
28 invalid.
29- **Data access is CLI-only.** Everything goes through `tl_cli.py` and the
30 `tl` CLI (`tl db pg/fb/es`, `tl channels similar`).
31- Do all data processing with the "utf-8" encoding explicitly in all scripts
32 you create.
33 
34## Setup check
35 
36```bash
37cd .claude/skills/tl-channel-authenticity/scripts
38python3 tl_cli.py preflight # must print "OK"
39```
40If this errors with `cli_unavailable`, tell the user to run `tl auth login`
41(or set `TL_API_KEY`). Comment scraping additionally needs `yt-dlp`
42(`pip install yt-dlp`) — it uses the android InnerTube client so **no cookies
43or API key are required**.
44 
45## How to run (three phases — a classifier subagent sits between two CLI passes)
46 
47**Phase 1 — collect.** From the `scripts/` dir:
48```bash
49python3 analyze_channel.py "<handle|url|id|name|adlink:ID>"
50```
51This runs Groups A + B + C(rule-based), scrapes ≥10 latest longforms
52(+ highest-view + most-recently-sponsored), and prints a JSON envelope with
53`state_path`, `llm_batch_path`, and `llm_batch_size`.
54 
55If the ref matches **multiple channels** (common for names with localized
56dupes), Phase 1 exits (code 4) with `{"error":"ambiguous_channel",
57"candidates":[{id,name,subscribers}…]}` instead of guessing. Show the
58candidates to the user — they're ordered by subscriber count, highest first
59(the most likely intended) — let them pick, then re-run Phase 1 with that
60numeric id.
61 
62**Phase 2 — classify comments (run the subagent TWICE).** Read
63`llm_batch_path` (a JSON array of `{i, text, author}`) and send it to the
64`youtube-comment-classifier` agent via the **Agent tool**
65(`subagent_type: youtube-comment-classifier`) **twice** — two separate calls on
66the same batch. Prepend one context line: `channel niche: cat
67<content_category>, language <language>` (both values are in the envelope).
68Each call returns a strict JSON array
69`[{"i":N,"label":"organic|generic-template|bot-like|promotional|spam"}]`; save
70each reply verbatim to its own file (e.g. `/tmp/ca_llm1.json`,
71`/tmp/ca_llm2.json`).
72 
73Why twice: single-pass LLM labeling wobbles ±10pts, so finalize majority-votes
74the two passes to keep the reported organic share stable. Sophisticated
75AI-comment farms read as clean English at normal volume — only the classifier
76catches them, so this pass is essential.
77 
78If the batch is empty (channel had almost no comments), skip the subagent and
79pass an empty array `[]` — near-zero comments is itself the loudest signal,
80and Group C already penalizes it.
81 
82**Phase 3 — finalize** (pass both classifier files):
83```bash
84python3 analyze_channel.py --finalize <state_path> /tmp/ca_llm1.json /tmp/ca_llm2.json
85```
86This applies the LLM verdict, computes the composite score, writes the final
87JSON + markdown report to `/tmp`, and prints the report. Present that report
88to the user (it's already formatted — peer comparison, group scores, ranked
89flags, verdict).
90 
91## Scoring (see references/scoring.md)
92 
93Three groups, each scored 0–100 independently (start at 100, subtract fixed
94per-flag penalties). **Final = simple mean of the three.** Two hard
95overrides force `FRAUD_LIKELY` (score capped at 39) regardless of the mean:
96(1) Group C — non-organic audience (<30% organic from the classifier, or a
97dead comment section); (2) Group B — concealed/misrepresented performance
98(≥2 sold+published sponsored videos deleted/unlisted, or one with ≥5k views;
99or ≥3 high-view videos scrubbed with ≥15% of tracked views gone).
100 
101Bands: ≥90 CLEAN · ≥70 MINOR_FLAGS · ≥40 MIXED · <40 FRAUD_LIKELY.
102 
103## What each group checks
104 
105- **Group A — engagement & peer ratios** (`engagement_ratios.py`,
106 `peer_cohort.py`): like/comment rates measured against a niche-matched peer
107 baseline, plus audience-size sanity checks across longforms vs shorts.
108- **Group B — view-curve anomalies + video integrity** (`view_curves.py`,
109 `anomaly_detector.py`, `video_integrity.py`): view-over-time curves that
110 don't behave like organic growth (bursts without engagement, guarantee
111 cliffs at round numbers, frozen likes, subs flat while views surge), plus
112 intent-aware detection of deleted/unlisted videos used to conceal or
113 misrepresent performance (benign re-uploads are excluded).
114- **Group C — comment content** (`comment_scraper.py`, `comment_analyzer.py`
115 + classifier subagent): whether the comments are a real, engaged audience —
116 scarcity vs views, templating and near-duplicates, language mismatch,
117 bot-handle patterns, and the classifier's organic-share verdict.
118 
119Full catalogue + thresholds: `references/red-flags.md`. The exact `tl` queries
120each check issues live in the scripts; the underlying channel/video/adlink
121schema is documented in the `tl` skill (`skills/tl/references/`).
122 
123## After a run
124 
125Offer to log the verdict (channel, score, top flags, date) to a "Channel
126Vetting Log" sheet via the `gws` skill if the user wants an audit trail.
127If you discover a new robust signal, add it to `references/red-flags.md` and
128a penalty to `references/scoring.md` (self-improvement).
129 

Discussion

Alternatives

Also in Partners & influencersSee all 364 in Marketing →