LinkedIn Profile Posts Lookup: posts scraper from $3/1k avatar

LinkedIn Profile Posts Lookup: posts scraper from $3/1k

Pricing

from $2.28 / 1,000 post returneds

Go to Apify Store
LinkedIn Profile Posts Lookup: posts scraper from $3/1k

LinkedIn Profile Posts Lookup: posts scraper from $3/1k

LinkedIn posts scraper with no cookies and no account. Give it public LinkedIn profile links and get one flat row per post: link, exact timestamp, text, reaction and comment counts, media type and repost flag. Nothing found, nothing charged.

Pricing

from $2.28 / 1,000 post returneds

Rating

0.0

(0)

Developer

Adrian Voss

Adrian Voss

Maintained by Community

Actor stats

1

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Share

LinkedIn Profile Posts Lookup: LinkedIn Posts Scraper, No Login

Give it public LinkedIn profile links and get one flat row per post: the permalink, an exact timestamp, the post text, reaction and comment counts, what media it carried, whether it links out, and whether it is a repost of someone else. No account, no cookies, no session token. You pay per post that came back, and a profile that returns nothing costs nothing.

Who it's for

The people who need this are usually watching a short list of named humans rather than crawling LinkedIn at large.

  • Founders and demand-gen teams running a warm-outbound motion. You have thirty prospects in a table and you want a first line that references what each of them actually said last week, not a merge field. One run gives you their recent posts with dates you can sort by.
  • Competitive and partner intelligence. Track what the four executives at a competitor are publishing, how it is landing, and what they are amplifying from other people. The repost flag and the original author column make "what are they signal-boosting" a filter rather than a reading exercise.
  • Creator and influencer scouting. Reaction and comment counts per post, with the exact post time, so you can rank a shortlist on engagement that is real and recent instead of on follower count.
  • Anyone feeding an agent or an LLM. Field names are stable, one post is one row, and the timestamp is ISO 8601, so a model gets a table it can reason over instead of "3d ago".

If you need a member's whole posting history back to 2015, this is the wrong tool and the FAQ says so plainly.

Why this one

  • Exact post times, not "2w". LinkedIn prints a relative age next to every post and that is all most scrapers pass on. A post's activity id is a Snowflake-style integer whose top bits are the millisecond it was created, so this actor decodes the real timestamp and returns it as ISO 8601 in postedAt. It was checked against all nine posts in the capture this actor was built from and agreed with LinkedIn's own label every time. postedAtText keeps the page's wording next to it. "Everything since Tuesday" becomes a filter you can write.
  • No login, no cookies, no session token, and the actor has no field to put one in. It reads the same public page a signed-out browser gets. When LinkedIn decides a request needs an account it answers with a sign-in wall, and this actor reports that as BLOCKED and charges you nothing rather than trying to get around it.
  • A repost is one row and it says so. LinkedIn renders a repost as a card wrapping the original post. Read carelessly that is two rows for one post, and you get billed twice for a duplicate. Here it is one row with isRepost: true and originalAuthor filled in.
  • You are billed per post, and you can cap it. maxPosts sets the most any single profile can return and therefore the most it can cost. A profile that returns nothing is a free row.
  • Reactions and comments are the page's own numbers. Exact integers off the markup, not rounded display strings. A post published minutes ago that genuinely has no reactions yet comes back as null, not a fake zero.

What you get

One row per post, with the profile-level fields repeated on each row so the table joins cleanly.

FieldWhat it is
profileUrl, publicId, authorNameWho the posts belong to, echoed on every row
postCountHow many posts this run returned for that profile, which is also what it billed
postsAvailableHow many the page actually carried, before maxPosts capped it
postUrl, postIdThe post permalink and its numeric activity id
postedAtExact ISO 8601 timestamp, decoded from the activity id
postedAtTextLinkedIn's own wording: Now, 5h, 3d, 2w
textThe poster's commentary, line breaks kept, cut at 1000 characters
textTruncatedTrue when the cut happened, so you know the text is partial
reactionCount, commentCountExact counts, or null when the page published none
mediaTypevideo, image, document, article or none
hasLink, linkUrlWhether the post sends people somewhere, and where, unwrapped out of LinkedIn's redirect
isRepost, originalAuthorWhether this is someone else's post being amplified, and whose
query, found, status, message, scrapedAtThe standard result columns on every actor here

