# LinkedIn Company Page Post & Engagement Extractor (`vexaloom-labs/linkedin-company-page-post-and-engagement`) Actor

Pull posts from any LinkedIn company page with captions, media, article links, hashtags, mentions, and reaction/comment/repost counts, filterable by date and engagement.

- **URL**: https://apify.com/vexaloom-labs/linkedin-company-page-post-and-engagement.md
- **Developed by:** [vexaloom-labs](https://apify.com/vexaloom-labs) (community)
- **Categories:** Social media, Lead generation, Automation
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.49 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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 Page Post & Engagement Extractor

Pull the public post history off any LinkedIn company page — captions, media, article links, hashtags, mentions, engagement counts and the top comments — **without cookies or a login**. Give it company URLs or bare slugs (one or many), and it returns one clean record per post: the company's own recent posts from its public page, plus deeper company-authored history found through the public search index.

### What this actor does

- **Company page feed:** reads the public recent-post feed of each company page (up to 10 posts, mixing in a few featured employee posts — employee posts are excluded by default and can be included with a toggle).
- **Deeper indexed history:** optionally searches the public web index for older company-authored posts, so you can go past what the page itself shows. Coverage depends on that index; the actor reports how many posts each source contributed.
- **Full post details:** each post's public page is opened for the complete text, exact publish time, top comments, follower count and media (images, video, documents). Turn detail fetching off for a faster, lighter run.
- **Documents:** document (PDF/PPTX) posts expose the title, page count, and — when requested — the original PDF, page images and the per-page text transcript.
- **Filters that actually apply:** post type, recency window, exact date range, minimum reactions/comments, reposts on/off, and sort by newest or most reactions. The legacy `cookie` field is accepted but ignored.
- Empty fields are omitted — you will never see `null` or an empty string in a record.

### Output per post

| Field | Description |
|---|---|
| `postId` | Numeric LinkedIn post ID. |
| `postUrl` | Direct link to the post on LinkedIn. |
| `sourcePostUrl` | The discovery URL that produced the record (may differ for reposts). |
| `companyName` | Display name of the company page. |
| `companySlug` | Company slug parsed from your input. |
| `companyUrl` | Canonical URL of the company page. |
| `companyLogoUrl` | Company logo image URL. |
| `authorName` | Name of the author (the company, or an employee for featured posts). |
| `authorProfileUrl` | LinkedIn URL of the author. |
| `authorHeadline` | Author headline when the page exposes one. |
| `authorFollowers` | Author's follower count. |
| `authorAvatar` | Author/company avatar image URL. |
| `content` | Full text body of the post. |
| `postedAt` | ISO 8601 publish timestamp. Rows built without opening the post page carry `postedAtApproximate: true` (date derived from the post ID). |
| `mediaType` | `text`, `image`, `video`, `article`, `document` or `repost`. |
| `mediaUrls` | Flat list of attached media URLs. |
| `mediaItems` | Structured media list (`type`, `url`, `thumbnailUrl`, `durationSec`). |
| `videoDuration` | ISO 8601 duration for video posts (e.g. `PT22S`). |
| `articleTitle`, `articleUrl` | Title/URL when the post shares an article or link. |
| `linkPreview` | Link preview metadata when present. |
| `documentTitle`, `documentPageCount` | Document post title and page count. |
| `documentUrl` | Original PDF URL (with *Include document details* on). |
| `documentPageImages[]`, `documentTranscript` | Page images and per-page text (with *Include document details* on). |
| `pollOptions` | Reserved for poll posts; LinkedIn does not expose poll options to logged-out visitors, so poll posts are returned as text. |
| `repostOf` | Original post details when this is a repost; `isRepost` is also set. |
| `hashtags[]` | Hashtags found in the post text. |
| `mentionedCompanies[]`, `mentionedPeople[]` | Entities tagged in the post. |
| `comments[]` | Top comments: `authorName`, `text`, `postedAt`, `reactionsCount`, and `authorProfileUrl` when the richer layout is served (capped at 10, up to 18 when LinkedIn serves its richer public layout). |
| `reactionsCount`, `commentsCount` | Engagement totals (0 is a real value). |
| `repostsCount` | Share count — only returned when *Include reaction breakdown* is on and LinkedIn serves the richer layout. |
| `reactionBreakdown` | Per-reaction-type counts — same conditions as `repostsCount`. |
| `viewsCount` | Reserved; LinkedIn does not publish view counts on public post pages. |
| `source` | Where the post was discovered: `companyPage`, `index` or `postUrl`. |
| `inputUrl`, `recordType`, `scrapedAt` | Your input that produced the row, `"post"`, and the scrape timestamp. |

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `auto` | `auto` / `companyPosts` / `postUrls` |
| `companyUrls` | array | – | Company page URLs or bare slugs (e.g. `hubspot`). |
| `postUrls` | array | – | Specific post links to extract (mode=postUrls). |
| `maxPostsPerCompany` | int | `10` | Hard cap per company (1–500). |
| `postTypes` | array | all | Keep only these media types. |
| `includeEmployeePosts` | bool | `false` | Include featured employee posts from the company feed (sub-brand/showcase posts already count as company posts). |
| `includeIndexedPosts` | bool | `true` | Also search the public index for older company posts. |
| `datePosted` | string | `""` | Recency window: any / 24 hours / week / month. |
| `postedAfter` | string | – | Exact ISO date: keep posts on or after this date. |
| `postedBefore` | string | – | Exact ISO date: keep posts on or before this date. |
| `minReactions` | int | `0` | Minimum reactions threshold. |
| `minComments` | int | `0` | Minimum comments threshold. |
| `sortBy` | string | `recent` | `recent` (newest first) or `popular` (most reactions). |
| `includeReposts` | bool | `true` | Keep reposts in the output. |
| `hydratePosts` | bool | `true` | Open each post page for full details. |
| `includeReactionBreakdown` | bool | `false` | Add `reactionBreakdown` and `repostsCount` when available. |
| `includeDocumentDetails` | bool | `false` | Add PDF URL, page images and transcript for documents. |
| `monitorMode` | bool | `false` | Return only posts not seen by a previous run. |
| `language` | string | `en` | Preferred content language. |
| `cookie` | string | – | Legacy field, accepted and ignored. |

#### Example: daily prefill (smallest run)

```json
{
  "mode": "auto",
  "companyUrls": ["https://www.linkedin.com/company/hubspot/"],
  "maxPostsPerCompany": 2
}
```

#### Example: monitor competitor pages weekly

```json
{
  "mode": "companyPosts",
  "companyUrls": ["salesforce", "hubspot", "zendesk"],
  "maxPostsPerCompany": 30,
  "datePosted": "r604800",
  "includeIndexedPosts": true,
  "monitorMode": true
}
```

#### Example: only high-engagement posts, newest first

```json
{
  "mode": "companyPosts",
  "companyUrls": ["https://www.linkedin.com/company/nvidia/"],
  "maxPostsPerCompany": 50,
  "minReactions": 100,
  "sortBy": "popular",
  "postTypes": ["text", "image", "video"]
}
```

#### Example: documents with full details

```json
{
  "mode": "companyPosts",
  "companyUrls": ["google", "microsoft"],
  "maxPostsPerCompany": 25,
  "postTypes": ["document"],
  "includeDocumentDetails": true
}
```

### Use cases

- **Competitive intelligence** — track what competitors publish, and how their audiences react.
- **Sales & ABM signals** — watch target accounts for launches, funding, hiring and event posts.
- **Content strategy** — analyse posting cadence, formats and top-performing topics across a sector.
- **Social listening exports** — feed company post data into BI tools, CRMs or AI pipelines.
- **Recruiting research** — follow employer-brand content and engagement trends.
- **Monitoring automation** — schedule runs with monitor mode to collect only new posts.

### FAQ

#### Does this actor need cookies or a LinkedIn login?

No. Everything is collected from public pages without any account, cookie or API key. The legacy `cookie` input is accepted for compatibility with older saved tasks and ignored.

#### Why does a company return fewer posts than I expected?

A company page's public feed only shows its latest handful of posts (up to 10 cards). Turn on *Include indexed posts* to search the public web index for older company-authored posts — that usually finds more, but its coverage varies by company. LinkedIn itself stops a company's full post history at 500 posts and one year.

#### Can it read the company's "Posts" tab with pagination?

No — LinkedIn requires a sign-in for that tab, and it stays behind the login page from every connection type we tested. The actor works from the public recent feed plus the public search index instead, and says so in the run summary when a company's feed is not public.

#### Why are some dates marked `postedAtApproximate`?

When detail fetching is off, the publish date is derived from the post ID (accurate to about an hour). With detail fetching on (the default), the exact timestamp from the post page is used.

#### How many comments are returned?

Up to 10 top comments from the public post page, or up to 18 when LinkedIn serves its richer public layout (which also includes commenter profile links). LinkedIn does not expose the full comment thread to logged-out visitors.

#### Why is `repostsCount` missing on some rows?

Share counts are only published in the richer public layout. Enable *Include reaction breakdown* to fetch them when available; the actor never invents a `0`.

#### Why is a document post missing its PDF link?

The PDF, page images and transcript are only fetched when *Include document details* is on. Without it, document posts still include the title and page count.

#### Do I need to set up a proxy?

No. The actor chooses a working connection to LinkedIn and the search index automatically. Just fill in the input and run it.

#### Is this affiliated with LinkedIn?

No, this is a third-party actor that reads publicly available pages. LinkedIn® is a trademark of LinkedIn Corporation.

# Actor input Schema

## `mode` (type: `string`):

What to scrape. "Auto" uses the targets you provide; the actor picks the right pipeline automatically.

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

LinkedIn company pages to scrape. Accepts full URLs (https://www.linkedin.com/company/hubspot/), a posts URL, or just the slug (hubspot).

## `postUrls` (type: `array`):

Specific LinkedIn post links to extract (any format: /posts/...-activity-..., share, ugcPost, or /feed/update/urn:li:...). Used in the "Specific post URLs" mode.

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

Maximum posts to return per company. LinkedIn itself stops a company's post history at 500 posts and one year; deeper older posts are reachable only through the public search index.

## `postTypes` (type: `array`):

Which post media types to keep. Leave empty to keep every type.

## `includeEmployeePosts` (type: `boolean`):

The public company page mixes a few featured employee posts into its recent feed. Turn this on to include them; off returns the company's own posts (including its showcase/sub-brand pages) only.

## `includeIndexedPosts` (type: `boolean`):

Also search the public web index for older company-authored posts. This finds more posts than the company page shows, but coverage depends on the search index.

## `datePosted` (type: `string`):

Keep only posts published within this window. Applied to each post's real publish date.

## `postedAfter` (type: `string`):

Only posts published on or after this date. Accepts YYYY-MM-DD or an ISO date-time.

## `postedBefore` (type: `string`):

Only posts published on or before this date. Accepts YYYY-MM-DD or an ISO date-time.

## `minReactions` (type: `integer`):

Skip posts with fewer than this many reactions.

## `minComments` (type: `integer`):

Skip posts with fewer than this many comments.

## `sortBy` (type: `string`):

How to order the returned posts. Recent = newest first, Popular = most reactions first.

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

Whether to include reposts (posts the company reshared from someone else).

## `hydratePosts` (type: `boolean`):

Open each post's public page for the full text, exact publish time, top comments and media. Turn off for a faster, lighter run.

## `includeReactionBreakdown` (type: `boolean`):

Also return the per-reaction-type breakdown and the repost (share) count when LinkedIn serves the richer public layout. Slightly slower.

## `includeDocumentDetails` (type: `boolean`):

For document (PDF/PPTX) posts, also return the original PDF link, page images and the per-page text transcript.

## `monitorMode` (type: `boolean`):

Return only posts that were not returned by a previous run with the same settings. Useful for scheduled monitoring.

## `language` (type: `string`):

Preferred content language used when requesting LinkedIn pages.

## `cookie` (type: `string`):

Kept for backward compatibility with older saved tasks. The actor is 100% cookieless; any value here is ignored.

## Actor input object example

```json
{
  "mode": "auto",
  "companyUrls": [
    "https://www.linkedin.com/company/hubspot/"
  ],
  "maxPostsPerCompany": 2,
  "postTypes": [],
  "includeEmployeePosts": false,
  "includeIndexedPosts": true,
  "datePosted": "",
  "minReactions": 0,
  "minComments": 0,
  "sortBy": "recent",
  "includeReposts": true,
  "hydratePosts": true,
  "includeReactionBreakdown": false,
  "includeDocumentDetails": false,
  "monitorMode": false,
  "language": "en"
}
```

# Actor output Schema

## `posts` (type: `string`):

Dataset containing all scraped LinkedIn company posts.

# 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 = {
    "mode": "auto",
    "companyUrls": [
        "https://www.linkedin.com/company/hubspot/"
    ],
    "maxPostsPerCompany": 2,
    "includeEmployeePosts": false,
    "includeIndexedPosts": false,
    "datePosted": "",
    "minReactions": 0,
    "minComments": 0,
    "sortBy": "recent",
    "includeReposts": true,
    "hydratePosts": true,
    "includeReactionBreakdown": false,
    "includeDocumentDetails": false,
    "monitorMode": false,
    "language": "en"
};

// Run the Actor and wait for it to finish
const run = await client.actor("vexaloom-labs/linkedin-company-page-post-and-engagement").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 = {
    "mode": "auto",
    "companyUrls": ["https://www.linkedin.com/company/hubspot/"],
    "maxPostsPerCompany": 2,
    "includeEmployeePosts": False,
    "includeIndexedPosts": False,
    "datePosted": "",
    "minReactions": 0,
    "minComments": 0,
    "sortBy": "recent",
    "includeReposts": True,
    "hydratePosts": True,
    "includeReactionBreakdown": False,
    "includeDocumentDetails": False,
    "monitorMode": False,
    "language": "en",
}

# Run the Actor and wait for it to finish
run = client.actor("vexaloom-labs/linkedin-company-page-post-and-engagement").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 '{
  "mode": "auto",
  "companyUrls": [
    "https://www.linkedin.com/company/hubspot/"
  ],
  "maxPostsPerCompany": 2,
  "includeEmployeePosts": false,
  "includeIndexedPosts": false,
  "datePosted": "",
  "minReactions": 0,
  "minComments": 0,
  "sortBy": "recent",
  "includeReposts": true,
  "hydratePosts": true,
  "includeReactionBreakdown": false,
  "includeDocumentDetails": false,
  "monitorMode": false,
  "language": "en"
}' |
apify call vexaloom-labs/linkedin-company-page-post-and-engagement --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vexaloom-labs/linkedin-company-page-post-and-engagement"
        }
    }
}
```

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/B19O7L63i7a0To0oh/builds/dfsyX9J6qz6on8sQY/openapi.json
