LinkedIn Profile Posts Scraper With Lead Enrichment avatar

LinkedIn Profile Posts Scraper With Lead Enrichment

Under maintenance

Pricing

from $5.99 / 1,000 results

Go to Apify Store
LinkedIn Profile Posts Scraper With Lead Enrichment

LinkedIn Profile Posts Scraper With Lead Enrichment

Under maintenance

Extract posts from LinkedIn profiles with the LinkedIn Profile Post Scraper. Collect post text, timestamps, likes, comments, and engagement metrics in structured format. Ideal for social media analysis, content research, brand monitoring, and tracking professional activity.

Pricing

from $5.99 / 1,000 results

Rating

0.0

(0)

Developer

Scrapier

Scrapier

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 days ago

Last modified

Share

LinkedIn Profile Posts Scraper — Extract Posts and Engaged Leads

LinkedIn Profile Posts Scraper With Lead Enrichment pulls public posts from any LinkedIn profile URL and returns them as structured JSON — post text, engagement counts, and media — plus two lead-ready row types: engaged leads (real people who commented) and reactions, each tagged with a rule-based seniority and decision-maker signal derived from the author's headline. Every response is structured JSON, ready to pass directly to an LLM, index into a vector store, or feed a sales-prospecting pipeline. No AI guesses and no fabricated contact data — only what LinkedIn's public profile page actually shows.

🧭 What is LinkedIn Profile Posts Scraper With Lead Enrichment?

It is an Apify Actor that crawls a LinkedIn personal profile URL (/in/...), follows the posts published on that profile, and extracts each post as a JSON row. On top of the raw post data, it applies a local, keyword-based classifier to the author's authorHeadline to derive a seniorityLevel and isDecisionMaker flag, and promotes every real, named comment author into its own engagedLead output row. No LinkedIn account, cookie, or login is used or required — everything comes from what an anonymous visitor to the profile can already see.

  • 🎯 Seniority & decision-maker classification on every post, derived from authorHeadline keyword rules (CEO, Founder, Director, VP, Head of, Manager, etc.)
  • 🤝 Engaged leads — every real, named commenter on a scraped post becomes its own linked output row
  • 👍 Reactions — likers/reactors are promoted into linked rows too, with their reaction type
  • 🏅 Minimum seniority filter (minSeniorityLevel) to drop posts whose author doesn't meet a seniority bar
  • 🔁 Automatic retries and proxy escalation — starts with a direct connection and escalates to Apify Proxy (datacenter, then residential) when LinkedIn blocks a request
  • 📡 Live dataset output — rows are pushed as they are found, not batched at the end of the run

📊 What data can you get with LinkedIn Profile Posts Scraper With Lead Enrichment?

The Actor writes three row types into one flat dataset, distinguished by a type field: profile posts, promoted engaged leads, and promoted reactions.

Result typeExtracted fields (top-level)Primary use case
Posturn, text, url, postedAtISO, authorFullName, authorHeadline, seniorityLevel, isDecisionMaker, numLikes, numComments, images, comments, reactionsTrack what a person or company page is posting, and score the author for lead qualification
Engaged leadauthorFullName, authorProfileId, authorProfileUrl, authorHeadline, seniorityLevel, isDecisionMaker, text, commentLinkBuild outreach lists from real people who engaged with a target's content
ReactionauthorFullName, authorProfileId, authorProfileUrl, reactionTypeSurface who liked/reacted to a post, without the comment text

🎯 Engaged leads

Every dataset row of type: "engagedLead" represents one real, named person who commented on a scraped post — never a fabricated identity. The Actor only promotes a comment if it can resolve both a real display name and a real profile handle from the page; a comment it cannot attribute to a named author is dropped rather than turned into a placeholder "commenter-hash" lead. Each lead row carries the same seniority/decision-maker classification as post authors, run against the commenter's own visible headline where LinkedIn's anonymous comment view exposes one — otherwise authorHeadline and seniorityLevel are null, since anonymous browsing rarely surfaces a commenter's headline.

