KOL Discovery
Build a ranked KOL list by combining a post-data half (LinkedIn post search ->
aggregate by author -> deterministic engagement scoring) with a web-research half
(the agent finds conference speakers, newsletter/podcast hosts via web search). The
agent does keyword generation and web research; the bundled scripts do the post fetch
and the scoring math.
When to use
- "Find KOLs / influencers in [industry]" / "who are the thought leaders for [domain]?"
- "Run KOL discovery for [client]" — authority voices, not complainers.
- Upstream of
linkedin-message-writer / linkedin-outreach for influencer engagement.
How it works (agent + scripts)
- (agent) Intake domain, audience, seeds, exclusions, scoring thresholds. Generate
15-25 authority/thought-leadership keywords (industry terms, "future of...", conference/
event terms, content-creator signals) + KOL title keywords + vendor-exclusion patterns.
Present for approval before running (controls Apify cost).
- Post search — for each approved keyword, pull LinkedIn posts (bundled
post_search.py, same as linkedin-post-research: Apify if APIFY_API_TOKEN set, else
keyless serp degrade). Concatenate all keyword results into one posts JSON.
- Score — aggregate by author and rank (bundled
score_kols.py).
- (agent) Web research — find known KOLs (top-[industry]-influencer searches, conference
speakers, newsletter/podcast hosts). Write them as
web_kols.json
([{name, linkedin_url, source, notes}]).
- Merge — pass
--web-kols web_kols.json to score_kols.py; overlaps are flagged
source: both (the strongest KOLs); web-only entries appear as source: web-research.
How to run
Run a post search per keyword and collect into one file, then score:
# Step 2 — collect posts (loop keywords; append into posts.json yourself, or run per batch)
python3 ${SKILL_DIR}/scripts/post_search.py \
--keywords "future of rpa,agentic automation,intelligent automation" \
--max-items 50 --sort-by relevance --output json > ${WORKSPACE}/posts.json
# Step 3+5 — aggregate, score, merge web-researched KOLs
python3 ${SKILL_DIR}/scripts/score_kols.py \
--posts ${WORKSPACE}/posts.json \
--web-kols ${WORKSPACE}/web_kols.json \
--min-posts 2 --min-total-engagement 50 --top-n 50 --output csv
score_kols.py flag |
Default |
Meaning |
--posts |
(required) |
JSON list of posts (post_search output shape). |
--web-kols |
"" |
JSON list of web-researched KOLs to merge/flag. |
--min-posts |
1 |
Drop authors below this post count. |
--min-total-engagement |
0 |
Drop authors below total reactions+comments. |
--top-n |
50 |
Cap returned KOLs. |
--output |
json |
json / csv / summary. |
Outputs
Ranked KOL list: {rank, name, linkedin_url, headline, kol_score, total_posts, total_reactions, total_comments, avg_engagement, top_post_url, top_post_preview, source(post-data|web-research|both)}.
Credentials / env
env.required: none — the serp post-search degrade + web research backbone need no key.
env.optional: APIFY_API_TOKEN — if set → LinkedIn posts-search actor (accurate
engagement metrics for the post-data scoring half); else → keyless serp (the default; no
engagement counts → weaker scoring, lean on web-research KOLs).
Notes & edge cases
- Search authority keywords, not pain-language — the goal is voices who shape the
conversation.
- Always run a small/test pass first (few keywords) before the full run to control Apify cost.
- Too many irrelevant authors -> tighten domain keywords + exclusions; too few -> lower
--min-posts / --min-total-engagement. Overlaps (source: both) are the strongest KOLs.
1---2name: kol-discovery3description: Find Key Opinion Leaders in a domain by searching LinkedIn posts for prolific, high-engagement authors and merging them with web-researched influencers (conference speakers, newsletter authors, podcast hosts) into a ranked, scored KOL list. Use when the goal is authority/thought-leadership voices, not pain-language leads.4---56# KOL Discovery78Build a ranked KOL list by combining a **post-data half** (LinkedIn post search ->9aggregate by author -> deterministic engagement scoring) with a **web-research half**10(the agent finds conference speakers, newsletter/podcast hosts via web search). The11agent does keyword generation and web research; the bundled scripts do the post fetch12and the scoring math.1314## When to use1516- "Find KOLs / influencers in [industry]" / "who are the thought leaders for [domain]?"17- "Run KOL discovery for [client]" — authority voices, not complainers.18- Upstream of `linkedin-message-writer` / `linkedin-outreach` for influencer engagement.1920## How it works (agent + scripts)21221. **(agent)** Intake domain, audience, seeds, exclusions, scoring thresholds. Generate23 15-25 authority/thought-leadership keywords (industry terms, "future of...", conference/24 event terms, content-creator signals) + KOL title keywords + vendor-exclusion patterns.25 **Present for approval** before running (controls Apify cost).262. **Post search** — for each approved keyword, pull LinkedIn posts (bundled27 `post_search.py`, same as `linkedin-post-research`: Apify if `APIFY_API_TOKEN` set, else28 keyless serp degrade). Concatenate all keyword results into one posts JSON.293. **Score** — aggregate by author and rank (bundled `score_kols.py`).304. **(agent)** Web research — find known KOLs (top-[industry]-influencer searches, conference31 speakers, newsletter/podcast hosts). Write them as `web_kols.json`32 (`[{name, linkedin_url, source, notes}]`).335. **Merge** — pass `--web-kols web_kols.json` to `score_kols.py`; overlaps are flagged34 `source: both` (the strongest KOLs); web-only entries appear as `source: web-research`.3536## How to run3738Run a post search per keyword and collect into one file, then score:3940```bash41# Step 2 — collect posts (loop keywords; append into posts.json yourself, or run per batch)42python3 ${SKILL_DIR}/scripts/post_search.py \43 --keywords "future of rpa,agentic automation,intelligent automation" \44 --max-items 50 --sort-by relevance --output json > ${WORKSPACE}/posts.json4546# Step 3+5 — aggregate, score, merge web-researched KOLs47python3 ${SKILL_DIR}/scripts/score_kols.py \48 --posts ${WORKSPACE}/posts.json \49 --web-kols ${WORKSPACE}/web_kols.json \50 --min-posts 2 --min-total-engagement 50 --top-n 50 --output csv51```5253| `score_kols.py` flag | Default | Meaning |54|---|---|---|55| `--posts` | (required) | JSON list of posts (post_search output shape). |56| `--web-kols` | `""` | JSON list of web-researched KOLs to merge/flag. |57| `--min-posts` | `1` | Drop authors below this post count. |58| `--min-total-engagement` | `0` | Drop authors below total reactions+comments. |59| `--top-n` | `50` | Cap returned KOLs. |60| `--output` | `json` | `json` / `csv` / `summary`. |6162## Outputs6364Ranked KOL list: `{rank, name, linkedin_url, headline, kol_score, total_posts,65total_reactions, total_comments, avg_engagement, top_post_url, top_post_preview,66source(post-data|web-research|both)}`.6768## Credentials / env6970- `env.required`: **none** — the serp post-search degrade + web research backbone need no key.71- `env.optional`: `APIFY_API_TOKEN` — **if set → LinkedIn posts-search actor (accurate72 engagement metrics for the post-data scoring half); else → keyless serp** (the default; no73 engagement counts → weaker scoring, lean on web-research KOLs).7475## Notes & edge cases7677- Search **authority** keywords, not pain-language — the goal is voices who shape the78 conversation.79- Always run a small/test pass first (few keywords) before the full run to control Apify cost.80- Too many irrelevant authors -> tighten domain keywords + exclusions; too few -> lower81 `--min-posts` / `--min-total-engagement`. Overlaps (`source: both`) are the strongest KOLs.