# LinkedIn Post Scraper (`dami_studio/linkedin-profile-posts-scraper`) Actor

LinkedIn post scraper: paste profile links or names and download each person's posts and reposts as rows: text, date, likes, comment count, pictures, video links and hashtags, with optional post details and comments. Read as LinkedIn shows them to signed-out visitors.

- **URL**: https://apify.com/dami_studio/linkedin-profile-posts-scraper.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** Social media, Automation
- **Features:** Limited permissions
- **Stats:** 14 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.75 / 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 post scraper: paste profile links or names and download each person's posts and reposts as rows**, with the text, date, likes, comment count, pictures, video links and hashtags, plus the post's comments if you want them.

You give it LinkedIn profile links, or just the name at the end of each link. You get that person's newest posts first, one row per post, as LinkedIn shows them to someone who is not signed in.

It reads public posts only. A profile LinkedIn does not serve to the run comes back as a free row saying so, and you pay only for posts that come back.

| | |
|---|---|
| **Input** | LinkedIn profile links (`linkedin.com/in/...`) or profile names such as `williamhgates` |
| **Output** | One row per post: text, date, likes, comment count, pictures, video link, hashtags, links, author; post details and comments on request |
| **Ceiling** | 500 profiles per run, 100 posts per profile |
| **Account needed** | None from you |
| **Price** | $0.75 per 1,000 posts, the same rate on every plan. The free plan's $5 a month covers about 6,600 |

| Using an AI agent? | |
|---|---|
| Actor | `dami_studio/linkedin-profile-posts-scraper` |
| Set one field | `profileUrls`, labelled "Profile links or names" in the Console |
| Cap the bill | `maxTotalChargeUsd` on the run, for example `0.10`: it never charges past that |
| MCP, one link | `https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/linkedin-profile-posts-scraper` |
| How often | Daily or weekly, to follow what a list of people post |

### 🔍 What LinkedIn Post Scraper does

It opens each person's public profile, reads the posts and reposts listed there, then looks up more of that person's public posts until it has the number you asked for. Every row is one post with its text, the date it was published, its likes and comment count, its pictures and links.

Reposts come with the original author's name and link, so you can tell a person's own words from what they shared. Turn reposts off to keep only their own posts.

Two switches add more:

- **Add post details** opens each post's own page for its title, every picture, a video link and length, the linked article, and the author's follower count.
- **Add comments** adds the comments on each post, each with the commenter's name, text, date and likes. Paid per comment.

### 📋 What data you get from each LinkedIn post

| What you get | Field |
|---|---|
| The post | `postUrl`, `activityId`, `kind` (`post` or `repost`), `text`, `title` |
| When | `publishedAt`, `postedAgo` |
| Reactions | `likes`, `commentsCount` |
| Media and links | `imageUrls`, `videoUrl`, `videoDuration`, `mediaType`, `articleTitle`, `articleSubtitle`, `links`, `hashtags` |
| Who wrote it | `authorName`, `authorUrl`, `authorIsProfile`, `authorFollowers`, `authorImageUrl` |
| Comments (paid add-on) | `comments` (`author`, `authorUrl`, `text`, `publishedAt`, `likes`) |
| Where it came from | `profileUrl`, `inputUrl`, `detailsRead`, `scrapedAt` |

### ▶️ How to scrape LinkedIn posts