{
"type": "engagedLead",
"isChild": true,
"parentId": "urn:li:activity:7051234567890123456",
"authorFullName": "Alex Rivera",
"authorProfileId": "alexrivera",
"authorHeadline": "VP of Sales at Northwind",
"seniorityLevel": "VP",
"isDecisionMaker": true,
"text": "Congrats on the launch, this is exactly what we need."
}

👍 Reactions

Reaction rows (type: "reaction") capture who liked, loved, celebrated, supported, or found a post insightful, linked back to the same post via parentId. They carry no comment text and no seniority classification — just the reactor's identity and reactionType. Useful for a lighter-weight signal of who is paying attention to a target's content, separate from the smaller set of people who actually commented.

🛠️ Why not build a LinkedIn post scraper yourself?

LinkedIn does not offer a public, self-serve API for pulling an arbitrary profile's posts, comments, and reactions — its developer platform is partner-gated and does not cover this use case for unaffiliated apps. Building this in-house means maintaining an HTML parser against a layout that changes without notice, handling LinkedIn's anti-bot responses (401/403/429/999 status codes), and paying for and rotating residential proxy IPs once your request volume gets flagged. This Actor already does all three: it parses JSON-LD and HTML fallbacks for post data, escalates from a direct connection to datacenter and then residential Apify Proxy automatically when blocked, and retries failed requests with backoff — so you send a list of profile URLs and get rows back.

