# LinkedIn Company Posts Scraper (`boncross/linkedin-company-posts-scraper`) Actor

Scrape the latest posts from any LinkedIn company page, with no login. Just add company URLs, slugs or names and get each post's full text, date, reactions, comment count, author, media type, images and link, plus sample comments on request. Export to CSV or Excel. $1.50 per 1,000 posts.

- **URL**: https://apify.com/boncross/linkedin-company-posts-scraper.md
- **Developed by:** [BonCross API](https://apify.com/boncross) (community)
- **Categories:** Social media, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.05 / 1,000 posts

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## LinkedIn Company Posts Scraper

### What is LinkedIn Company Posts Scraper?

LinkedIn Company Posts Scraper pulls the posts off any LinkedIn company page, newest first, with the reaction and comment counts as numbers. Type the company's name, or paste its URL or slug. You get the post text, a link to each post, its media type, and a flag on anything the company reposted or quoted.

It was built for watching more than one company at a time, and the numbers show it: 670 companies at 10 posts each returned 6,262 posts in under five minutes on 2 October 2026.

Where it's stronger than you might expect:

- **You can start from a name.** "Monzo" is enough. The name is matched to LinkedIn's own company record and the log tells you what it matched.
- **The company profile rides along free.** Switch on "Include company details on every post" and each row gains industry, size, headquarters and follower count. It adds no charge.
- **A date window makes a short run.** Ask for the last week and paging stops once the feed drops past it. You pay for the posts inside the window only.
- **Reposts are labelled.** A plain repost and a quote post are told apart, each with the original post's link where LinkedIn gives one. You can keep or drop either kind.
- **Companies with nothing to return are free.** No public posts, or a feed that can't be read: you get a row saying so and no charge.

**BonCross Verified** means we tested this actor against the live site before release and kept the record:

- 18 of 18 live checks on its inputs and filters passed on 5 October 2026
- 7 companies run on 7 October 2026 by link, slug and name: 40 posts, 2 error rows
- Charges checked against the 40 posts; error rows were free

### How to scrape LinkedIn company posts

1. [Open a free Apify account](https://console.apify.com/sign-up), then go to [LinkedIn Company Posts Scraper](https://apify.com/boncross/linkedin-company-posts-scraper).
2. Enter the companies: names, URLs or slugs.
3. Say how many posts you want from each (50 unless you change it) and, if you like, how far back to look.
4. Press Start. One company's latest 10 posts took 5.7 to 12 seconds when we measured it.
5. Download the posts as a spreadsheet, or as JSON, XML or HTML.

### What data can you extract from company posts?

| | |
|---|---|
| 📝 Full post text | 🔗 Post permalink and activity id |
| 👍 Reaction count | 💬 Comment count |
| 📅 When it was posted | Media type: text, image, video, article or document |
| Image links | Repost and quote-post flags, with the original post's link |
| 🏢 Company name, slug and id | Author name and profile |
| Sample comments, optional | Company industry, size and followers, optional |

### ⬇️ Input

Start with the companies. Everything else has a default you can live with.

"Posts per company" caps each company and defaults to 50. Set it to 0 to take everything the feed will serve. "Maximum posts" caps the run across all companies, and its default of 0 means no cap. If your list lives in a file or a Google Sheet, load it through Start URLs.

**Two companies, 50 posts each**

```json
{
  "companyUrls": ["https://www.linkedin.com/company/monzo"],
  "companyNames": ["Xelix"],
  "maxPostsPerCompany": 50
}
```

**The last month's posts, reposts left out, with comments**

```json
{
  "companyUrls": ["https://www.linkedin.com/company/microsoft"],
  "postedLimit": "month",
  "includeReposts": false,
  "scrapeComments": true,
  "maxComments": 5
}
```

| Field | Notes |
|---|---|
| `companyUrls` | Full company URLs or bare slugs. Paste the slug exactly: a trailing dot is part of it. |
| `companyNames` | Plain names, matched to LinkedIn's own company record rather than by guessing a URL from the name. The log says what each name matched. |
| `startUrls` | The same as `companyUrls`, pasted or loaded in bulk from a file or a Google Sheet. |
| `maxPostsPerCompany` | Newest first. Default 50; 0 takes everything the feed will serve. |
| `postedLimit`, `postedLimitDate` | Only return posts newer than a window (`1h`, `24h`, `week`, `month`, `3months`, or `any`) or an explicit date such as `2026-08-01`. Paging stops as soon as the feed drops past the window, so a narrow window is a short run. |
| `includeReposts` | Posts the company reposted with no commentary added. On by default. |
| `includeQuotePosts` | Posts where the company reshared something **and** added its own commentary. On by default. |
| `scrapeComments`, `maxComments` | Also open each post and return the comments LinkedIn shows publicly (up to `maxComments`, default 10). One extra request per post, charged separately. |
| `maxItems` | A ceiling on the whole run, across every company. |
| `includeCompanyDetails` | Adds industry, size, headquarters, follower count and the rest of the company profile to every post. Costs no extra requests. |
| `delayMs`, `maxConcurrency` | An optional extra pause before each request (default 0), and how many companies are read at once (default 8). |

#### For developers

- LinkedIn serves the feed 10 posts per request and the run pages through it. A larger `maxPostsPerCompany` means more requests and a longer run, nothing else.
- `postedLimit` and `postedLimitDate` stop the paging as soon as the feed drops past the window.
- `scrapeComments` opens each post once more for the comments LinkedIn shows publicly, up to `maxComments` (default 10). Each post opened is billed as `post-comments`.
- `includeCompanyDetails` makes no extra requests and has no event of its own.
- `maxConcurrency` (default 8, from 1 to 8) is how many companies are read at once. `delayMs` (default 0) adds a pause before each request.
- Posts are written as they're read, so stopping a run early keeps what it had.
- In `companyUrls`, a slug must be pasted exactly. A trailing dot is part of it.

### ⬆️ Output

Each post is one record.

```json
{
  "activityUrn": "urn:li:activity:7508810949139578880",
  "id": "7508810949139578880",
  "url": "https://www.linkedin.com/posts/monzo_were-going-to-dedicate-this-post-to-our-activity-7508810949139578880-8VYX",
  "text": "We’re going to dedicate this post to our lovely TechOps team. From the very first day when Monzonauts join, our TechOps team is there. They help us set up our l…",
  "postedText": "1d Edited",
  "postedAt": "2026-09-25",
  "reactions": 320,
  "comments": 30,
  "authorName": "Monzo",
  "authorUrl": "https://uk.linkedin.com/company/monzo",
  "mediaType": "image",
  "images": [
    "https://media.licdn.com/dms/image/v2/…/feedshare-image-high-res/…"
  ],
  "companyUrl": "https://www.linkedin.com/company/monzo",
  "companySlug": "monzo",
  "companyName": "Monzo",
  "companyId": "9471107",
  "inputSource": "url",
  "scrapedAt": "2026-09-26T06:56:59.665Z"
}
```

Four things to know before you build on it:

- `postedAt` is worked out from LinkedIn's relative wording ("1d", "2w"), which makes it approximate. `postedText` is exactly what LinkedIn showed.
- A repost has `isRepost: true` and a quote post has `isQuotePost: true`, each with `originalPostUrl` and `originalPostId` where the shared post is linked. `url` always points at the company's own post. `isCanonicalUrl: true` marks a row whose link is LinkedIn's standard activity address, used when the card had no other permalink.
- With comments switched on, each row adds `sampleComments` (author, author profile, text, posted wording and reactions for each) and `sampleCommentCount`.
- With company details switched on, each row adds `companyDescription`, `companyWebsite`, `companyIndustry`, `companySize`, `companyHeadquarters`, `companyAddressParts`, `companyType`, `companyFounded`, `companySpecialties`, `companyEmployeesCount`, `companySlogan`, `companyFollowers`, `companyLocations` and `companyLogo`.

A company whose feed can't be read, or which has no public posts, is a single row with an `error` field.

### How much does it cost to scrape LinkedIn company posts?

| Event | Free plan | Starter | Scale | Business |
|---|---|---|---|---|
| `actor-start`, per run | $0.001 | $0.001 | $0.001 | $0.001 |
| `post-comments`, per post opened for comments, only when `scrapeComments` is on | $0.001 | $0.0009 | $0.0008 | $0.0007 |
| `post`, per post returned | $0.0015 | $0.00135 | $0.0012 | $0.00105 |

Enterprise plans pay the Business price.

**$1.50 per 1,000 posts** on the Free plan and $1.05 on Business. That figure is the full bill, proxy usage and platform usage included.

- Four companies at 50 posts each: $0.001 + 200 × $0.0015 = **$0.301** ($0.21 on Business).
- The same run with comments on: $0.001 + 200 × $0.0015 + 200 × $0.001 = **$0.501** ($0.35 on Business).

If you only want the counts, leave comments off. The comment count is on each post either way, and you save $0.001 a post.

On Apify's Free plan, the $5 of monthly credits pays for about 3,300 posts.

### How far back, and how fast?

| Run | Result |
|---|---|
| One company, 10 posts | 10 posts in 5.7-12 seconds |
| 670 companies, 10 posts each | 6,262 posts in 4 minutes 16 seconds to 4 minutes 49 seconds (1,300-1,460 a minute) |
| One company, 10 posts with comments | 10 posts with their comments in 10-16 seconds |

Measured on Apify on 2 October 2026. At that pace an hour covers roughly 8,000 companies at 10 posts each, and each further 10 posts per company is one more request.

How far back a feed goes is LinkedIn's decision. The run keeps paging until LinkedIn stops returning new posts, then moves to the next company.

### FAQ

#### Why are there fewer comments than the comment count says?

The count is the real total. LinkedIn shows a logged-out visitor roughly nine or ten comments from the thread, never all of it, and that sample is what you get.

#### What's the difference between a repost and a quote post?

A repost shares someone else's post with nothing added. A quote post shares it with the company's own commentary on top. "Include reposts" and "Include quote posts" are separate switches, both on by default.

#### How exact is the date window?

To within about a day. LinkedIn gives "3d" or "2w" where you'd want a date, so `postedAt` is derived and the window inherits that. A post whose date can't be read is kept, not dropped.

#### A company I know is active returned an error row. Why?

A company that has never posted returns an error row, and LinkedIn sometimes answers a repeated request the same way. Run that company again a few minutes later.

#### Do I need proxies or a LinkedIn login?

You need neither. The posts are read from pages LinkedIn shows to anyone who isn't signed in, and the proxy usage is part of the price.

#### How do I collect only new posts each day?

Schedule the run daily and set "Posted within" to `24h`. For a weekly digest use `week`.

#### What are the limits?

- Comments are a public sample of roughly nine or ten per post, on request. The full thread isn't available.
- Timestamps are relative on LinkedIn, so dates are approximate.
- A count of zero is returned as 0, not left empty.
- Feed depth is set by LinkedIn.

#### Is scraping LinkedIn company posts legal?

Company posts are published for anyone to read, and this actor reads them without an account and collects no private data. Scraping public data is generally lawful in the UK, EU and US, with hiQ v LinkedIn the usual reference. How you use the results is on you, GDPR included where a row identifies a person, such as a comment author.

### Monitoring, dashboards and code

A watched-company alert is the common setup: an Apify Schedule, a `24h` window, and the Slack integration posting whatever came back. For reporting, send the dataset to Google Sheets or through Airbyte and chart reactions per post by media type.

To call it yourself, `POST https://api.apify.com/v2/acts/boncross~linkedin-company-posts-scraper/run-sync-get-dataset-items` with the input as JSON. That returns the posts directly on a short run. `apify-client` on NPM or PyPI handles the longer ones.

It's also available to AI agents through the Apify MCP server at `mcp.apify.com`. An agent can fetch a competitor's last month of posts and tell you what themes they're pushing.

### More from BonCross

- [LinkedIn Company Scraper](https://apify.com/boncross/linkedin-company-details-scraper): LinkedIn company pages by URL, slug or name, with no login.
- [LinkedIn Jobs Scraper](https://apify.com/boncross/linkedin-jobs-scraper): LinkedIn jobs from keywords and locations or search URLs, no login needed.
- [LinkedIn Post Scraper](https://apify.com/boncross/linkedin-post-details-scraper): Any public LinkedIn post by URL, with no login.
- [Marriott Hotel Details Scraper](https://apify.com/boncross/marriott-hotel-details): Everything a Marriott property publishes: address, coordinates, phones, brand, guest…
- [Marriott Hotel Search Scraper](https://apify.com/boncross/marriott-hotel-search): Every Marriott hotel for a destination and dates.
- [Marriott Reviews Scraper](https://apify.com/boncross/marriott-reviews): Guest reviews for any Marriott hotel.

### Your feedback

If a post's link, date or counts don't match what you see on LinkedIn, send us the company and the post on the Issues tab in Apify Console. We check each one against the live page and reply in the thread.

# Changelog

This Actor's version history is a separate document: https://apify.com/boncross/linkedin-company-posts-scraper/changelog.md

# Actor input Schema

## `companyUrls` (type: `array`):

LinkedIn company pages, as full URLs or bare slugs. Paste the slug exactly: a trailing dot is part of it.

## `companyNames` (type: `array`):

Plain company names, e.g. "Monzo". Each is resolved through LinkedIn's own search suggestions and then mapped to the real page using LinkedIn's own data. Names are not unique, so the run log states what each one matched.

## `startUrls` (type: `array`):

The same as Company URLs, in the format Apify's scheduler and integrations pass links in.

## `maxPostsPerCompany` (type: `integer`):

How many posts to return for each company, newest first. The feed is paged 10 at a time, so a larger number means more requests and a longer run. Leave at 0 to take everything LinkedIn will serve.

## `postedLimit` (type: `string`):

Only return posts newer than this. Dates on the public company feed are worked out from LinkedIn's own wording ("3d", "2w"), so this window is approximate to within a day. A post whose date cannot be read is kept rather than dropped.

## `postedLimitDate` (type: `string`):

Keep only posts published on or after this date, e.g. 2026-08-01. Overrides the window above when both are set.

## `includeReposts` (type: `boolean`):

Posts the company reposted from someone else, with no commentary added. On by default, matching what the page shows.

## `includeQuotePosts` (type: `boolean`):

Posts where the company reshared someone else's post AND added its own commentary. On by default.

## `scrapeComments` (type: `boolean`):

The company feed carries comment counts but not the comments themselves, so this opens each post's own page to read the ones LinkedIn publishes: roughly nine or ten per post, never the full thread. It costs one extra request per post, is charged as a separate event, and makes a run noticeably slower.

## `maxComments` (type: `integer`):

A ceiling on the comments kept for each post. LinkedIn publishes around ten to logged-out visitors, so a higher number will not return more.

## `maxItems` (type: `integer`):

A ceiling on the posts the whole run returns, across every company. Nothing past it is fetched or charged for. Leave at 0 for no limit.

## `includeCompanyDetails` (type: `boolean`):

Add the company's industry, size, headquarters, follower count and the rest to each post. It costs no extra requests, because the company page is fetched anyway to get the feed.

## `delayMs` (type: `integer`):

Extra pause before each request, jittered by about 30 percent either way. The run already keeps to a request rate measured safe for LinkedIn, so the default is 0; raise it only if a run reports refusals.

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

How many targets are read at once. The default is the fastest level measured clean; lower it only if a run reports refusals or errors.

## `restartAttempt` (type: `integer`):

Set by the actor when it restarts itself in a fresh container after being refused. Leave it alone.

## Actor input object example

```json
{
  "companyUrls": [
    "https://www.linkedin.com/company/google"
  ],
  "companyNames": [],
  "startUrls": [],
  "maxPostsPerCompany": 50,
  "postedLimit": "any",
  "postedLimitDate": "",
  "includeReposts": true,
  "includeQuotePosts": true,
  "scrapeComments": false,
  "maxComments": 10,
  "maxItems": 0,
  "includeCompanyDetails": false,
  "delayMs": 0,
  "maxConcurrency": 8,
  "restartAttempt": 0
}
```

# Actor output Schema

## `dataset` (type: `string`):

Every post the run returned.

## `stats` (type: `string`):

Counts for the run, and what every company name resolved to.

# 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 = {
    "companyUrls": [
        "https://www.linkedin.com/company/google"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("boncross/linkedin-company-posts-scraper").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 = { "companyUrls": ["https://www.linkedin.com/company/google"] }

# Run the Actor and wait for it to finish
run = client.actor("boncross/linkedin-company-posts-scraper").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 '{
  "companyUrls": [
    "https://www.linkedin.com/company/google"
  ]
}' |
apify call boncross/linkedin-company-posts-scraper --silent --output-dataset

```

## MCP server setup

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

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/w4c1ZPpaxz4fz6akR/builds/sGH3RTjlwwbDhpkLv/openapi.json
