# LinkedIn Post Scraper (`aurenic/linkedin-post-scraper`) Actor

Scrape LinkedIn posts without login. Full post text, author, reactions total + breakdown, comment count, published date, media, and shared-content (reshares). HTTP/1.1 + residential proxy. Optional cookie for profile discovery.

- **URL**: https://apify.com/aurenic/linkedin-post-scraper.md
- **Developed by:** [Aurenic](https://apify.com/aurenic) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 results

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 Post Scraper

Scrape LinkedIn posts from profiles or direct URLs using your own session cookie. Full post text, author, reactions total + breakdown, comment count, published date, media, and shared-content. HTTP/1.1 + residential proxy.

### What does LinkedIn Post Scraper do?

Extract posts from any public LinkedIn profile in two steps:

1. **Profile → posts discovery** — pass a username (`satyanadella`) or profile URL. The actor loads `/recent-activity/all/` and extracts the post URLs LinkedIn returns.
2. **Post → full data** — each post URL is fetched and parsed for the full body text, author, publication timestamp, reactions total + per-type breakdown, comment count, images, and reshare context.

You can also pass direct post URLs without profiles for one-off fetches.

### Setup — getting your LinkedIn cookie

The actor needs **your own LinkedIn session cookie** to bypass LinkedIn's bot detection (HTTP 999). You paste it once per run — the actor never sees your password.

1. Log in to `linkedin.com` in your browser
2. Press **F12** to open DevTools
3. Go to the **Application** tab (Chrome/Edge) or **Storage** tab (Firefox)
4. In the left sidebar: **Cookies** → **https://www.linkedin.com**
5. Find the cookie named **`li_at`**
6. Copy its **Value** (a long string starting with `AQED...`)
7. Paste into the **LinkedIn Cookie** field — just the value, no `li_at=` prefix needed

The cookie lasts weeks to months. If the actor starts failing with `HTTP 401/999 — cookie may be invalid or expired`, re-copy it from your browser.

**Alternatively**, paste the entire cookie header string (`li_at=...; JSESSIONID=...; bcookie=...`) — both forms work.

### Output fields

| Field | Description |
|---|---|
| postUrl | Canonical post URL |
| activityId | Numeric activity ID |
| type | `SocialMediaPosting`, `Article`, `VideoObject` |
| text | Full post body text |
| textLength | Character count |
| headline | Post headline when present |
| description | Page description fallback |
| authorName | Author display name |
| authorUrl | Author profile URL |
| authorImage | Author avatar |
| publishedAt | ISO 8601 publication timestamp |
| reactionsTotal | Total reactions |
| commentCount | Total comments |
| reactionsByType | Per-type breakdown object |
| imageCount / images / thumbnail | Attached media |
| sharedContent | Original post when this is a reshare |
| isReshare | Reshare flag |
| sourceProfile | Which profile produced this post |
| keywords | Keywords from structured data |

### Who is it for?

- **Social media analysts** tracking post engagement and topic trends
- **Content marketers** benchmarking competitor post performance
- **Recruiters and sales teams** monitoring thought-leader activity
- **AI/ML builders** sourcing LinkedIn post corpora for training
- **Brand monitoring teams** watching mentions across public feeds
- **Newsrooms** verifying quotes and viral posts

### Pricing

**$1.50 per 1,000 results.** No subscription.

| Results | Cost |
|---|---|
| 100 | $0.15 |
| 1,000 | $1.50 |
| 10,000 | $15.00 |

### How to use it

1. Paste your **LinkedIn Cookie** (`li_at` value from DevTools).
2. Enter one or more **Profiles** — usernames or URLs.
3. Optionally add **Direct Post URLs**.
4. Set **Max Posts per Profile** (default 10).
5. Click **Start**.

### Output example

```json
{
  "recordType": "linkedin-post",
  "postUrl": "https://www.linkedin.com/feed/update/urn:li:activity:7488618410256523265/",
  "activityId": "7488618410256523265",
  "type": "SocialMediaPosting",
  "text": "Three things I learned this year working on climate innovation...",
  "textLength": 1842,
  "authorName": "Bill Gates",
  "authorUrl": "https://www.linkedin.com/in/williamhgates",
  "authorImage": "https://media.licdn.com/dms/image/...",
  "publishedAt": "2026-06-14T09:30:00Z",
  "reactionsTotal": 18422,
  "commentCount": 611,
  "reactionsByType": { "Like": 15200, "Celebrate": 2100, "Support": 1122 },
  "imageCount": 1,
  "images": ["https://media.licdn.com/dms/image/..."],
  "thumbnail": "https://media.licdn.com/dms/image/...",
  "sharedContent": null,
  "isReshare": false,
  "sourceProfile": "williamhgates",
  "scrapedAt": "2026-09-26T12:00:00.000Z"
}
```

### Technical details

- **Cookie-authenticated requests.** The `li_at` session cookie makes every request look like a real logged-in browser session — this is what bypasses LinkedIn's HTTP 999 bot-detection. No account is created by the actor; you supply your own session.
- **JSON-LD `SocialMediaPosting` is the primary extraction path.** LinkedIn embeds a schema.org block on post pages — the actor parses it directly. DOM selectors are a fallback for text and images.
- **HTTP/1.1 required.** LinkedIn's edge blocks HTTP/2 fingerprints regardless of headers. The actor uses `got-scraping` with `http2: false`.
- **Residential proxy** for IP-level safety on top of the authenticated session. Rotates every 30 requests.
- **URL normalization** — all three common post URL forms map to one canonical URL + activity ID. Deduping happens before fetching.
- **No browser, no rendering.** Pure HTTP + Cheerio.

### Known limits

- **Cookie is required.** LinkedIn blocks unauthenticated profile access with HTTP 999. There is no keyless path — every working LinkedIn actor on the Apify Store requires a user-supplied cookie.
- **Cookie can expire.** LinkedIn invalidates `li_at` after weeks to months, or when you log out of the browser session. The actor fails fast with `HTTP 401/999 — cookie may be invalid or expired` so you know to re-copy it.
- **Rate limits still apply per IP.** Even authenticated sessions are rate-limited. The actor rotates residential proxy sessions every 30 requests.
- **Public activity only.** The actor cannot see posts only visible to a user's connections — even with your cookie, it sees what your account can see.
- **`commentCount` is what LinkedIn publishes** — the actor does not paginate into comment threads.
- **Some posts return short `articleBody`** — LinkedIn truncates JSON-LD for very long posts. The DOM fallback catches most cases but not all.

### FAQ

**Do I need a LinkedIn account?** You need to be logged into LinkedIn in your browser to obtain the cookie. The actor itself never creates or uses an account — it only uses the session token you paste.

**Where exactly do I find the `li_at` cookie?** DevTools (F12) → Application → Cookies → `https://www.linkedin.com` → find `li_at` → copy its value. Full step-by-step is in the README setup section above.

**Is pasting my cookie safe?** The cookie is a session token, not your password. It's passed only to linkedin.com from the actor's proxy IP. If you're worried about exposure, log out of LinkedIn in your browser afterward — this invalidates the cookie. Or use a dedicated throwaway LinkedIn session.

**Why does the actor need a cookie?** LinkedIn blocks unauthenticated profile access with a non-standard HTTP 999 status code. Cookies are how every working LinkedIn scraper on the Apify Store operates.

**How long does the cookie last?** Typically weeks to months, or until you log out of that browser session.

**How do I export data?** After a run, go to Storage → Export as JSON, CSV, Excel.

### Support

Open an issue on the Actor's page for bugs or feature requests.

# Actor input Schema

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

Required only if you pass profiles. Not needed for direct post URLs. Paste the li\_at value from your LinkedIn session (DevTools → Application → Cookies → https://www.linkedin.com → li\_at). The actor never sees your password — only this session token.

## `profiles` (type: `array`):

LinkedIn profile usernames or URLs. Examples: 'satyanadella', 'https://www.linkedin.com/in/satyanadella/'. The actor fetches /recent-activity/all/ and extracts the posts it returns.

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

Optional. Direct LinkedIn post URLs to fetch in addition to profile-discovered posts. Three forms accepted: /posts/{slug}-activity-{id}-{suffix}, /feed/update/urn:li:activity:{id}/, or a bare numeric activity ID.

## `maxPostsPerProfile` (type: `integer`):

Hard cap on how many posts to pull from each profile.

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

Hard cap on total records per run.

## `includeRaw` (type: `boolean`):

Attach the full parsed JSON-LD block under a `raw` field for debugging.

## `requestDelayMs` (type: `integer`):

Delay between requests. Authenticated LinkedIn sessions tolerate faster requests, but 1500ms is a polite default.

## `sessionRotateEvery` (type: `integer`):

Force a residential proxy IP change after this many requests. Keeps per-IP rate-limit risk low.

## Actor input object example

```json
{
  "profiles": [],
  "postUrls": [
    "https://www.linkedin.com/feed/update/urn:li:activity:7488618410256523265/",
    "https://www.linkedin.com/posts/williamhgates_the-best-things-i-read-listened-to-and-activity-7488618410256523265-47dm"
  ],
  "maxPostsPerProfile": 5,
  "maxPosts": 50,
  "includeRaw": false,
  "requestDelayMs": 1500,
  "sessionRotateEvery": 30
}
```

# 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 = {
    "cookie": "",
    "profiles": [],
    "postUrls": [
        "https://www.linkedin.com/feed/update/urn:li:activity:7488618410256523265/",
        "https://www.linkedin.com/posts/williamhgates_the-best-things-i-read-listened-to-and-activity-7488618410256523265-47dm"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("aurenic/linkedin-post-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 = {
    "cookie": "",
    "profiles": [],
    "postUrls": [
        "https://www.linkedin.com/feed/update/urn:li:activity:7488618410256523265/",
        "https://www.linkedin.com/posts/williamhgates_the-best-things-i-read-listened-to-and-activity-7488618410256523265-47dm",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("aurenic/linkedin-post-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 '{
  "cookie": "",
  "profiles": [],
  "postUrls": [
    "https://www.linkedin.com/feed/update/urn:li:activity:7488618410256523265/",
    "https://www.linkedin.com/posts/williamhgates_the-best-things-i-read-listened-to-and-activity-7488618410256523265-47dm"
  ]
}' |
apify call aurenic/linkedin-post-scraper --silent --output-dataset

```

## MCP server setup

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