LinkedIn Post Scraper: What Actually Comes Back
Posts, reactions and comments are three billing decisions in one call. A live run shows the fields, and the two flags that quietly multiply the bill.

Copy this line to your agent to pull a LinkedIn profile's recent posts with engagement.
set up https://monid.ai/SKILL.md and use apify /harvestapi/linkedin-profile-posts to pull a profile's recent posts
A LinkedIn post scraper looks like one call and is actually three billing decisions. The posts themselves are bounded and cheap. Reactions and comments are unbounded and attach to each post, so two boolean flags in the same request turn a predictable call into one whose cost depends on how popular the content happened to be. Here is what comes back, measured, and where the bill hides, running through Monid, the OpenRouter for agent tools.
What does a LinkedIn post scraper return?
More structure than the store listings suggest, and the useful parts are not the post text.
One live record, field by field
Running apify/harvestapi/linkedin-profile-posts against a public executive profile on 2026-08-31 returned records shaped like this: type, id, linkedinUrl, content, contentAttributes, author, postedAt, postImages, socialContent, header, entityId, shareUrn, shareLinkedinUrl, engagement, reactionIds, commentIds and query.
Four of those are worth calling out.
type distinguishes an original post from a repost or a quote post. That matters more than it sounds, because a feed pull that counts reposts as original output will overstate somebody's activity by a wide margin, and executives repost heavily.
author arrives nested in every post record. You do not need a separate profile lookup to know who wrote it, which is the same pattern we found on YouTube and TikTok: the identity comes attached to the content.
engagement carries the counts. This is the number most people came for and it is the cheapest thing in the response, because counting reactions is not the same as fetching them.
reactionIds and commentIds are identifiers rather than content. They tell you how to go and get the reactions and comments, and going to get them is a separate and much larger job. The next section is about exactly that.
What the store listing does not show you
The Apify store pages that hold page one for this cluster are product cards. They list what the actor does; they do not show a response, and they do not price the difference between asking for posts and asking for everything attached to posts.
Why do reactions and comments change the price so much?
Because posts are bounded and engagement is not, and the same request carries both.
The flags that do it
Reading the schema for that endpoint on 2026-08-31, the input carries scrapeReactions, maxReactions, postNestedReactions, scrapeComments, maxComments and commentsPostedLimit, alongside maxPosts, postedLimit, includeQuotePosts and includeReposts.
Look at what that list is doing. maxPosts caps a bounded thing: a profile has a finite post history and you asked for the first N of it. maxReactions and maxComments cap an unbounded thing, per post, and the number you set is multiplied by however many posts came back.
Ask for fifty posts with reactions capped at five hundred each and you have asked for up to twenty-five thousand records from a call that looked like it was about fifty.
Why the default is the safe one
Both scrape flags default off, which is the correct design and also why people are surprised later: the first run is cheap, somebody turns on comments to answer one question, and the second run costs two orders of magnitude more for reasons nobody wrote down.
The discipline is the same one that applies to TikTok comments and to any nested collection: set the per-parent cap before the first run rather than after the first invoice, and treat turning a nested flag on as a separate decision with its own budget.
The counts are usually enough
Worth saying plainly because it saves most of the money in this category. If the question is "which posts landed", engagement answers it without fetching a single reaction. You need the actual reactors only when the question is "who specifically engaged", which is a prospecting job rather than an analytics one.
Bounded vs nested: what actually differs
| Aspect | Posts only | Posts plus engagement |
|---|---|---|
| What caps the size | maxPosts | maxPosts times maxReactions |
| Size known before running | Yes | No |
| Answers "which posts worked" | Yes, via engagement | Yes |
| Answers "who engaged" | No, only ids | Yes |
| Cost shape | Per result, predictable | Per result, multiplied |
The row that decides it is the fourth. Ids are free; the people behind them are not.
How do you pull a person's or a company's posts?
Three steps, two of them free.
For agents
Grab an API key at app.monid.ai, then paste this to your agent and hand it the key:
set up https://monid.ai/SKILL.md
It learns the whole discover, inspect, run workflow itself. More in the agent quickstart.
For humans
npm install -g @monid-ai/cli
monid keys add -k <your-api-key> -l main
Step 1. Read the flags before you run anything
What it does. Shows which inputs cap a bounded thing and which cap an unbounded one, which is the whole cost model.
The call.
monid discover -q "linkedin posts by a person"
monid inspect -p apify -e /harvestapi/linkedin-profile-posts
What comes back. The full input schema and the billing shape. Four providers cover this surface with different shapes: two Apify actors billing per result, and two TikHub endpoints billing per call.
What it costs. Nothing. Discovery and inspection never bill.
Step 2. Pull the posts, engagement only
What it does. Gets the content and the counts without the nested collections.
The endpoints. apify/harvestapi/linkedin-profile-posts, billed per result.
The call.
monid run -p apify -e /harvestapi/linkedin-profile-posts -w -i '{
"targetUrls": ["https://www.linkedin.com/in/example/"],
"maxPosts": 20,
"includeReposts": false
}'
What comes back. The field set above, one record per post, with author nested and engagement populated. Note the input parameter is targetUrls rather than profiles; passing the wrong key returns zero records with no error, which is the kind of silent failure worth checking for on the first run.
What it costs. A fraction of a cent per post returned. Setting includeReposts false is worth doing deliberately rather than by default: it changes what you are measuring, not just what you pay. Current figures at monid.ai/tools.
Step 3. Decide about engagement as a separate job
What it does. Keeps the unbounded half from riding along with the bounded half.
The call.
monid run -p apify -e /harvestapi/linkedin-profile-posts -w -i '{
"targetUrls": ["https://www.linkedin.com/in/example/"],
"maxPosts": 5,
"scrapeReactions": true,
"maxReactions": 100
}'
What comes back. Reactors on five posts rather than twenty, because when the nested flag is on the post count is the multiplier. Cutting maxPosts when you turn engagement on is the move, and it is counterintuitive enough that people do the opposite.
What it costs. Up to five hundred records where the previous call was twenty. Same endpoint, same syntax, two orders of magnitude.
📖 See also Proxycurl Shut Down: Where LinkedIn Data Goes Now
Give this to your agent![]()
Set up https://monid.ai/SKILL.md, and then use Monid to pull the last 20 posts for these 5 linkedin profiles without reposts, and give me a table of post url, date, and engagement counts sorted by reactions.How do you get the author behind a quoted post?
This is the largest row in the cluster and the intent is specific: somebody has a post, often quoted or screenshotted, and wants to know who wrote it and whether they matter.
It is two lookups, not one
The post record gives you author, which is identity. What it does not give you is the person's company, seniority, or anything you would qualify them on. That is a profile enrichment and it is a separate call.
Doing both is the whole job: post to author to enriched profile. Each step is cheap and the mistake is expecting one endpoint to do all three, which is why the ranked lists for this term disagree.
Search by text when you do not have the URL
If what you have is the text of a post rather than its link, apify/harvestapi/linkedin-post-search searches posts by query and returns them with the author attached, billed per result. That is the route for "who said this" when the screenshot has no link, and it is the one people usually cannot find.
The honest limit
Neither route recovers a deleted post, an author who has since gone private, or the identity behind an account that was never public. The archive is what LinkedIn currently serves, not a historical record, and there is no version of this that works retroactively.
Which endpoint should I use for which job?
| Endpoint | What it does | Input | Output | Best for | Billing |
|---|---|---|---|---|---|
apify/harvestapi/linkedin-profile-posts | Posts from a profile or company page | Target URLs, caps | Post records with author and engagement | Content and activity analysis | Per result |
apify/harvestapi/linkedin-post-search | Posts matching a text query | A query | Posts with authors | Finding who said something | Per result |
tikhub get user posts | One profile's posts | A profile identifier | Post records | Bounded, high volume | Per call |
tikhub get company posts | One company page's posts | A company identifier | Post records | Company content tracking | Per call |
pdl/v5/person/enrich | Fills the author into a full record | An identifier | Title, seniority, history | Qualifying the author | Per call |
Every row was verified with monid inspect on 2026-08-31. The table gives billing shape rather than figures; shape drives design and current numbers live on monid.ai/tools.
The per-call versus per-result split decides how you batch. Per-call endpoints reward asking for one profile at a time and not caring how many posts come back. Per-result endpoints reward setting a cap and knowing what it multiplies against. Running the same batch shape against both is how a LinkedIn pipeline develops a bill nobody can account for.
When should you use LinkedIn's own API?
Three cases, and the first is not a consolation prize.
You are building on behalf of members who authorise you. LinkedIn's Marketing and Community Management APIs exist for applications acting for a page or a member who connected them. If your users link their own accounts, that is the correct and supported route and none of this article applies.
You are managing your own company page. Publishing, analytics on your own content, and comment management on posts you own are all first-party jobs with first-party tools.
You need a contract. Sanctioned access with a partner agreement carries obligations in both directions, and if a broken field is a customer incident that is the dependency you want.
Where the official route cannot help is the case that generates this search volume: reading public activity from accounts that have no relationship with you. LinkedIn does not offer that and the gap is why the third-party market exists at all. The legal shape of that gap, including the hiQ rulings that everybody half-remembers, is in Is Web Scraping Legal?.
And the disclosure: you are reading Monid's blog and we sell per-call access to these endpoints. If your users authorise you, use LinkedIn's API and ignore us.
Conclusion
A LinkedIn post scraper is not one decision. Posts are bounded, cheap and answer most content questions through the engagement counts that arrive with them. Reactions and comments are unbounded, attach per post, and are controlled by flags that default off for good reason. Turning one on without cutting maxPosts is the single most common way this becomes expensive.
The thing worth carrying past this surface is that the author comes nested in the post. That removes a lookup from the design and makes the post, rather than the profile, the natural unit of a LinkedIn content pull. What it does not remove is the enrichment: knowing who wrote something and knowing whether they matter are still two calls.
Free next step: run monid inspect -p apify -e /harvestapi/linkedin-profile-posts and read the input list. It is free, and seeing maxReactions sitting next to maxPosts is the fastest way to understand which one multiplies. Start at monid.ai.
FAQ
Is scraping LinkedIn posts allowed?
Public, logged-out collection of public pages has been treated very differently by US courts from logged-in collection, and the distinction that keeps deciding cases is whether you held an account. hiQ won on the computer-intrusion statute and lost on breach of contract, because it had accounts; Bright Data won twice against platforms while logged out. That is a real pattern and it is not legal advice, and the citations are in Is Web Scraping Legal?.
Can the same endpoint pull company posts and person posts?
On the Apify actor yes, because both are target URLs and a company page is just another URL. On the per-call providers they are separate endpoints, one for user posts and one for company posts, which matters when you are batching a mixed list. Check which shape you have before writing the loop, because a mixed list against a person-only endpoint fails per row rather than up front.
Do reposts count as somebody's posts?
Only if you let them, and the flags are explicit: includeReposts and includeQuotePosts both exist and the type field on each record tells you what you got. This is a measurement decision rather than a technical one. Counting reposts as original output overstates activity substantially for executive accounts, which repost far more than they write, so decide what you are measuring before the first run.
How far back can you pull a profile's posts?
As far as LinkedIn currently serves on that profile, which is not a documented depth and varies. The endpoint gives you postedLimit and postedLimitDate to bound a pull by recency, which is the right control for monitoring, but neither extends reach into an archive that is not being served. If you need history you did not collect, no endpoint here reaches it and the honest answer is to start collecting now.
Last updated August 2026.


