LinkedIn Post Comments Scraper By Keyword & Engagement Filter
Pricing
from $3.99 / 1,000 results
LinkedIn Post Comments Scraper By Keyword & Engagement Filter
๐ฌ Scrape LinkedIn post comments & replies in bulk. ๐ Get likes, reactions, author names & profile links. ๐ Filter by date. ๐ Add multiple posts at once. No login required by default.
Pricing
from $3.99 / 1,000 results
Rating
0.0
(0)
Developer
Scrapio
Maintained by CommunityActor stats
0
Bookmarked
3
Total users
0
Monthly active users
a day ago
Last modified
Categories
Share
LinkedIn Comment Scraper โ Comments, Buying Signals & Contacts
A LinkedIn comment scraper that returns typed JSON, not a raw comment dump: point it at LinkedIn post URLs and it pulls every top-level comment, narrows the set with a filter stack (keyword, reactions, length, author, exact date range), then scores each survivor 0โ100 for buying intent against a fully auditable keyword lexicon โ no model, no black box. Every kept row also carries any email, phone number, mention or hashtag found inside the comment text. Unlike scraping frameworks that hand back raw HTML for you to parse, this Actor returns typed JSON โ ready for a CRM, a spreadsheet, or an LLM prompt with no cleanup step. Below: every input parameter, every output field read from the source code, and how sales, growth and research teams actually run it.
๐งญ What Does This LinkedIn Comment Scraper Do?
It scrapes comments from one or more LinkedIn posts, runs a deterministic keyword-and-reaction filter stack over them before anything is saved, then attaches a 0โ100 buying-signal score, a tier label, in-text contact extraction, mentions and hashtags to every row that survives. No LinkedIn account or login is required โ the default engine is the logged-out public post page. Supplying a LinkedIn li_at session cookie is optional and only changes what the Actor can reach (more comments per post, nested replies, commenter headline and picture), not whether it runs at all.
- Scrapes top-level comments from public LinkedIn posts by URL, activity URN, or bare numeric activity ID
- Filters comments by keyword match/exclude, minimum reactions, minimum length, post-author exclusion, and an exact date range before any row is written
- Scores every surviving comment 0โ100 for buying intent with a named, weighted, auditable term match
- Extracts in-text email addresses, phone numbers, URLs, @mentions and #hashtags from the comment body
- Optionally escalates to LinkedIn's authenticated comment engine with a supplied
li_atcookie to reach the full comment list and nested replies - Optionally adds AI-generated sentiment, an intent label and a short summary per comment, using your own API key for a provider of your choice
โก Features & Capabilities
Core features
- Dual engine, one output shape. The default logged-out engine (
sourceEngine: "public_page") parses the same LinkedIn post page an anonymous visitor sees โ comment text, exact absolute UTC timestamp, per-comment reaction count, author name, author profile URL and avatar, all read from two independent, cross-checked surfaces on that one response (the page'sapplication/ld+jsonblock and the server-rendered comment DOM). SupplyingliAtCookieescalates to the authenticated Voyager GraphQL engine (sourceEngine: "voyager"), which reaches the full paginated comment list and nested replies. - Filter before you pay.
filterKeywords,excludeKeywords,minReactions,minCommentLength,excludeAuthorComments,postedFrom/postedTo/postedLimitandminBuyingSignalScoreare all applied before a row is written to the dataset โ the filtered-out comments never appear in the output and are not billed. - Deterministic buying-signal scoring, no API key.
buyingSignalScore,buyingSignalTier,buyingSignalMatchesandbuyingSignalReasonsare computed by a fixed keyword lexicon (signals.py) โ every point on the score traces back to a literal phrase, its category and its weight. - In-text contact extraction.
contactInTextEmail,contactInTextPhone,contactInTextUrl(plus the fullcontactEmailsInText/contactPhonesInText/contactUrlsInTextarrays) are pulled from the comment body with regexes hardened against known false positives โ an@handleis never read as an email, and a bare licence or ID number is never read as a phone number. - Honest coverage reporting. Every row carries
commentsAvailable(comments actually scanned),commentsTotal(the post's real comment count, read from LinkedIn's own page metadata) andcommentsCoveragePctโ so a partial slice is always visible, never silently hidden.
How this LinkedIn comment scraper compares to other options
| Feature | This Actor | apimaestro (no-cookies) | benjarapi |
|---|---|---|---|
| Output format | Typed JSON, stable schema | Typed JSON | Typed JSON |
| Keyword/reaction/length pre-filtering | โ Built in, applied before save | โ Not documented | โ Not documented |
| Deterministic buying-intent score | โ 0โ100, auditable term list | โ Not documented | โ Not documented |
| In-text email/phone/URL extraction | โ Built in | โ Not documented | โ Not documented |
| Exact date-range filter | โ
postedFrom/postedTo | โ Not documented | โ Not documented |
| Logged-out (no cookie) by default | โ | โ | Not documented (implies login-based access) |
| Nested reply extraction | โ
With li_at cookie | โ | โ |
| Optional AI sentiment/intent/summary | โ Bring your own key, off by default | โ Not documented | โ Not documented |
Comparison built from each competitor's own Apify Store listing, checked 2026-07-26. If your use case is feeding structured comment data to an LLM or a CRM enrichment step, the pre-filtering and scoring rows are the decision-maker โ piping thousands of unscored raw comments into an agent loop and asking it to find the three that matter is a reliability failure mode, not a feature.
When another tool might suit you better
If you need every comment and reply on a viral post with tens of thousands of comments and no interest in filtering or scoring โ just a full export โ a batch-oriented scraper built around raw volume, such as apimaestro's no-cookies comment scraper (4,336 users, 663,413 runs as observed on its Apify Store listing, checked 2026-07-26), is a reasonable fit. This Actor is built around narrowing the set down to the comments that matter for outreach, not around maximizing raw comment count per run, and its default logged-out engine caps out around 9โ10 top-level comments per post before a li_at cookie is supplied.
LinkedIn Comment Scraper within the Scrapio data stack
This Actor covers post comments and their buying-intent scoring. For monitoring LinkedIn posts themselves for new brand or keyword mentions over time, use LinkedIn Post Keyword Monitor. For scoring the credibility of a commenter's or prospect's profile rather than their comment, use LinkedIn Profile Credibility Scraper. Both are Scrapio Actors and share this Actor's logged-out-first approach to LinkedIn.
Why do developers and data teams scrape LinkedIn comments?
Comment sections under company and founder posts are one of the few places B2B buying intent shows up unprompted, in public, in the prospect's own words โ before a demo request ever reaches a CRM.
๐ข Sales development and demand generation
An SDR team points the Actor at a competitor's or an industry influencer's recent posts, sets filterKeywords to commercial terms ("pricing", "demo", "how much"), and reads back rows where buyingSignalScore is 50 or higher. authorProfileSlug and author.profile_url go straight into a CRM lookup or a Sales Navigator search; contactInTextEmail sometimes shortcuts that step entirely when a commenter drops their address in the thread.
๐ AI training data and RAG indexing
text, buyingSignalReasons and (when AI enrichment is on) summary are the high-information fields for both use cases: RAG enrichment, where text plus the scored buyingSignalMatches give a retrieval system pre-labeled intent signal rather than raw prose to re-classify at query time; and training-data construction, where buyingSignalTier, isQuestion and sentiment are already-typed labels with a consistent enum across every row, needing no normalization pass before they hit a training set.
๐ฑ Competitive and market intelligence
Run the Actor against a competitor's product-launch or pricing-announcement posts and track buyingSignalScore distribution and mentions/hashtags volume over time โ a spike in pricing-tier comments (buyingSignalMatches category pricing) under a competitor's post is a leading indicator worth watching before it shows up in a win/loss report.
๐ฌ Research and academic use
Social and market researchers studying public discourse patterns, engagement dynamics or B2B communication norms on professional networks can build a dataset from text, stats.total_reactions, commentCreatedAt and isQuestion across a set of posts. Scope is public-comment data only โ no private groups, no messages, no content behind LinkedIn's login wall.
๐ฅ Product and SaaS development
Lead-scoring tools, social-listening dashboards and CRM-enrichment plugins can be built directly on this Actor's output: buyingSignalScore and buyingSignalTier slot into a lead-priority field, contactInTextEmail/contactInTextPhone populate an enrichment record, and sourceEngine plus commentsCoveragePct let a downstream product be honest with its own users about data completeness.
๐ Input Parameters
All fields are optional โ the Actor runs with an empty input and does nothing until postUrls is supplied. Parameter names, types, defaults and constraints below are copied exactly from .actor/actor.json.
| Parameter | Required | Type | Constraints | Description |
|---|---|---|---|---|
postUrls | No | array (string list) | default [] | One or more LinkedIn post URLs, activity URNs or bare activity IDs. Each post is scanned separately. |
commentsPerPost | No | integer | min 1, max 500, default 10 | Top-level comments to pull per post before filtering. Logged-out, the public page serves roughly 9โ10 regardless of this value; a li_at cookie raises the ceiling. |
filterKeywords | No | array (string list) | default [] | Case-insensitive. A comment is kept only if its text contains at least one of these. Empty = keep everything. |
excludeKeywords | No | array (string list) | default [] | Case-insensitive. Drops comments containing any of these โ useful for stripping congratulation noise. |
minReactions | No | integer | min 0, default 0 | Keep only comments with at least this many reactions. |
minCommentLength | No | integer | min 0, default 0 | Minimum comment length in characters โ the cheapest way to drop one-word replies and emoji-only comments. |
excludeAuthorComments | No | boolean | default false | Drops comments written by the post's own author. |
postedFrom | No | string (datepicker) | absolute or relative | Comments posted on or after this date. Accepts 2025-01-27, an ISO timestamp, or a relative value like "7 days". |
postedTo | No | string (datepicker) | absolute or relative | Comments posted on or before this date. Same accepted formats as postedFrom. |
postedLimit | No | string (select) | enum: any, 24h, week, month, 3months, 6months, year; default any | A coarse age bucket applied on top of the exact date range โ it can only tighten the lower bound, never widen it. |
minBuyingSignalScore | No | integer | min 0, max 100, default 0 | Keep only comments scoring at least this much. 25+ means one real intent term fired; 50+ means several. |
buyingSignalKeywords | No | array (string list) | default [] | Your own intent terms, added to the built-in lexicon. Each is worth 20 points and reported by name in the score breakdown. |
aiEnrichment | No | boolean | default false | Adds AI sentiment, an intent label and a short summary per comment. Off by default; requires your own provider API key. |
aiModel | No | string (select) | enum: claude-haiku-4-5, claude-sonnet-5, claude-opus-4-8, gpt-4o-mini, gpt-4o, gpt-4.1-mini, o3-mini, gemini-2.0-flash-lite, gemini-2.0-flash, gemini-2.5-flash, grok-3-mini, deepseek-chat, sonar, mistral-small-latest; default claude-haiku-4-5 | Provider is auto-detected from the model name prefix. |
aiApiKey | No | string (text field, secret) | โ | Your own key for the provider chosen above. Falls back to a matching environment variable. Leave empty to keep AI off. This field is flagged isSecret in the Actor's schema โ the Apify Console masks it in the UI and in logs. |
includeReplies | No | boolean | default false | Includes nested replies. Only reachable through the authenticated engine โ requires a li_at cookie. |
authorDetailLevel | No | string (select) | enum: short, full; default short | full adds commenter headline and profile picture, but only on the authenticated engine. Logged-out, LinkedIn does not expose headline data at all, so it stays null regardless of this setting. |
liAtCookie | No | string (text field, secret) | โ | Optional. Without it the Actor runs fully logged-out. With it, the authenticated engine reaches the full comment list and nested replies. This field is flagged isSecret in the Actor's schema โ treat it like a password, never commit it to a repo or share it in a support ticket screenshot. |
proxyConfiguration | No | object (proxy editor) | prefill {"useApifyProxy": false} | Optional. No proxy is used by default; the Actor escalates direct โ datacenter โ residential on its own when LinkedIn returns its HTTP 999 throttle response. |
aiApiKey and liAtCookie are the only two credential-shaped fields in this schema, and both carry isSecret: true โ meaning the Apify platform stores and displays them as masked values, not plaintext. Neither is required to run the Actor.
Example input (JSON)
{"postUrls": ["https://www.linkedin.com/feed/update/urn:li:activity:7289521182721093633/"],"commentsPerPost": 50,"filterKeywords": ["pricing", "demo", "how much"],"excludeKeywords": ["congrats", "great post"],"minReactions": 2,"minCommentLength": 40,"excludeAuthorComments": true,"postedFrom": "30 days","minBuyingSignalScore": 25,"buyingSignalKeywords": ["switch from", "migrate off", "renewal"],"aiEnrichment": false,"proxyConfiguration": { "useApifyProxy": true }}
Supported URL types and input formats
postUrls accepts three shapes, matched by the same parser used across the array:
- A full activity URL:
https://www.linkedin.com/feed/update/urn:li:activity:7289521182721093633/ - A bare numeric activity ID:
7289521182721093633 - A structured
{"url": "..."}object, for compatibility with the base actor's originalstartUrlsinput shape
The base actor's original field names โ startUrls, resultLimitPerPost, scrapeReplies, profileScraperMode, liAt โ are still accepted as aliases alongside the renamed fields in the table above, in case you are migrating an existing input JSON.
๐ฆ Output Format
Every run pushes one JSON row per surviving comment to the default dataset โ typed, normalized, and stable across runs. Rows export to JSON, CSV, Excel, HTML table, or any other format the Apify platform's dataset export supports; there is no separate export mechanism specific to this Actor.
Output for a comment (the primary row)
This is the complete row shape written by the row-assembly function in main.py, with realistic example values. All 45 keys below are present on every successful row (an unsuccessful post produces a smaller accounting row instead โ see below).
{"comment_id": "7289521199876543210","text": "This looks great โ what's the pricing for a team of 20? Would love to book a demo this week.","posted_at": {"timestamp": 1737936000000,"date": "2025-01-27 00:00:00","relative": "5mo"},"is_edited": null,"is_pinned": null,"comment_url": "https://www.linkedin.com/feed/update/urn:li:activity:7289521182721093633/?commentUrn=urn%3Ali%3Acomment%3A%28urn%3Ali%3Aactivity%3A7289521182721093633%2C7289521199876543210%29","author": {"name": "Dana Rivera","headline": null,"profile_url": "https://www.linkedin.com/in/danarivera/","profile_picture": "https://media.licdn.com/dms/image/D4E03AQ.../profile-displayphoto-shrink_100_100/"},"stats": {"total_reactions": 14,"reactions": { "like": null, "appreciation": null, "empathy": null, "interest": null, "praise": null },"comments": null},"replies": [],"post_input": "7289521182721093633","totalComments": 62,"postUrl": "https://www.linkedin.com/feed/update/urn:li:activity:7289521182721093633/","sourceEngine": "public_page","commentCreatedAt": "2025-01-27T00:00:00Z","commentRelativeAge": "5mo","authorProfileSlug": "danarivera","commentsAvailable": 9,"commentsTotal": 62,"commentsCoveragePct": 14.52,"commentsKeptAfterFilters": 3,"postAuthorName": "Acme SaaS","postAuthorProfileUrl": "https://www.linkedin.com/company/acme-saas/","postPublishedAt": "2025-01-20T14:00:00.000Z","isPostAuthorComment": false,"isQuestion": true,"buyingSignalScore": 60,"buyingSignalTier": "high","buyingSignalMatches": [{ "term": "pricing", "category": "pricing", "weight": 25 },{ "term": "book a call", "category": "demo_or_call", "weight": 25 }],"buyingSignalReasons": ["is_question:+10","pricing:'pricing':+25","demo_or_call:'book a call':+25"],"contactInTextEmail": null,"contactInTextPhone": null,"contactInTextUrl": null,"contactEmailsInText": [],"contactPhonesInText": [],"contactUrlsInText": [],"mentions": [],"hashtags": [],"commentLength": 95,"sentiment": null,"intentLabel": null,"summary": null,"aiEnriched": false,"errorReason": null,"scrapedAt": "2026-07-26T09:00:00Z","runId": "a1B2c3D4e5F6g7H8"}
is_edited, is_pinned and the per-type stats.reactions breakdown are null on the logged-out engine โ the guest page carries no edited/pinned markers and no reaction-type split, so the Actor reports null rather than fabricating false or 0. On the authenticated (voyager) engine these fields are populated with real booleans and per-type counts.
When AI enrichment is on and a usable key is supplied, the three AI columns populate instead of staying null:
{"sentiment": "positive","intentLabel": "buying_intent","summary": "Asks for team pricing and wants to book a demo this week.","aiEnriched": true}
Output for a nested reply (only with li_at + includeReplies)
Replies live inside a comment's replies array and are only populated on the authenticated engine. A reply carries the same base identity, timing and stats fields as a top-level comment, but not the buying-signal, contact-extraction or AI layer โ only top-level comments are filtered and scored.
{"comment_id": "7289521199876543299","text": "Following up โ sent you a DM with our deck.","posted_at": { "timestamp": 1737939600000, "date": "2025-01-27 01:00:00", "relative": "5mo" },"is_edited": false,"is_pinned": false,"comment_url": "https://www.linkedin.com/feed/update/urn:li:ugcPost:7289521182721093633?commentUrn=urn%3Ali%3Acomment%3A...","author": {"name": "Sam Patel","headline": null,"profile_url": "https://www.linkedin.com/in/sampatel","profile_picture": null},"stats": {"total_reactions": 2,"reactions": { "like": 2, "appreciation": 0, "empathy": 0, "interest": 0, "praise": 0 },"comments": 0},"replies": [],"post_input": "7289521182721093633","totalComments": 62}
headline and profile_picture stay null here because authorDetailLevel defaults to short; set it to full to populate them for replies reached through the authenticated engine.
Accounting rows (no comments collected)
When a post URL can't be parsed, or LinkedIn's guest page blocks the request, or no comments survive collection, the Actor still writes one row so the run's log is complete โ with an errorReason (invalid_input, http_999, http_429, login_required, blocked_no_container, network_error, fetch_failed, or no_comments) and an errorMessage string, and every other field null, 0 or empty:
{"comment_id": null,"text": null,"postUrl": "https://www.linkedin.com/feed/update/urn:li:activity:7289521182721093633/","sourceEngine": "public_page","commentsAvailable": 0,"commentsKeptAfterFilters": 0,"buyingSignalScore": null,"errorReason": "blocked_no_container","errorMessage": "No comments were collected for this post (blocked_no_container).","scrapedAt": "2026-07-26T09:03:11Z"}
These accounting rows are pushed without the row_result charged event โ only rows with errorReason: null (i.e. an actual scraped, filtered, scored comment) are billed under the row_result pay-per-event. To exclude accounting rows from a downstream count or export, filter on errorReason == null.
Schema stability and export options
Field names in the table above are stable across runs and are not renamed when LinkedIn changes its front-end markup โ the guest engine's HTML parsing (guest.py) and the authenticated GraphQL parsing (extractor.py) are isolated from the output row shape in main.py, so a LinkedIn markup change is absorbed inside the parser, not surfaced as a schema break. Results export from the Apify platform's dataset view as JSON, CSV, Excel/XLSX, or an HTML table, and are reachable via the Apify API or the apify-client SDKs in any language.
๐ก LinkedIn Comment Scraper Strategy Guide
๐ฏ Strategy 1: Real-time lead-signal enrichment
Trigger the Actor whenever a tracked account or founder publishes a new post โ a scheduled hourly run against a small watch-list of postUrls is the simplest version. For each run, filter the output on buyingSignalScore >= 50 and errorReason == null, then write author.name, author.profile_url, contactInTextEmail, buyingSignalReasons and text back to a CRM or a Slack alert. Because filtering happens before the row is saved, the enrichment step reads a short list, not a raw comment dump.
๐ฏ Strategy 2: Scheduled monitoring and alerting
Use an Apify Schedule to re-run the Actor daily or weekly against the same set of postUrls with postedLimit set to "24h" or "week" so only new comments are pulled each run. Diff the new dataset against the previous run's comment_id values, and alert on any new row where buyingSignalTier is "high" or "very_high" โ a spike in high-tier comments under a competitor's post is worth a same-day look, not a weekly digest.
๐ฏ Strategy 3: Bulk dataset build for outreach or research
Feed a list of post URLs (one per line in postUrls) covering a target account's or an industry hashtag's recent activity, run once with generous filters (minCommentLength low, minBuyingSignalScore at 0) to keep everything scored but nothing dropped, then aggregate the resulting dataset to CSV for a research corpus or an outreach list sorted by buyingSignalScore descending. No concurrency limit is documented for this Actor beyond the per-post commentsPerPost cap and the sequential 1โ2 second delay the Actor applies between posts in a single run.
Strategy comparison at a glance
| Strategy | Best for | Run pattern | Output format |
|---|---|---|---|
| Real-time enrichment | SDR/sales teams working a small watch-list | Triggered or hourly run, tight filters | Filtered rows to CRM/Slack |
| Scheduled monitoring | Competitive intelligence, brand tracking | Daily/weekly Apify Schedule, postedLimit narrow | Diffed dataset, alert on high tier |
| Bulk dataset build | Research corpora, outreach lists | One-off run, loose filters, wide postUrls list | Full dataset exported to CSV |
๐ด Related LinkedIn Scrapers & Tools
| Scraper | What it extracts |
|---|---|
| LinkedIn Post Keyword Monitor | Monitors public LinkedIn posts for brand, product and keyword mentions, flagging what's new since the last scheduled run |
| LinkedIn Profile Credibility Scraper | Scores a public LinkedIn profile 0โ100 for credibility and extracts its recommendations |
| Instagram Comment Sentiment Scraper | Cross-platform equivalent: scores Instagram post/reel comments for sentiment, emotion and topic |
| Instagram Phone Lead Validator | Complementary contact-validation step for phone numbers surfaced during lead-qualification workflows |
How to integrate this LinkedIn comment scraper with your stack
This Actor works with any language or tool that can make an HTTP request โ it runs on the Apify platform and is reachable through the Apify API or an official apify-client SDK.
Python
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run_input = {"postUrls": ["https://www.linkedin.com/feed/update/urn:li:activity:7289521182721093633/",],"filterKeywords": ["pricing", "demo"],"minBuyingSignalScore": 25,}run = client.actor("<YOUR_USERNAME>/linkedin-post-comments-scraper-buying-signal-detection").call(run_input=run_input)rows = []for item in client.dataset(run["defaultDatasetId"]).iterate_items():if item.get("errorReason") is None:rows.append(item)import csvwith open("linkedin_comments.csv", "w", newline="", encoding="utf-8") as f:writer = csv.DictWriter(f, fieldnames=["text", "author", "buyingSignalScore", "buyingSignalTier", "contactInTextEmail",])writer.writeheader()for row in rows:writer.writerow({"text": row.get("text"),"author": (row.get("author") or {}).get("name"),"buyingSignalScore": row.get("buyingSignalScore"),"buyingSignalTier": row.get("buyingSignalTier"),"contactInTextEmail": row.get("contactInTextEmail"),})print(f"Saved {len(rows)} scored comments to linkedin_comments.csv")
Node.js
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('<YOUR_USERNAME>/linkedin-post-comments-scraper-buying-signal-detection').call({postUrls: ['https://www.linkedin.com/feed/update/urn:li:activity:7289521182721093633/'],minBuyingSignalScore: 25,});const { items } = await client.dataset(run.defaultDatasetId).listItems();const highIntent = items.filter((row) => row.errorReason === null && row.buyingSignalScore >= 50);console.log(`${highIntent.length} high-intent comments out of ${items.length} rows`);
Async and scheduled pipelines
Every run is an Apify Actor run: start it asynchronously through apify_client/apify-client and poll run.status or wait on client.run(runId).wait_for_finish(), or attach an Apify webhook to the run for a fire-and-forget notification when it finishes. For recurring monitoring, an Apify Schedule re-runs the Actor on a cron expression without any polling code at all.
๐ฏ Who Needs This LinkedIn Comment Scraper? (Use Cases & Industries)
๐ข Sales development and B2B growth teams
An SDR targeting a named-account list runs the Actor against that account's recent posts with filterKeywords set to buying-language terms, then works the output sorted by buyingSignalScore โ author.profile_url for the Sales Navigator lookup, contactInTextEmail when a commenter left one, buyingSignalReasons as the exact talking point to reference in outreach.
๐ RevOps and marketing analysts
Analysts track buyingSignalTier distribution across a set of monitored posts week over week to quantify how much public buying signal a content or ad campaign is actually generating, independent of vanity metrics like raw comment count.
๐ฑ Competitive intelligence teams
Running the Actor against a competitor's launch or pricing posts and reading buyingSignalMatches for the pricing and purchase_intent categories surfaces market reaction โ objection language, comparison shopping, timeline pressure โ before it reaches a win/loss report.
๐ฌ Researchers
Academic and market researchers studying professional-network discourse can build a public-data-only corpus from text, commentCreatedAt, stats.total_reactions and isQuestion across a defined set of posts, with no login and no access to private groups or messages.
๐ฅ Product and lead-gen tool builders
Teams building a lead-scoring dashboard or a social-selling browser extension can wire this Actor's buyingSignalScore, buyingSignalTier and contact fields directly into a product's data layer rather than building and maintaining their own LinkedIn parser and keyword lexicon.
Is it legal to scrape LinkedIn comments?
Scraping publicly accessible data is generally lawful in the United States: in hiQ Labs, Inc. v. LinkedIn Corp., 938 F.3d 985 (9th Cir. 2019), the Ninth Circuit held that scraping data LinkedIn had made publicly viewable likely does not violate the Computer Fraud and Abuse Act. That case concerned public LinkedIn profile data specifically, and legal standards vary by jurisdiction and by what is scraped, so it should not be read as blanket clearance.
Separately, scraping may still breach LinkedIn's own Terms of Service, which is a contract and civil-risk question, not a criminal one โ this Actor's default logged-out mode reduces but does not eliminate that exposure, and using a personal li_at cookie escalates it further by tying the request to an authenticated account.
Because this Actor returns commenter names, profile URLs and avatars, its output is personal data under GDPR and CCPA-style frameworks, even though the source is public. This Actor returns only publicly accessible data. What you do with that data is your responsibility โ consult legal counsel for commercial applications involving personal data.
โ Frequently asked questions
Does this LinkedIn comment scraper work without a LinkedIn account?
Yes. The default engine is the logged-out public post page and needs no account, cookie or browser. Supplying liAtCookie is an optional escalation that unlocks the full comment list, nested replies, and commenter headline/picture on authorDetailLevel: "full" โ it is never required to get a result.
How does it handle LinkedIn's anti-scraping measures?
The Actor treats an HTTP 200 response as unreliable on its own โ a LinkedIn guest wall answers 200 with a normal-looking page โ so it only accepts a guest page when the actual comment container or the post's structured-data node is present, and rejects any response whose final URL resolved to a login or signup wall. On LinkedIn's HTTP 999 throttle signal (or a 429), it retries with escalating proxy tiers โ none โ datacenter โ residential, up to two residential attempts โ rather than failing the post outright.
Can I run this at scale without getting blocked?
The Actor applies a randomized 1โ2 second delay between posts within a single run and escalates proxy tiers automatically on a block; no uptime or success-rate figure is published for running many posts in a single job, and none should be assumed. Supplying your own residential proxy via proxyConfiguration gives the retry ladder a stronger starting point.
How fresh is the data this Actor returns?
Every run performs a live fetch of the post page (or the authenticated GraphQL endpoint) at run time โ nothing is cached or served from a prior run's snapshot.
Which fields work best for AI training and RAG indexing?
For RAG: text combined with buyingSignalReasons gives a retrieval system pre-labeled intent context instead of raw prose to re-classify. For training data: buyingSignalTier, isQuestion and (with AI enrichment on) sentiment/intentLabel are consistent enum values across every row. All fields return as typed primitives โ strings, integers, booleans, arrays โ requiring no normalization before use.
What happens to personal data returned in the results?
The commenter names, profile URLs and avatars in the output are publicly visible on LinkedIn at scrape time. This Actor does not infer, guess or enrich beyond what LinkedIn's page itself displays; lawful basis for storing and using that data in your own systems sits with you as the operator, not with the Actor.
Does this Actor work with Claude, ChatGPT and other AI agent tools?
It is not documented as reachable through a dedicated MCP server. Any agent framework that can call the Apify API or the apify_client/apify-client SDK can run it and read back typed JSON directly โ no HTML parsing step is needed before passing a row into an LLM's context window.
What happens when a post has no comments left after filtering?
The post still produces one dataset row rather than nothing: errorReason is set to "no_comments" (or a more specific block reason), commentsKeptAfterFilters is 0, and every content field is null. This accounting row is pushed without the row_result charged event, so a fully-filtered-out post costs nothing.
How does this Actor compare to other LinkedIn comment scrapers?
apimaestro's no-cookies comment scraper and benjarapi's comment scraper both document broader raw comment volume and nested-reply extraction (observed on their Apify Store listings, checked 2026-07-26) without documenting any pre-filtering, scoring or contact-extraction layer. This Actor trades some of that raw-volume framing for a filter-then-score pipeline: fewer rows, but every row carries a keyword-auditable buying-intent score and any contact details LinkedIn itself never surfaces as a structured field.
โน๏ธ Disclaimer
This Actor extracts only publicly available data from LinkedIn. It is intended for lawful use cases only. Users are responsible for complying with LinkedIn's Terms of Service and applicable data protection laws in their jurisdiction, including any obligations that attach to the personal data (names, profile URLs, avatars) present in the comments it returns.