LinkedIn Company Posts Lookup: posts scraper from $3/1k
Pricing
from $2.28 / 1,000 post returneds
LinkedIn Company Posts Lookup: posts scraper from $3/1k
LinkedIn company posts scraper with no cookies and no account. Give it public LinkedIn company page links and get one flat row per post: link, exact timestamp, text, reaction and comment counts, media type and who posted it. Nothing found, nothing charged.
Pricing
from $2.28 / 1,000 post returneds
Rating
0.0
(0)
Developer
Adrian Voss
Maintained by CommunityActor stats
1
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
LinkedIn Company Posts Lookup: Company Page Posts Scraper
Give it public LinkedIn company page 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 who actually wrote it when the page is amplifying somebody else. No account, no cookies, no session token. You pay per post that came back, and a page that returns nothing costs nothing.
Who it's for
- Competitive marketers. You want to know what four rivals shipped, announced and boasted about this quarter, in a table you can read in ten minutes rather than four browser tabs and a scroll. Exact dates mean you can line their announcements up against your own release calendar.
- Account teams working named-account outbound. A company's last three posts are the cheapest
source of a first line that is not a merge field.
maxPosts: 3across two hundred accounts is a small bill and a very different email. - Partner and ecosystem teams. The repost rows are the interesting ones: they show which
partners, customers and employees a company chooses to amplify, and the
authorNamecolumn names them. - Content and social benchmarking. Reactions and comments per post, with the media type alongside, tells you what actually works on a page you are trying to learn from.
- 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 "2w ago".
Why this one
- Exact post times, not "2w". LinkedIn prints a relative age on every update 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 agreed with LinkedIn's own label on every card in the page this actor was built from.postedAtTextkeeps the page's wording next to it. "Everything this company posted since the funding round" becomes a filter you can write. - It tells you when a post is not the company's. LinkedIn's Updates section mixes the
company's own posts with posts it reposted from partners, customers and employees. Read
carelessly, those become "things this company said", which is wrong. Here
isRepostflags them andauthorNameandauthorUrlname whoever wrote them. - A quote-post is one row, not two. When a company writes commentary around somebody else's post, LinkedIn nests the quoted post inside the card. A naive reader emits both and bills you twice for one post. This one emits the outer post and marks it as the company's own.
- 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, the row comes back
BLOCKEDand free. - You are billed per post, and you can cap it.
maxPostssets the most any one page can return and therefore the most it can cost. A page that returns nothing is a free row.
What you get
One row per post, with the company-level fields repeated on each row so the table joins cleanly.
| Field | What it is |
|---|---|
companyUrl, companySlug, companyName | The page the posts came from, echoed on every row |
postCount | How many posts this run returned for that page, which is also what it billed |
postsAvailable | How many the page actually carried, before maxPosts capped it |
postUrl, postId | The post permalink and its numeric activity id |
postedAt | Exact ISO 8601 timestamp, decoded from the activity id |
postedAtText | LinkedIn's own wording: 6h, 1d, 2w |
edited | True when the post carries LinkedIn's "Edited" marker |
text | The commentary, line breaks kept, cut at 1000 characters |
textTruncated | True when the cut happened, so you know the text is partial |
reactionCount, commentCount | Exact counts off the page markup, or null when the page published none (a post with no comments yet) |
mediaType | video, image, document, article or none, read from LinkedIn's own label |
hasLink, linkUrl | Whether the post sends people somewhere, and where, unwrapped out of LinkedIn's redirect |
isRepost, authorName, authorUrl | Whether the page is amplifying someone else, and who |
query, found, status, message, scrapedAt | The 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 Updates section carries a recent window, ten posts on the page this was built against, and there is no next page a signed-out visitor can request.
Pricing
Misses are free. A page that is blocked, gone, or has no public updates 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-company-posts-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \-X POST \-H "Content-Type: application/json" \-d '{"companies":["https://www.linkedin.com/company/stripe","shopify"]}'
n8n. Add an HTTP Request node: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~linkedin-company-posts-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body Content Type JSON, JSON Body {"companies":["https://www.linkedin.com/company/stripe","shopify"]} (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-company-posts-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body {"companies":["{{company page}}"]}, mapping the row's company page into the companies array.
MCP. In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "LinkedIn Company Posts Scraper | Apify" — the agent will find and run this actor.
How to use
- In the Apify Console. Open the actor page and click Start — the
companiesfield is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found. - 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-company-posts-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \-X POST \-H "Content-Type: application/json" \-d '{"companies":["https://www.linkedin.com/company/stripe","shopify"]}'
- 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
{"companies": ["https://www.linkedin.com/company/stripe","shopify"]}
One company per line. Paste the full company page link, the /posts/ link you copied while looking at their updates, or just the part after /company/. School and showcase pages work too. Accepted formats: https://www.linkedin.com/company/stripe, https://www.linkedin.com/company/shopify/posts/, stripe.
Useful options, all optional:
| Option | What it does |
|---|---|
maxPosts | The most posts one page may return, newest first. This is also the most it can cost you for that page. |
testRun | Process only the first five companies, so you can check the shape before spending on the whole list. |
onlyFound | Drop the rows that came back with nothing. Misses are free either way. |
includeKeywords / excludeKeywords | Keep or drop posts by the words in them. Filtered-out posts are not billed. |
columns | Choose which fields land in the table. |
School pages (/school/...) and showcase pages (/showcase/...) are accepted too, because a
pasted CRM column has all three mixed in. A member profile link is rejected as a free
BAD_FORMAT row without spending a request.
Output
| query | found | status | companyUrl | companySlug | companyName | postCount | postsAvailable | posts | postUrl | postId | postedAt | postedAtText | edited | text | textTruncated | reactionCount | commentCount | mediaType | hasLink | linkUrl | isRepost | authorName | authorUrl | scrapedAt |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| https://www.linkedin.com/company/stripe | true | OK | <all posts found (full list)> | <posted at (exact)> | <posted (as linkedin shows it)> | <text was cut at 1000 characters> | <poster's page> | 1970-01-01T00:00:00.000Z |
Tips
- Filter on
isRepostbefore you quote anything. A reposted row is somebody else's words on the company's page.authorNametells you whose. - Sort on
postedAt, never onpostedAtText. The relative label is what the page said at fetch time and it ages the moment you store it. The ISO timestamp does not. excludeKeywordsis the cheap way to drop noise. A post filtered out by your keywords is not billed, so a run that only wants posts mentioning a product name costs less than the same run unfiltered.- Set
maxPoststo 3 for a wide sweep. If you are checking two hundred companies for "posted anything recently", three posts each answers it at a fraction of the cost of twenty. - Leave the residential proxy on and concurrency low. LinkedIn's sign-in wall fires on IP reputation rather than on rate, so a datacenter address is not a saving. Two at a time is the default for a reason.
vs. alternatives
| What it costs | What you get | Trade-off | |
|---|---|---|---|
This actor (linkedin-company-posts-lookup) | $0.003 per post returned, $0.00005 actor start, nothing for a miss | One row per post with an exact ISO timestamp, text, reaction and comment counts, media type, outbound link, and the real author behind every repost | It reads the recent window the public page serves, roughly the last ten posts. There is no way to page back through a page's history without an account, and this actor will not try. |
| harvestapi/linkedin-company-posts | $2 per 1,000 posts | The highest-rated actor in this niche, 4.97 across 3,270 monthly users, with deeper post history | Cheaper per post and it goes back further. Pick this one when you need the exact publish time, reposts separated from the company's own words, or a per-page cost cap. |
| Clay | $0.08 to $0.40 per enriched row in credits, on top of a seat | A whole enrichment workspace, waterfalls across dozens of providers, plus the table and the sequencing around it | If 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 yourself | Your time, plus a sign-in wall that fires on reputation rather than on rate, and markup that nests a quoted post inside its own container | The same posts | This absorbs the wall handling, the session rotation, the quote-post 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 company page a signed-out
browser gets. If LinkedIn decides that request needs an account, the row comes back BLOCKED
and free.
Why does the /company/stripe/posts/ URL not work?
It does work as input, and the actor strips it. What it cannot do is fetch it: LinkedIn redirects
that tab to a login form for anyone who is not signed in. The plain company page carries the same
recent updates and is served to guests, so that is what gets fetched.
How far back does it go?
As far as the Updates section carries, which was ten posts on the page this was built against and
varies by company. 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.
Some rows have another company's name in authorName. Why?
Because the page reposted that company's post. isRepost is true on those rows. Filter it out
if you only want the company's own words, or keep it if you are studying who they amplify.
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.
Why is commentCount sometimes empty?
Because the page published no number for that post, which is normal on a post nobody has
commented on yet. It is reported as null rather than 0, because "nobody has commented" and
"LinkedIn did not say" are different facts.
What does edited mean?
LinkedIn shows an "Edited" marker next to the age of a post that was changed after publishing.
That marker is reported as its own boolean rather than glued onto the date, so postedAtText
stays a clean 6h or 2w.
Does it work for member profiles?
No. Feed it an /in/ link and it returns a free BAD_FORMAT row without spending a request.
Member profiles have their own actor, linkedin-profile-posts-lookup.
What happens to a page with no public updates?
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.
Personal data, and your responsibility
This actor reads public LinkedIn company pages only. It never signs in, never sends a cookie or a session token, and never requests anything behind the sign-in wall.
Most of what comes back is organisation content rather than personal data, but not all of it: a repost row names the person who wrote the original post, and a small company's page can identify individuals on its own. Where the GDPR, the UK GDPR, the CCPA or a comparable law applies to you, you need your own lawful basis for collecting and using that, and your own answer on retention and notice. 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.
Related actors
- LinkedIn Profile Posts Lookup: the same thing for member profiles.
- LinkedIn Company Lookup: firmographics behind a company page, rather than what it posted.
- LinkedIn Profile Lookup: who a person is, from a public profile link.
- LinkedIn Jobs Search Lookup: open roles from LinkedIn's public job search.