🚀 How to scrape LinkedIn profile posts with LinkedIn Profile Posts Scraper With Lead Enrichment

  1. Open the Actor's page in Apify Console under the Scrapier account, or search for linkedin-profile-posts-scraper-with-lead-enrichment in the Apify Store.
  2. Paste one or more LinkedIn profile URLs into the required urls field (e.g. https://www.linkedin.com/in/username).
  3. Set the real controls you need: maxPosts, minSeniorityLevel, includeEngagedLeads, rateLimitDelay, fetchRetries, and optionally proxyConfiguration.
  4. Click Start to run the Actor.
  5. Open the Output tab, filter by the type column to separate posts, engaged leads, and reactions, or export the dataset as JSON, CSV, or another format the Apify dataset supports.

🔁 How to run multiple profiles in one job

urls is a list field — paste each profile URL on its own line and they all run in the same job. The Actor processes URLs one at a time inside a single run (there is no concurrency setting in the input schema); to scrape a large number of profiles faster, split the list across multiple scheduled runs rather than expecting parallel processing within one run.

⬇️ Input

ParameterRequiredTypeConstraintsDescription
urlsYesarrayeditor: stringListLinkedIn profile URLs to scrape (e.g. https://www.linkedin.com/in/username). Paste each URL on a new line. Only personal profile URLs (/in/...) are processed — company, post, feed, school, and group URLs are skipped.
maxPostsNointegermin 1, max 500, default 25Maximum number of posts to collect per URL. Keep lower for faster runs (e.g. 10–50).
rateLimitDelayNointegermin 0, max 30, default 1Base delay in seconds between requests while crawling a profile's posts. Higher values are slower but gentler.
fetchRetriesNointegermin 0, max 10, default 3Number of retry attempts per HTTP request before moving on.
includeEngagedLeadsNobooleandefault trueWhen enabled, every real person who commented on a scraped post is promoted into its own labeled output row (type: "engagedLead", linked to the post via parentId).
minSeniorityLevelNostringenum: any, manager, director, vp, executive; default anyOnly keep posts whose author's headline classifies at or above this seniority level. any disables the filter.
proxyConfigurationNoobjecteditor: proxyApify Proxy settings. Defaults to no proxy for the initial request; the Actor automatically escalates to a more resilient connection strategy if LinkedIn restricts requests.

Example input

{
"urls": [
"https://www.linkedin.com/in/ajjames",
"https://www.linkedin.com/in/satyanadella"
],
"maxPosts": 25,
"rateLimitDelay": 1,
"fetchRetries": 3,
"includeEngagedLeads": true,
"minSeniorityLevel": "director",
"proxyConfiguration": { "useApifyProxy": false }
}

Common pitfalls

  • Only /in/ profile URLs are accepted. Company pages, individual post URLs, feed URLs, school pages, and group URLs are silently skipped (a warning is logged, but no row is produced) — pass the profile page, not a specific post.
  • rateLimitDelay accepts 0, but the Actor enforces an internal floor of 0.2 seconds between requests regardless of a lower value you set — it will never crawl with literally zero delay.
  • Each post carries at most 10 comments and 20 reactions in the comments/reactions arrays, even if the real post has more (see commentsTruncated/reactionsTruncated below) — this is a fixed slice size in the Actor, not a proxy or network limit.
  • Leaving proxyConfiguration at its default (no proxy) does not guarantee the run makes zero proxied requests: for any profile URL, the Actor proactively switches to a residential Apify Proxy session before scraping, regardless of the toggle, because profile pages are the most block-prone target.

⬆️ Output

Results are typed, normalized JSON rows written to the Actor's default dataset — the same schema on every run, exportable as JSON, CSV, Excel, HTML table, or the other formats Apify datasets support. Every row carries type, isChild, and parentId so the three row kinds can be told apart and joined back together in one flat table.

📋 Scraped results

[
{
"type": "image",
"isChild": false,
"parentId": null,
"urn": "urn:li:activity:7051234567890123456",
"text": "Excited to share that we closed our Series B this week.",
"url": "https://www.linkedin.com/posts/janedoe_activity-7051234567890123456",
"postedAtTimestamp": 1717000330000,
"postedAtISO": "2024-05-29T14:32:10.000000Z",
"timeSincePosted": "3mo",
"isRepost": null,
"authorType": "Person",
"authorProfileUrl": "https://www.linkedin.com/in/janedoe",
"authorProfileId": "janedoe",
"authorHeadline": "Founder & CEO at Acme Analytics",
"authorFullName": "Jane Doe",
"authorName": "Jane Doe",
"authorTitle": "Founder & CEO at Acme Analytics",
"image": "https://media.licdn.com/dms/image/example1.jpg",
"images": ["https://media.licdn.com/dms/image/example1.jpg"],
"author": {
"firstName": "Jane",
"lastName": "Doe",
"occupation": "Founder & CEO at Acme Analytics",
"id": "janedoe",
"publicId": "janedoe",
"trackingId": "aBcDeFgHiJkLmNoPqRs",
"profileId": "janedoe",
"picture": "",
"backgroundImage": ""
},
"attributes": [],
"comments": [
{
"time": 1717003000000,
"link": "https://www.linkedin.com/feed/update/comment/9123456789",
"text": "Congrats on the launch, this is exactly what we need.",
"entities": [],
"pinned": false,
"originalLanguage": "English",
"author": {
"firstName": "Alex",
"lastName": "Rivera",
"occupation": "",
"id": "commenter-3f9a12b0c8de",
"publicId": "alexrivera",
"trackingId": "TrK9284x0alBqweRty0",
"profileId": "commenter-3f9a12b0c8de",
"picture": "",
"backgroundImage": "",
"distance": "OUT_OF_NETWORK"
}
}
],
"reactions": [
{
"type": "LIKE",
"profile": {
"firstName": "Priya",
"lastName": "Nair",
"occupation": "",
"id": "reactor-7d21ac903e11",
"publicId": "priyanair",
"trackingId": "TrK028x9zqEwLopQr21",
"profileId": "ACoAA7d21ac903e11",
"picture": "",
"backgroundImage": ""
}
}
],
"numShares": null,
"numLikes": 214,
"numComments": 18,
"commentsTruncated": true,
"commentsComplete": false,
"reactionsTruncated": true,
"canReact": null,
"canPostComments": null,
"canShare": null,
"commentingDisabled": null,
"allowedCommentersScope": null,
"rootShare": null,
"shareAudience": null,
"seniorityLevel": "Executive",
"isDecisionMaker": true,
"scrapedAt": "2026-08-04T10:15:22.123456Z"
},
{
"type": "text",
"isChild": false,
"parentId": null,
"urn": "urn:li:activity:7051234567890123999",
"text": "Hiring three account executives this quarter — DM me.",
"url": "https://www.linkedin.com/posts/janedoe_activity-7051234567890123999",
"postedAtTimestamp": 1716400000000,
"postedAtISO": "2024-05-22T09:10:00.000000Z",
"timeSincePosted": "3mo",
"isRepost": null,
"authorType": "Person",
"authorProfileUrl": "https://www.linkedin.com/in/janedoe",
"authorProfileId": "janedoe",
"authorHeadline": "Founder & CEO at Acme Analytics",
"authorFullName": "Jane Doe",
"authorName": "Jane Doe",
"authorTitle": "Founder & CEO at Acme Analytics",
"image": "",
"images": [],
"author": {
"firstName": "Jane",
"lastName": "Doe",
"occupation": "Founder & CEO at Acme Analytics",
"id": "janedoe",
"publicId": "janedoe",
"trackingId": "bCdEfGhIjKlMnOpQrSt",
"profileId": "janedoe",
"picture": "",
"backgroundImage": ""
},
"attributes": [],
"comments": [],
"reactions": [],
"numShares": null,
"numLikes": 42,
"numComments": 0,
"commentsTruncated": false,
"commentsComplete": true,
"reactionsTruncated": false,
"canReact": null,
"canPostComments": null,
"canShare": null,
"commentingDisabled": null,
"allowedCommentersScope": null,
"rootShare": null,
"shareAudience": null,
"seniorityLevel": "Executive",
"isDecisionMaker": true,
"scrapedAt": "2026-08-04T10:15:24.654321Z"
},
{
"type": "text",
"isChild": false,
"parentId": null,
"urn": "urn:li:activity:7051234567890124222",
"text": "Great panel today on B2B pipeline health.",
"url": "https://www.linkedin.com/posts/janedoe_activity-7051234567890124222",
"postedAtTimestamp": 1715800000000,
"postedAtISO": "2024-05-15T11:20:00.000000Z",
"timeSincePosted": "3mo",
"isRepost": null,
"authorType": "Person",
"authorProfileUrl": "https://www.linkedin.com/in/janedoe",
"authorProfileId": "janedoe",
"authorHeadline": "Founder & CEO at Acme Analytics",
"authorFullName": "Jane Doe",
"authorName": "Jane Doe",
"authorTitle": "Founder & CEO at Acme Analytics",
"image": "",
"images": [],
"author": {
"firstName": "Jane",
"lastName": "Doe",
"occupation": "Founder & CEO at Acme Analytics",
"id": "janedoe",
"publicId": "janedoe",
"trackingId": "cDeFgHiJkLmNoPqRsTu",
"profileId": "janedoe",
"picture": "",
"backgroundImage": ""
},
"attributes": [],
"comments": [],
"reactions": [],
"numShares": null,
"numLikes": 9,
"numComments": 0,
"commentsTruncated": false,
"commentsComplete": true,
"reactionsTruncated": false,
"canReact": null,
"canPostComments": null,
"canShare": null,
"commentingDisabled": null,
"allowedCommentersScope": null,
"rootShare": null,
"shareAudience": null,
"seniorityLevel": "Executive",
"isDecisionMaker": true,
"scrapedAt": "2026-08-04T10:15:26.789012Z"
},
{
"type": "engagedLead",
"isChild": true,
"parentId": "urn:li:activity:7051234567890123456",
"urn": "urn:li:activity:7051234567890123456",
"url": "https://www.linkedin.com/posts/janedoe_activity-7051234567890123456",
"authorFullName": "Alex Rivera",
"authorProfileId": "alexrivera",
"authorProfileUrl": "https://www.linkedin.com/in/alexrivera",
"authorHeadline": null,
"seniorityLevel": null,
"isDecisionMaker": null,
"text": "Congrats on the launch, this is exactly what we need.",
"commentLink": "https://www.linkedin.com/feed/update/comment/9123456789",
"postedAtISO": "2024-05-29T14:32:10.000000Z",
"scrapedAt": "2026-08-04T10:15:22.987000Z"
},
{
"type": "reaction",
"isChild": true,
"parentId": "urn:li:activity:7051234567890123456",
"urn": "urn:li:activity:7051234567890123456",
"url": "https://www.linkedin.com/posts/janedoe_activity-7051234567890123456",
"authorFullName": "Priya Nair",
"authorProfileId": "priyanair",
"authorProfileUrl": "https://www.linkedin.com/in/priyanair",
"reactionType": "LIKE",
"postedAtISO": "2024-05-29T14:32:10.000000Z",
"scrapedAt": "2026-08-04T10:15:23.111000Z"
}
]

Fields that require an authenticated LinkedIn session to observe — canReact, canPostComments, canShare, commentingDisabled, allowedCommentersScope, rootShare, shareAudience, numShares, and isRepost — are always null in every run, because this Actor never logs in. They are left null rather than guessed. Charged rows are pushed via the row_result event; a failed fetch (blocked profile, network error) produces a log warning and no dataset row at all, so it is never charged.

💼 How can I use the data extracted with LinkedIn Profile Posts Scraper With Lead Enrichment?

  • 🎯 Sales / BDR teams: filter posts with minSeniorityLevel: "director" or higher, then work the linked engagedLead rows on those posts as a warm-comment outreach list instead of a cold one.
  • 🏢 Account-based marketing teams: track a set of target-account executives' urls, and use seniorityLevel / isDecisionMaker to confirm which of their posts are actually reaching decision-makers before running ad or outreach sequences against that content.
  • 🤖 AI engineers and LLM developers: feed the JSON rows directly into a grounded agent — the agent requests a profile's recent posts, receives typed fields like text, authorHeadline, and numLikes, and reasons over them as context instead of hallucinating engagement data.
  • 📊 Market and competitive researchers: compare posting cadence, numLikes/numComments, and reaction mix (reactionType) across a set of profiles to see whose content is actually landing.

📈 How do you monitor engaged leads and decision-maker activity over time?

Monitoring here means re-running the Actor against the same set of profile URLs on a schedule and diffing what changed between runs, rather than treating a single run as a one-off snapshot. Each row carries a scrapedAt timestamp and posts are keyed by a stable urn, so you can match the same post across two runs and see whether numLikes, numComments, or the set of engagedLead/reaction child rows attached to it grew. The fields worth diffing are: numLikes, numComments on the parent post, and the list of authorProfileId values across its engagedLead and reaction child rows (new profile IDs appearing since the last run are new engagement). A typical workflow: schedule a daily run across your target account list → for each urn seen before, compare its current numComments and child-row count to the prior run → alert when a new decision-maker-level engagedLead (isDecisionMaker: true) shows up on a post you care about. Set this up with an Apify schedule on the Actor, and attach a dataset webhook so each run's results are delivered as soon as the run finishes.

🔌 Integrate LinkedIn Profile Posts Scraper With Lead Enrichment and automate your workflow

LinkedIn Profile Posts Scraper With Lead Enrichment works with any language or tool that can send an HTTP request to the Apify API.

🐍 REST API with Python

import requests
run_input = {
"urls": ["https://www.linkedin.com/in/satyanadella"],
"maxPosts": 25,
"minSeniorityLevel": "director",
}
resp = requests.post(
"https://api.apify.com/v2/acts/YOUR_USERNAME~linkedin-profile-posts-scraper-with-lead-enrichment/run-sync-get-dataset-items",
params={"token": "YOUR_APIFY_TOKEN"},
json=run_input,
)
rows = resp.json()
for row in rows:
if row.get("type") in ("text", "image"):
print(row["authorFullName"], row["seniorityLevel"], row["numComments"])

🕒 Scheduled monitoring and delivery

Set up a recurring Apify schedule against a saved input to re-run the Actor automatically (e.g. daily). Attach a webhook to the run-succeeded event to push each run's dataset items to your own endpoint, or poll the dataset via the Apify API after each scheduled run instead of a live push.

Scraping publicly accessible LinkedIn pages is generally lawful in the United States — in hiQ Labs, Inc. v. LinkedIn Corp., 9th Cir., 2019, the court held that scraping data a website makes available to anyone without a login does not violate the Computer Fraud and Abuse Act. This Actor returns only what an anonymous visitor to a public profile page can already see; it does not log in, does not bypass a paywall, and does not access private content. That said, the posts, comments, and reactor names this Actor returns are personal data about identifiable individuals, so GDPR (if you or the data subjects are in the EU/UK) and CCPA (for California residents) can still apply to how you store, use, and retain it — publicly visible does not mean unregulated. LinkedIn's own Terms of Service also separately restrict automated access for logged-in users, which is a contract question independent of scraping legality. Scraping for one-off research and scraping to build a persistent, resold contact database carry different risk profiles. Consult your legal team for commercial use cases involving bulk personal data storage.

❓ Frequently asked questions

Does LinkedIn Profile Posts Scraper With Lead Enrichment need a LinkedIn login or cookies?

No. It scrapes public profile pages anonymously — no li_at cookie, password, or authenticated session is used or required. This is also why permission-related fields like canReact and commentingDisabled are always null: they are only observable to a logged-in viewer.

Can I filter posts by the author's seniority or role?

Yes, with minSeniorityLevel. Set it to manager, director, vp, or executive and only posts whose author's headline classifies at or above that level are kept; any (the default) disables the filter. The classification is a local keyword match against authorHeadline — it is a signal, not a verified title.

How does the Actor handle LinkedIn's anti-bot measures?

It starts with a direct connection, then automatically escalates: if a request comes back blocked (HTTP 401, 403, 429, 999, or a captcha/forbidden response), it switches to Apify Proxy on a datacenter IP, and if that is also blocked, to a residential IP. Requests to /in/ profile pages proactively start on residential proxy instead of waiting to get blocked first. 429 responses trigger an exponential backoff sleep before retrying.

Does it extract engaged leads?

Yes — set includeEngagedLeads to true (the default). Every real, named person who commented on a scraped post arrives as its own engagedLead row, linked to the post via parentId, with authorFullName, authorProfileId, and the comment text. If LinkedIn's anonymous view doesn't expose that commenter's headline, authorHeadline and seniorityLevel on that row are null rather than guessed.

How many posts, comments, and reactions does it return per profile?

Up to maxPosts posts per URL (default 25, maximum 500, set via input). Within each post, at most the first 10 available comments and the first 20 available reactions are attached to that post's comments/reactions arrays — commentsTruncated and reactionsTruncated are true when the real post has more than that.

How do I monitor decision-maker engagement over time?

Schedule repeated runs against the same profile URLs and diff numLikes/numComments per urn, plus the authorProfileId values on that post's engagedLead/reaction child rows, against the previous run's results. See "How do you monitor engaged leads and decision-maker activity over time?" above for the full workflow.

Does LinkedIn Profile Posts Scraper With Lead Enrichment work with Claude, ChatGPT, and AI agent frameworks?

It has no dedicated MCP server, but it is callable as a plain HTTP endpoint through the Apify API from any agent framework — an agent can trigger a run, poll or receive the dataset, and use the returned JSON (posts, engaged leads, reactions) as grounded context before generating an answer.

Can I use it without managing proxies or LinkedIn credentials?

Yes. You never supply a LinkedIn login, cookie, or password — the Actor scrapes anonymously. You also don't need to bring your own proxies: it uses Apify Proxy automatically (starting direct and escalating to datacenter, then residential) when LinkedIn restricts requests. You only need an Apify account to run it.

💬 Your feedback

Found a bug, a missing field, or a profile layout the Actor mis-parses? Let us know through the Issues tab on this Actor's page in Apify Console, or contact Scrapier through the Store listing. Reports like this are how the extraction rules stay aligned with LinkedIn's current page structure.