# LinkedIn Posts Scraper — Companies, People, Keywords & URLs (`inovaflow/linkedin-posts-scraper`) Actor

Scrape LinkedIn posts from company pages, people profiles, keyword or hashtag searches and post links. One clean row per post: text, exact date, author, reactions, comments, images, video, links, reposted original. Date and engagement filters. No login, no cookies.

- **URL**: https://apify.com/inovaflow/linkedin-posts-scraper.md
- **Developed by:** [inovaflow](https://apify.com/inovaflow) (community)
- **Categories:** Social media, Lead generation, Marketing
- **Stats:** 6 total users, 4 monthly users, 99.8% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 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.

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 posts as clean rows — from company pages, people profiles, keyword or hashtag searches and post links. No login, no cookies, $2 per 1,000 posts, $0.50 per 1,000 comments.**

If you keep an eye on a market on LinkedIn, you know the routine: a few company pages to check, the founders and sales leaders who post every week, and the searches for your product, your competitors or a phrase like *"MCP server"*. LinkedIn shows all of this to anyone who opens the page, but the moment you try to collect it the official way you need a logged-in account, your own cookies in someone else's tool, and a prayer that the account survives.

We needed this for our own prospecting and content research, so we built it to be boring and dependable: every post comes from LinkedIn's **public** pages (the ones a logged-out visitor sees), through a rotating pool of proxy connections, with nothing of yours involved. Keyword searches run through Brave Search and Google, every post found is opened and read in full, and a page LinkedIn refuses becomes a line in the status message instead of a failed run. Now we're sharing it.

### Who it's for

- **Sales and lead-gen teams** — *"Everyone who posted about 'hiring an SDR' this month, with their profile link."*
- **Marketers and brand teams** — *"Every post that mentions our product or a competitor, with reactions and comments."*
- **Founders and content creators** — *"What do the ten people I learn from post, and which posts of theirs take off?"*
- **Researchers and analysts** — *"All posts of these 50 company pages since January, as one table."*
- **AI agents and pipelines** — *"Fresh posts from a list of companies and people as flat JSON, on a schedule."*

### What you can scrape

| Source | What to enter | You get |
|---|---|---|
| **Company pages** | `apify`, a company / school / showcase URL | The page's latest posts, then older ones found through web search when you ask for more |
| **People profiles** | `jancurn`, a profile URL | Their recent posts and reposts, their articles, then older posts through web search |
| **Keywords, phrases, hashtags** | `web scraping`, `"MCP server"`, `#hiring` | Public posts that match, found via Brave Search and Google and read in full |
| **Post links** | A post URL, a `feed/update/urn:li:activity:…` link, a URN or the bare id | The post itself, with its visible comments if you want them |

Mix them freely. Any LinkedIn URL works in any field — a profile link pasted into "Post links" is still read as a profile.

**Each post row:** post link, exact publish time (to the millisecond — it is encoded in the post id), author name, profile or company link, author type (person / company) and follower count, full text with line breaks, hashtags, mentioned people and companies (name + link), outbound links (unwrapped from LinkedIn's redirect), content kind (text, image, video, document, article, repost), image URLs, the video file and thumbnail, the linked article (title, URL, source), reaction count and the reaction types shown, comment count, and for reposts the original: author, link, text, date and media.

**Each comment row** (when you ask for comments): post id and link, commenter name and profile link, text, exact date, reactions.

A post found through two sources (say, a company page and a search) is delivered once.

### Options that matter

- **Maximum posts per source** — a cap for each company, profile, query and for the post list. A company page shows its latest ~10 posts and a profile its latest ~10 posts and reposts; when you ask for more, the Actor looks up the author's older posts on Brave and Google (`site:linkedin.com/posts/<author>_`) and reads them.
- **Posted after / before** — a date (`2026-09-01`) or a window (`24h`, `7d`, `2w`, `3m`, `1y`). Because the post time is known from the id, posts outside the range are skipped before any page is read, and never charged.
- **Content type**, **author type** (people / companies), **minimum reactions**, **minimum comments**, **include reposts** — plain filters on what is delivered.
- **Order** — newest first (default), most reactions first, or search relevance.
- **Open every post page** — on by default: each post found on a company or profile page is read in full (exact time, media, reaction types, the whole reposted original, visible comments). Turn it off for a faster run that takes only what the page shows.
- **Include comments** — adds one row per visible comment (LinkedIn shows a logged-out visitor the first comments of a post, usually up to 10–20). Charged per comment.
- **Also search Google** — off by default. Brave Search is free and returns up to ~20 posts per query and time window; Google (through Apify's Google SERP proxy) paginates further but is slower and often unreadable, so it is used only when you switch it on and more posts are wanted than Brave returned. **Search pages per query** caps both.
- **Only posts that contain the query.** Search engines pad a thin query with loosely related pages; a keyword search delivers a post only when every quoted phrase and hashtag — and most of the loose words — really appear in it. A plain two-to-five-word query is searched as a phrase.

### How to set it up

1. Add at least one company page, profile, keyword or post link.
2. Set the maximum posts per source and, for monitoring, a "posted after" window.
3. Run. Rows land in the dataset as each source finishes; the status message and the `OUTPUT` record list what every source returned and why anything was unavailable.

Schedule it for daily monitoring, or call it from the API / an AI agent (the MCP tool description is the input schema).

### Pricing

Pay per result: **$0.002 per post** ($2 per 1,000) and **$0.0005 per comment** ($0.50 per 1,000), plus the platform's start fee ($0.005 per GB of memory, one unit at the default 512 MB). Posts removed by your filters, duplicates and empty runs are never charged.

### Notes

- **No account, no cookies.** Everything comes from LinkedIn's public pages, so there is nothing of yours to risk and nothing to configure.
- **What a guest can and cannot see.** Public posts, reactions and comment counts, and the first comments of a post are public. Private profiles, posts shared "to connections only", poll results and the full comment list are not, and are not guessed.
- **Reposts.** A repost with the reposter's own words keeps those words in `text` and the original in the `repostOf…` fields; a plain repost has `contentType = repost`, an empty `text` and the original in `repostOf…`. What a person merely liked or commented on is never listed as their post.
- **How far back.** The page itself shows the latest ~10 posts; older posts depend on what Brave and Google have indexed for that author — typically dozens, sometimes hundreds, for active accounts.
- **Proxies.** LinkedIn's public pages open through Apify's datacenter proxy; when an IP is rate-limited the request switches to the residential proxy by itself. You do not need to change the proxy setting.
- Need every comment, the reactor list, or posts shared to connections only? Those need a logged-in session, which this Actor deliberately does not use.

# Actor input Schema

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

LinkedIn company, school or showcase pages — full URLs or just the slug (`apify`, `https://www.linkedin.com/company/apify/`). Their latest posts come from the page; older ones are found through web search when you ask for more than the page shows.

## `profileUrls` (type: `array`):

Public profiles of people — full URLs or just the public identifier (`jancurn`, `https://www.linkedin.com/in/jancurn/`). You get their recent posts and reposts, plus their articles.

## `searchQueries` (type: `array`):

Find public posts by what they say: `web scraping`, `"MCP server"`, `#hiring`, `AI agents startup`. Quotes keep an exact phrase. Each query is searched on the web (Brave, then Google) and every matching post page is read in full.

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

Specific posts to read: a post link (`https://www.linkedin.com/posts/…-activity-7514686314999513088-rSrF`), a feed link (`…/feed/update/urn:li:activity:…`), a URN or the bare numeric id.

## `maxPostsPerSource` (type: `integer`):

Cap per company, profile, query or post list. A company or profile page shows its latest 10–20 posts; asking for more makes the Actor look up the author's older posts through web search.

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

Only posts published after this moment: a date (`2026-09-01`), a date-time, or a relative value (`24h`, `7d`, `2w`, `3m`, `1y`). The exact post time is known from the post id, so older posts are skipped before any page is read.

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

Only posts published before this moment (same formats as above).

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

Order of the rows within each source.

## `contentType` (type: `string`):

Keep only posts of one kind.

## `authorType` (type: `string`):

Keep only posts written by people or only by company pages (useful for keyword searches).

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

Keep reposts (the row carries the original author, link and text in the repostOf… fields). Turn off for original posts only.

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

Skip posts with fewer reactions.

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

Skip posts with fewer comments.

## `fetchPostDetails` (type: `boolean`):

Open each post found on a company or profile page as well: exact publish time, media, reaction types, the full reposted original and the visible comments. Turn off to take only what the page shows (faster; text, counts and times are still there). Posts from keyword searches and post links are always read in full.

## `includeComments` (type: `boolean`):

Add one row per visible comment (type = comment, with the commenter's name, profile link, text, date and reactions). Charged per comment; implies opening every post page.

## `maxCommentsPerPost` (type: `integer`):

LinkedIn shows a guest the first comments of a post (usually up to 10–20).

## `discoverOlderPosts` (type: `boolean`):

When a company or profile page shows fewer posts than the maximum, find the author's older posts via Brave and Google and read them in full. Turn off to take only what the page shows.

## `useGoogleSearch` (type: `boolean`):

Brave Search is free and finds up to ~20 posts per query and time window. Turn this on to continue on Google through Apify's Google SERP proxy when more posts are wanted than Brave returned: it paginates further but each result page is paid and often slow, and Google frequently answers with a page that cannot be read.

## `maxSearchPagesPerQuery` (type: `integer`):

Budget of search-engine pages per keyword query or per author look-up (Brave queries and Google pages together).

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

How many LinkedIn pages are read at the same time.

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

LinkedIn's public pages open fine through Apify's datacenter proxy (the default). Whenever an IP is rate-limited the Actor switches that request to the residential proxy by itself, so there is normally nothing to change here.

## Actor input object example

```json
{
  "companyUrls": [
    "https://www.linkedin.com/company/apify/"
  ],
  "profileUrls": [
    "https://www.linkedin.com/in/jancurn/"
  ],
  "searchQueries": [],
  "postUrls": [],
  "maxPostsPerSource": 20,
  "sortBy": "date",
  "contentType": "any",
  "authorType": "any",
  "includeReposts": true,
  "minReactions": 0,
  "minComments": 0,
  "fetchPostDetails": true,
  "includeComments": false,
  "maxCommentsPerPost": 20,
  "discoverOlderPosts": true,
  "useGoogleSearch": false,
  "maxSearchPagesPerQuery": 6,
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

One row per post: link, publish time, author, text, hashtags, mentions, links, media, reactions, comment count, reposted original.

## `comments` (type: `string`):

One row per comment (only when comments were requested): post, commenter, text, date, reactions.

## `summary` (type: `string`):

Posts and comments delivered and charged, the per-source report (what LinkedIn or the search engines refused and why), filters applied and request statistics.

# 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/apify/"
    ],
    "profileUrls": [
        "https://www.linkedin.com/in/jancurn/"
    ],
    "searchQueries": [],
    "postUrls": [],
    "maxPostsPerSource": 20,
    "postedAfter": "",
    "postedBefore": "",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("inovaflow/linkedin-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/apify/"],
    "profileUrls": ["https://www.linkedin.com/in/jancurn/"],
    "searchQueries": [],
    "postUrls": [],
    "maxPostsPerSource": 20,
    "postedAfter": "",
    "postedBefore": "",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("inovaflow/linkedin-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/apify/"
  ],
  "profileUrls": [
    "https://www.linkedin.com/in/jancurn/"
  ],
  "searchQueries": [],
  "postUrls": [],
  "maxPostsPerSource": 20,
  "postedAfter": "",
  "postedBefore": "",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call inovaflow/linkedin-posts-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,inovaflow/linkedin-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/a5RuwCQn4JtkVzTw4/builds/pAwQIqTmEC6Vvkyn9/openapi.json