1. Open [LinkedIn Post Scraper](https://apify.com/dami_studio/linkedin-profile-posts-scraper) and click **Try for free**.
2. Paste profile links or names into **Profile links or names**, one per line.
3. Set **Most posts per profile**, and a date window under **Posted within** if you only want recent posts.
4. Turn on **Add post details** or **Add comments** if you need them, then click **Start**.
5. Download the rows as JSON, CSV or Excel, or read them from the API.

Leave the list empty and you get one free sample row showing the shape of the output, with nothing read.

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

**$0.75 per 1,000 posts**, which is $0.00075 each, the same rate on every plan, with or without post details. On the free plan, the $5 Apify gives you each month covers about 6,600 posts.

Comments cost **$0.56 per 1,000 comments**, charged for each comment returned.

Free rows are never charged: a profile that was not served, a profile with no post in your date window, an entry that is not a profile, the sample row, and the row that says the run stopped at your time or cost limit.

### 📥 What you give it

```json
{
  "profileUrls": ["https://www.linkedin.com/in/williamhgates"],
  "maxPostsPerProfile": 10,
  "postedLimit": "month",
  "includeReposts": true,
  "includePostDetails": false,
  "includeComments": false
}
```

| Field | Default | What it is |
|---|---|---|
| `profileUrls` | none, the form starts with one example | Up to 500 profile links or names. A company page is refused with a free row. |
| `maxPostsPerProfile` | `10` | 1 to 100, newest first. |
| `postedLimit` | `any` | `any`, `24h`, `week`, `month`, `3months`, `6months` or `year`. |
| `postedAfter` | none | A day as `YYYY-MM-DD`. When set, it replaces `postedLimit`. Any other format is refused before anything runs. |
| `includeReposts` | `true` | Off keeps only the person's own posts. |
| `includePostDetails` | `false` | Opens each post's page for the details above. Slower, same price. |
| `includeComments` | `false` | Adds the comments on each post. Paid per comment. |

### 📤 What you get back

A real row from a run on 7 November 2026 with comments on. The text and the comment list are cut short, and the commenter's name is shortened here:

```json
{
  "ok": true,
  "recordType": "post",
  "profileUrl": "https://www.linkedin.com/in/williamhgates",
  "kind": "post",
  "postUrl": "https://www.linkedin.com/posts/williamhgates_bad-news-isnt-the-only-news-bill-gates-activity-7524574266554605568-I338",
  "activityId": "7524574266554605568",
  "authorName": "Bill Gates",
  "authorUrl": "https://www.linkedin.com/in/williamhgates",
  "authorIsProfile": true,
  "text": "The challenges we face today are tough. But I try to remember that we've cut child deaths by more than half since the turn of the century…",
  "title": "The challenges we face today are tough.",
  "publishedAt": "2026-11-06T20:51:44.975Z",
  "postedAgo": "20h",
  "likes": 880,
  "commentsCount": 134,
  "mediaType": "image",
  "articleTitle": "Bad news isn't the only news | Bill Gates",
  "articleSubtitle": "gatesnotes.com",
  "links": ["https://lnkd.in/evkxp6Je"],
  "authorFollowers": 40797849,
  "detailsRead": true,
  "comments": [
    {
      "author": "C. P.",
      "text": "Cancer vaccines sound promising (pending side effects)…",
      "publishedAt": "2026-11-06T21:06:04.619Z",
      "likes": 2
    }
  ],
  "scrapedAt": "2026-11-07T17:12:24.886Z"
}
```

| Field | Read it like this |
|---|---|
| `kind` | `post` is the person's own post; `repost` is someone else's post they shared, and `authorName` is the original author |
| `publishedAt` | When the post was published. On a repost it is the original post's date |
| `postedAgo` | LinkedIn's own "20h", "3w", "1y", when the profile page shows one |
| `likes`, `commentsCount` | As counted when the run read them |
| `title`, `mediaType`, `videoUrl`, `authorFollowers` | Only with post details or comments on, otherwise not in the row |
| Picture and video links | LinkedIn's own links. They stop working after a while, so save the file if you need it |

### 🧾 Reading the output

Every real row has `ok: true` and `recordType: "post"`. Rows with `ok: false` are free notes, one per profile that gave no posts, with `errorCode` and `error` saying why:

| `errorCode` | What happened |
|---|---|
| `NOT_SERVED` | The profile was not served this run. Re-run it later. A misspelled name ends here too |
| `NO_RESULTS` | The profile shows no post, or none in your date window |
| `BAD_INPUT` | The entry is not a person's profile link or name, or the date is not `YYYY-MM-DD` |
| `TIME_LIMIT` | The run reached its time limit; `notRead` lists the profiles it did not get to and `cutShort` the ones it stopped partway through |
| `COST_LIMIT` | The run reached the maximum cost you set; `notRead` lists the rest |

An empty run returns one sample row with `_sample: true`. To keep only real posts, filter on `ok` being true. The **Comments** view lists one comment per line and the **Notes** view lists the free rows.

### 💡 What people use it for

- **Sales and partnership teams** watching what a list of prospects or partners post, to start a conversation on something real.
- **Recruiters** reading what candidates write about their work before a call.
- **Brand and PR teams** following executives' posts and how much engagement each one gets.
- **Researchers** collecting the public posts of a group of people over a date range.

A simple chain: take the profile links of your prospects from a CRM export, run them here weekly with **Posted within** set to `week`, then sort by `likes` to see what landed.

### 🚧 What it does not do

- No company pages. For a company's posts, use [LinkedIn Company Posts Scraper](https://apify.com/dami_studio/linkedin-company-posts-scraper).
- No list of who liked a post.
- No e-mail addresses or phone numbers.
- Nothing from inside a LinkedIn account: no messages, no private posts, nothing only signed-in members see.
- It is not an official LinkedIn tool. Dami's Studio is independent and is not affiliated with or endorsed by LinkedIn, or by any other company named on this page.

### 🧭 Which LinkedIn scraper do you need?

| If you want | Use |
|---|---|
| A person's posts and reposts | This one |
| The posts a company page publishes | [LinkedIn Company Posts Scraper](https://apify.com/dami_studio/linkedin-company-posts-scraper) |
| A company's size, industry and headquarters | [LinkedIn Companies Scraper](https://apify.com/dami_studio/linkedin-companies-scraper) |
| Job listings | [LinkedIn Jobs Scraper](https://apify.com/dami_studio/linkedin-jobs-scraper) |
| Posts that match keywords | [LinkedIn Post Search Scraper](https://apify.com/dami_studio/linkedin-post-search-scraper) |
| The comments on a post | [LinkedIn Comments Scraper](https://apify.com/dami_studio/linkedin-post-comments-scraper) |

### ❓ Questions people ask

#### Do I need a LinkedIn account to scrape posts?

No. You don't need a LinkedIn account, a cookie or a login. The actor reads the public profile and post pages LinkedIn shows to anyone who opens the link.

#### Why did I get fewer posts than I asked for?

The run returns the posts it can find publicly for that person, newest first, up to your number. Someone who posts rarely, or a date window that is short, gives fewer rows. You pay only for the rows you get.

#### Why do the like and comment counts differ from what I see on LinkedIn?

They are counted at the moment the run reads the post, and they keep moving. A signed-in view can also show a little more than a visitor sees. Open the post in a private browser window to compare.

#### Can I call it from code or an AI assistant?

Yes. The [API tab](https://apify.com/dami_studio/linkedin-profile-posts-scraper/api) has ready-made calls, and AI assistants can use it through Apify's MCP server at `https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/linkedin-profile-posts-scraper`. In Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("dami_studio/linkedin-profile-posts-scraper").call(
    run_input={"profileUrls": ["williamhgates"], "maxPostsPerProfile": 10},
    max_total_charge_usd=0.05,
)
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row.get("ok") is False:
        continue
    print(row["publishedAt"], row["likes"], row["text"][:80])
```

#### Is scraping LinkedIn legal?

The actor reads public posts the way a signed-out visitor sees them, with no account and nothing private. Posts and comments carry personal data, so GDPR and similar laws apply to what you keep and how you use it: keep only what you need, and mind the rules on contacting people. LinkedIn's own terms still apply to what you do with the data. Apify has a good write-up on [the legality of web scraping](https://blog.apify.com/is-web-scraping-legal/). We are not lawyers, and this is not legal advice.

### 🆘 If something breaks

Open an issue on the actor's **Issues** tab. Include the run ID and the profile link that went wrong, and we will look at it.

# Actor input Schema

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

LinkedIn profile links, like https://www.linkedin.com/in/williamhgates, or just the name at the end of the link (williamhgates). Each profile's recent posts come back, one row per post.

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

The newest posts first, up to this many per profile. You pay only for posts that come back.

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

Keep only posts from this window. Leave on Any time to keep them all.

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

Keep only posts from this day on, as YYYY-MM-DD, for example 2026-10-01. When set, it replaces Posted within.

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

Also return posts the person reposted from others. Turn off to keep only their own posts.

## `includePostDetails` (type: `boolean`):

Also opens each post's own page for its title, every picture, a video link, the linked article, and the author's follower count and picture. Slower, same price.

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

Adds the comments on each post, with the commenter's name, text, date and likes. Charged per comment returned.

## Actor input object example

```json
{
  "profileUrls": [
    "https://www.linkedin.com/in/williamhgates"
  ],
  "maxPostsPerProfile": 10,
  "postedLimit": "any",
  "includeReposts": true,
  "includePostDetails": false,
  "includeComments": false
}
```

# Actor output Schema

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

Every row in the default dataset: the post's text, date, likes, comment count, pictures, links and author, with post details and comments when asked for. A profile that could not be read returns a free row saying why.

# 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 = {
    "profileUrls": [
        "https://www.linkedin.com/in/williamhgates"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/linkedin-profile-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 = { "profileUrls": ["https://www.linkedin.com/in/williamhgates"] }

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

```

## MCP server setup

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