# LinkedIn Company Posts Lookup: posts scraper from $3/1k (`accountable_eel/linkedin-company-posts-lookup`) Actor

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.

- **URL**: https://apify.com/accountable\_eel/linkedin-company-posts-lookup.md
- **Developed by:** [Adrian Voss](https://apify.com/accountable_eel) (community)
- **Categories:** Lead generation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.28 / 1,000 post returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## 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: 3` across 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 `authorName` column
  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. `postedAtText` keeps 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 `isRepost` flags them
  and `authorName` and `authorUrl` name 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 `BLOCKED` and free.
- **You are billed per post, and you can cap it.** `maxPosts` sets 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.

```bash
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

1. **In the Apify Console.** Open the actor page and click **Start** — the `companies` 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:
   ```bash
   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"]}'
   ```
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

```json
{
  "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 | <company page> | <company slug> | <company> | <posts returned> | <posts the page carried> | \<all posts found (full list)> | <post link> | <post id> | \<posted at (exact)> | \<posted (as linkedin shows it)> | <edited after posting> | <post text> | \<text was cut at 1000 characters> | <reactions> | <comments> | <media> | <links out> | <links to> | <repost of someone else> | <posted by> | \<poster's page> | 1970-01-01T00:00:00.000Z |

### Tips

- **Filter on `isRepost` before you quote anything.** A reposted row is somebody else's words on
  the company's page. `authorName` tells you whose.
- **Sort on `postedAt`, never on `postedAtText`.** 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 a product name costs less than the same
  run unfiltered.
- **Set `maxPosts` to 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](https://apify.com/accountable_eel/linkedin-profile-posts-lookup)**: the same thing for member profiles.
- **[LinkedIn Company Lookup](https://apify.com/accountable_eel/linkedin-company-lookup)**: firmographics behind a company page, rather than what it posted.
- **[LinkedIn Profile Lookup](https://apify.com/accountable_eel/linkedin-profile-lookup)**: who a person is, from a public profile link.
- **[LinkedIn Jobs Search Lookup](https://apify.com/accountable_eel/linkedin-jobs-search-lookup)**: open roles from LinkedIn's public job search.

# Actor input Schema

## `companies` (type: `array`):

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. You're only charged for the ones we actually find — a miss costs nothing.

## `testRun` (type: `boolean`):

Turn this on to test your input on a small sample before running the full list. Turn it off to process everything.

## `onlyFound` (type: `boolean`):

Only keep rows where something was actually found. Misses are always free, whether or not you show them here.

## `includeKeywords` (type: `array`):

Optional. Only keep results that mention at least one of these words (e.g. a job title, a city, a product name). Leave empty to keep everything.

## `excludeKeywords` (type: `array`):

Optional. Drop any result that mentions one of these words. Leave empty to skip nothing.

## `maxResults` (type: `integer`):

Optional. Stop the run once this many results have been found — useful for a quick, cheap sample. Leave blank for no limit.

## `maxPosts` (type: `integer`):

Optional. Caps how many posts each company page returns, newest first, which is also the most you are billed for that page. The public page carries up to 20; leave it at 20 to take everything it served.

## `columns` (type: `array`):

Choose which pieces of information to include in each result row. All are included by default.

## `expandRows` (type: `boolean`):

When on, each post found gets its own row instead of being grouped under its company page. You're still only charged once per company page, no matter how many rows it produces.

## `maxConcurrency` (type: `integer`):

Parallel requests. Keep conservative — this target has no browser fallback, so getting blocked costs more than slow-and-steady.

## `proxyConfiguration` (type: `object`):

Apify Proxy config. Residential recommended for anti-bot-sensitive targets.

## Actor input object example

```json
{
  "companies": [
    "https://www.linkedin.com/company/stripe",
    "shopify"
  ],
  "testRun": false,
  "onlyFound": false,
  "includeKeywords": [],
  "excludeKeywords": [],
  "maxPosts": 20,
  "columns": [
    "companyUrl",
    "companySlug",
    "companyName",
    "postCount",
    "postsAvailable",
    "posts",
    "postUrl",
    "postId",
    "postedAt",
    "postedAtText",
    "edited",
    "text",
    "textTruncated",
    "reactionCount",
    "commentCount",
    "mediaType",
    "hasLink",
    "linkUrl",
    "isRepost",
    "authorName",
    "authorUrl"
  ],
  "expandRows": true,
  "maxConcurrency": 2,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "companies": [
        "https://www.linkedin.com/company/stripe",
        "shopify"
    ],
    "includeKeywords": [],
    "excludeKeywords": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("accountable_eel/linkedin-company-posts-lookup").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "companies": [
        "https://www.linkedin.com/company/stripe",
        "shopify",
    ],
    "includeKeywords": [],
    "excludeKeywords": [],
}

# Run the Actor and wait for it to finish
run = client.actor("accountable_eel/linkedin-company-posts-lookup").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "companies": [
    "https://www.linkedin.com/company/stripe",
    "shopify"
  ],
  "includeKeywords": [],
  "excludeKeywords": []
}' |
apify call accountable_eel/linkedin-company-posts-lookup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,accountable_eel/linkedin-company-posts-lookup"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/NcAfWCyzzuSuWhbSr/builds/1LhRyl4naVVebfFGU/openapi.json