Two things the public page does not publish, and this actor therefore does not invent:

  • There is no repost or share counter anywhere in the markup. Reaction and comment counts are the only numbers LinkedIn emits. Rather than ship a column that is empty on every row, there is no repost-count column at all.
  • There is no full archive. The page carries a recent window, nine posts in the profile this was built against, and there is no next page a signed-out visitor can request.

Pricing

Misses are free. A profile that is blocked, gone, or has no public activity produces a row with found: false and is never charged.

Use it from Clay, n8n, Make, or an AI agent

This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.

curl "https://api.apify.com/v2/acts/accountable_eel~linkedin-profile-posts-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
-X POST \
-H "Content-Type: application/json" \
-d '{"profileUrls":["https://www.linkedin.com/in/satyanadella","reidhoffman"]}'

n8n. Add an HTTP Request node: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~linkedin-profile-posts-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body Content Type JSON, JSON Body {"profileUrls":["https://www.linkedin.com/in/satyanadella","reidhoffman"]} (swap in an expression from an earlier node for a real value).

Clay. Add an "HTTP API" column: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~linkedin-profile-posts-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body {"profileUrls":["{{profile}}"]}, mapping the row's profile into the profileUrls array.

MCP. In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "LinkedIn Posts Scraper, No Login | Apify" — the agent will find and run this actor.

How to use

  1. In the Apify Console. Open the actor page and click Start — the profileUrls field is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found.
  2. Via the API. Call it directly with a POST request — no Console needed once you have an API token:
    curl "https://api.apify.com/v2/acts/accountable_eel~linkedin-profile-posts-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
    -X POST \
    -H "Content-Type: application/json" \
    -d '{"profileUrls":["https://www.linkedin.com/in/satyanadella","reidhoffman"]}'
  3. On a schedule. Save this actor as an Apify Task with the input you want, then add a Schedule (hourly, daily, weekly) so it runs on its own — no server of your own required.

Input

{
"profileUrls": [
"https://www.linkedin.com/in/satyanadella",
"reidhoffman"
]
}

One profile per line. Paste the full profile link, the /recent-activity/ link you copied while looking at someone's posts, or just the part after /in/. Accepted formats: https://www.linkedin.com/in/williamhgates, https://www.linkedin.com/in/satyanadella/recent-activity/all/, satyanadella.

Useful options, all optional:

OptionWhat it does
maxPostsThe most posts one profile may return, newest first. This is also the most it can cost you for that profile.
testRunProcess only the first five profiles, so you can check the shape before spending on the whole list.
onlyFoundDrop the rows that came back with nothing. Misses are free either way.
includeKeywords / excludeKeywordsKeep or drop posts by the words in them. Filtered-out posts are not billed.
columnsChoose which fields land in the table.

Output

queryfoundstatusprofileUrlpublicIdauthorNamepostCountpostsAvailablepostspostUrlpostIdpostedAtpostedAtTexttexttextTruncatedreactionCountcommentCountmediaTypehasLinklinkUrlisRepostoriginalAuthorscrapedAt
https://www.linkedin.com/in/satyanadellatrueOK<all posts found (full list)><posted at (exact)><posted (as linkedin shows it)><text was cut at 1000 characters>1970-01-01T00:00:00.000Z

Tips

  • Sort on postedAt, filter on postedAtText never. The relative label is what the page said at fetch time and it ages the moment you store it. The ISO timestamp does not.
  • excludeKeywords is the cheap way to drop noise. A post filtered out by your keywords is not billed, so a run that only wants posts mentioning your category costs less than the same run unfiltered.
  • Set maxPosts to 3 for a wide sweep. If you are checking two hundred people for "posted anything recently", three posts each answers it at a fifth of the cost of twenty.
  • Leave the residential proxy on. LinkedIn's sign-in wall is IP-reputation driven. The very first probe of this build took a wall on a clean home address, so a datacenter address is not a saving.
  • Keep concurrency low. Two at a time is the default for a reason. Pushing it raises the share of rows that come back BLOCKED, and while those are free, they are also not data.

