Install
$ agentstack add skill-felipesalinasr-fsr-stack-linkedin-comment-scraper ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
LinkedIn Comment Scraper
Overview
Extracts every commenter from a single LinkedIn post with profile enrichment data using the Apify actor harvestapi/linkedin-post-comments. The core principle: always override the actor's default maxItems cap, then deduplicate and filter null profiles before saving structured output.
When to use
- User provides a LinkedIn post URL and asks to scrape, extract, or list commenters
- Building a lead list from people who commented on a specific post
- Pulling comment text + commenter profiles for outreach personalization
- Called as a sub-step by the
linkedin-comment-to-outreachorchestrator
When NOT to use
- Scraping reactions/likes on a post — use
linkedin-reaction-scraperinstead - Private posts behind a login wall the actor cannot reach
- Paginated feeds, search results, or full-profile scrapes (different actors)
- Bulk-scraping many posts in a loop without rate-limit consideration
Prerequisites
- Apify MCP server connected with the
mcp__apify__*tools available APIFY_TOKENenvironment variable set (see../SETUP.mdfor configuration)- A valid, public LinkedIn post URL
- Write access to a local
./output/directory for the result file
Quick Reference
- Input: Public LinkedIn post URL (
/posts/,/feed/update/urn:li:activity:, or/feed/update/urn:li:ugcPost:) - Output file:
./output/linkedin_commenters.json - Apify actor:
harvestapi/linkedin-post-comments - Default
maxItemspitfall: Actor defaults to 20 — ALWAYS override to 500+ or comments will be silently truncated - MCP tools used:
mcp__apify__fetch-actor-details,mcp__apify__call-actor
The Workflow
Step 1: Validate the LinkedIn Post URL
Accept any of these URL formats:
https://www.linkedin.com/posts/username_activity-IDhttps://www.linkedin.com/feed/update/urn:li:activity:IDhttps://www.linkedin.com/feed/update/urn:li:ugcPost:ID
If the user provides a shortened or redirect URL, resolve it first via WebFetch.
Step 2: Fetch Actor Details
Use: mcp__apify__fetch-actor-details
Actor: harvestapi/linkedin-post-comments
This confirms the actor exists and returns the input schema. Key input fields:
urls(array of strings) -- LinkedIn post URLs to scrapemaxItems(number) -- Maximum results to return. DEFAULTS TO 20. Always override.
Step 3: Run a Test Scrape (maxItems: 20)
Always test first to validate the URL works and data structure is correct:
Use: mcp__apify__call-actor
Actor: harvestapi/linkedin-post-comments
Input: { "urls": ["THE_URL"], "maxItems": 20 }
Verify output fields are populated: fullName, headline, profileUrl, comment, companyName, reactions.
Step 4: Run Full Scrape (maxItems: 500+)
Once test passes, scrape everything:
Use: mcp__apify__call-actor
Actor: harvestapi/linkedin-post-comments
Input: { "urls": ["THE_URL"], "maxItems": 500 }
CRITICAL: The default maxItems is 20. Posts with 100+ comments WILL be truncated unless you explicitly set this higher. Always set to at least 500.
Step 5: Process and Deduplicate
- Parse the Apify output dataset
- Remove null profiles -- entries with null/empty
profileUrlare deleted accounts - Deduplicate by
profileUrl-- same person can comment multiple times - Normalize fields:
fullName-- keep as-isheadline-- keep as-isprofileUrl-- normalize tohttps://www.linkedin.com/in/usernameformatcompanyName-- if null, try to extract from headline (e.g., "CPA at Firm Name")comment-- the comment textreactions-- number, default 0
Step 6: Save and Report
Save processed data to ./output/linkedin_commenters.json.
Report to user:
- Total comments scraped (raw)
- Unique commenters (after dedup)
- Records removed (null profiles)
- Sample of first 5 names
Composio Fallback (Optional Path)
If the founder doesn't have a direct Apify MCP connection but does have Composio.dev MCP installed, route through Composio. One Composio subscription replaces the four separate API setups (Apify, Airtable, Apollo, Instantly).
Detection (do this first if the direct path is missing or fails):
- Check whether
mcp__composio__COMPOSIO_SEARCH_TOOLSis exposed in the current session - If yes, treat Composio as the fallback transport for this skill
Fallback workflow:
- Discover slugs and verify connection: call
mcp__composio__COMPOSIO_SEARCH_TOOLSwithuse_case: "scrape comments from a LinkedIn post URL using an Apify actor"andsession: { generate_id: true }. Save the returnedsession_idfor subsequent meta calls. - If the response shows the
apifytoolkit is NOT connected, callmcp__composio__COMPOSIO_MANAGE_CONNECTIONSwithtoolkits: ["apify"]and the samesession_id. Show the returnedredirect_urlto the user as a clickable markdown link. - Immediately follow with
mcp__composio__COMPOSIO_WAIT_FOR_CONNECTIONSto poll until the connection becomes Active. Do not ask the user to confirm. - Once connected, run the equivalent of Step 4 above using the Composio slug:
- Slug:
APIFY_RUN_ACTOR_SYNC - Input:
{ "actor_id": "harvestapi/linkedin-post-comments", "input": { "urls": ["THE_URL"], "maxItems": 500 } }
- Continue with Steps 5-6 of the standard workflow exactly as written (filter null
profileUrl, dedupe byprofileUrl, save to./output/linkedin_commenters.json).
Tool slug equivalents:
mcp__apify__fetch-actor-details->APIFY_GET_ACTORmcp__apify__call-actor->APIFY_RUN_ACTOR_SYNC(waits for completion, returns dataset inline)mcp__apify__get-actor-output->APIFY_ACTOR_RUN_GET(only needed for async runs)
Output difference: APIFY_RUN_ACTOR_SYNC returns the dataset items inline in the response body — no separate dataset fetch step needed. Parse items directly from the response.
Common Mistakes
| Mistake | Fix | |---------|-----| | Only 20 results returned | The actor's default maxItems is 20 — explicitly set maxItems: 500 or higher on every call. | | Null LinkedIn URLs in output | Filter them out. They represent deleted or deactivated accounts. | | companyName is null | Parse it from the headline field (split on " at "). | | Duplicate commenters in final list | Deduplicate by profileUrl — the same person can leave multiple comments. | | Skipping the test scrape | Run the 20-item probe first; catches bad URLs before burning a full run. | | Using a redirect/shortened URL | Resolve to the canonical linkedin.com/posts/... URL with WebFetch first. | | Long scrapes look "stuck" | 200+ comments typically takes 2-3 minutes — that is normal, do not abort. |
Output Schema
[
{
"fullName": "Jane Smith, CPA",
"headline": "Senior Accountant at Smith Advisory",
"profileUrl": "https://www.linkedin.com/in/janesmith",
"companyName": "Smith Advisory",
"comment": "This is amazing! I need to try this.",
"reactions": 3
}
]
File saved to: ./output/linkedin_commenters.json
Example
Input URL: https://www.linkedin.com/posts/example-author_post-id
- Validate the URL — it matches the
/posts/pattern, no resolution needed. - Call
mcp__apify__fetch-actor-detailsforharvestapi/linkedin-post-commentsand confirm theurls+maxItemsschema. - Test scrape:
mcp__apify__call-actorwith{ "urls": ["https://www.linkedin.com/posts/example-author_post-id"], "maxItems": 20 }. Verify the first row hasfullName,profileUrl, andcommentpopulated. - Full scrape: same call with
maxItems: 500. Wait ~2 minutes for 180 comments. - Process: 180 raw rows → drop 6 null-profile rows → dedupe by
profileUrl→ 168 unique commenters. - Save to
./output/linkedin_commenters.json.
Sample first 3 rows:
[
{
"fullName": "Jane Smith, CPA",
"headline": "Senior Accountant at Smith Advisory",
"profileUrl": "https://www.linkedin.com/in/janesmith",
"companyName": "Smith Advisory",
"comment": "This is amazing! I need to try this.",
"reactions": 3
},
{
"fullName": "Alex Rivera",
"headline": "Founder at Rivera Tax Group",
"profileUrl": "https://www.linkedin.com/in/alexrivera",
"companyName": "Rivera Tax Group",
"comment": "Saving this for next quarter.",
"reactions": 1
},
{
"fullName": "Morgan Lee",
"headline": "Tax Manager at Lee & Co",
"profileUrl": "https://www.linkedin.com/in/morganlee",
"companyName": "Lee & Co",
"comment": "Have you tried this with multi-state filings?",
"reactions": 0
}
]
Report back: 180 raw / 168 unique / 6 removed / saved to ./output/linkedin_commenters.json.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: felipesalinasr
- Source: felipesalinasr/fsr-stack
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.