vs. alternatives

What it costsWhat you getTrade-off
This actor (linkedin-profile-posts-lookup)$0.003 per post returned, $0.00005 actor start, nothing for a missOne row per post with an exact ISO timestamp, text, reaction and comment counts, media type, outbound link and a repost flagIt reads the recent window the public page serves, roughly the last handful of posts. There is no way to page back through a member's history without an account, and this actor will not try.
harvestapi/linkedin-profile-posts$2 per 1,000 postsThe category leader by a distance, 8,248 users in the last 30 days at a 4.41 rating, with deeper post historyCheaper per post and it goes back further. Pick this one when you need the exact publish time, a repost separated from an original, or a per-profile cost cap.
Clay$0.08 to $0.40 per enriched row in credits, on top of a seatA whole enrichment workspace, waterfalls across dozens of providers, plus the table and the sequencing around itIf you want one place that does everything and you are not counting rows, that is Clay. This is one column, priced per column, callable from Clay via its HTTP step.
Doing it yourselfYour time, plus a sign-in wall that fires on reputation rather than on rate, and markup that nests a repost inside its own containerThe same postsThis absorbs the wall handling, the session rotation, the repost de-duplication and the timestamp decoding, and it stops charging the moment a page comes back empty.

Prices for third-party tools are their published list prices as of September 2026 and are not tracked here. Check the vendor before relying on the comparison.

FAQ

Do I need a LinkedIn account, a cookie, or a li_at token? No, and there is nowhere to put one. The actor requests the public profile page a signed-out browser gets. If LinkedIn decides that request needs an account, the row comes back BLOCKED and free.

How far back does it go? As far as the public page carries, which was nine posts for the profile this was built against and varies by member. There is no page-two for a signed-out visitor, so maxPosts can lower what you get but never raise it above what the page served. postsAvailable tells you what was there.

Why is reactionCount sometimes empty? Because the page published no number for that post. That is normal on a post published minutes ago. It is reported as null rather than 0, because "nobody has reacted yet" and "LinkedIn did not say" are different facts.

Why is there no repost count? Because LinkedIn's public page does not emit one. The only social numbers in the markup are reactions and comments. A column that is empty on every row is worse than no column.

A repost shows the original author's name. Is that a bug? No. When someone reposts without commentary, LinkedIn's own permalink points at the original post, so that is what postUrl carries. isRepost is true and originalAuthor names the person who wrote it. Filter on isRepost if you only want a person's own writing.

Can it read comments, or who reacted? No. The public page renders a comments tab and a reactions tab, and both hold other people's posts and other people's names. This actor reads only the member's own Posts tab.

What happens to a profile with no public activity? One free row, found: false, with a message saying the page loaded but published no posts a signed-out visitor can read. Nothing is charged.

Does it work for company pages? No. Feed it a /company/ link and it returns a free BAD_FORMAT row without spending a request. Company pages have their own actor, linkedin-company-posts-lookup.

Is the exact timestamp really exact? It is decoded from the post's own activity id, and it was checked against every relative label on the page it was built from. If LinkedIn ever changes how those ids are minted, postedAt comes back null rather than wrong, and postedAtText still carries the page's own wording.

Personal data, and your responsibility

This actor reads public LinkedIn profile pages only. It never signs in, never sends a cookie or a session token, and never requests anything behind the sign-in wall.

What it returns is still personal data about identifiable people. If the GDPR, the UK GDPR, the CCPA or a comparable law applies to you, you need your own lawful basis for collecting and using it, and your own answer on retention, notice and the rights of the people in your table. LinkedIn's User Agreement also restricts automated collection from its services, and that agreement is between you and LinkedIn.

None of this is legal advice, and nothing here says that any particular use is lawful. That call is yours.