# LinkedIn Scraper: Profiles, Companies & Posts (`apisamurai/linkedin-scraper`) Actor

LinkedIn scraper for public profiles, company pages and posts by URL. No login or cookies, exact limits, and you pay only for real, unique rows.

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

## Pricing

from $6.50 / 1,000 profiles

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 Scraper: Profiles, Companies & Posts

This LinkedIn scraper gets public data from LinkedIn profiles, company pages and posts by URL. Profiles come with name, location, followers, about, experience, education, articles and recommendations. Company pages come with industry, size, employee count, headquarters, website, specialties and funding. Posts come with full text, date, likes, comment count, author and the public comment preview. No LinkedIn account, login or cookies are needed, and you pay only for real, unique rows.

### What you can use it for

- **Enrich leads and CRM records** with a person's location, followers, current companies and education.
- **Research companies** for sales prospecting: industry, size, employee count, headquarters, website and funding.
- **Track posts** from founders, competitors and brands, with likes and comment counts over time.
- **Monitor a company page** and its recent posts on a schedule.
- **Collect post text** for content research, AI and NLP datasets.

### How to use

1. Open the [LinkedIn Scraper](https://apify.com/apisamurai/linkedin-scraper) page and click **Try for free**.
2. Paste profile links, company page links or post links, one per line.
3. Optionally turn on **Add recent posts of each profile and company** and set **Max posts per profile or company**.
4. Click **Start**. Rows appear in the **Output** tab while the run works.
5. Export the dataset as JSON, CSV or Excel, or check the `SUMMARY` record in the key-value store.

**API:** start a run and get the rows in one call with `POST https://api.apify.com/v2/acts/apisamurai~linkedin-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>` and the input as JSON in the body.

### Input

| Field | What it does |
|---|---|
| Profile links | `https://www.linkedin.com/in/parrsam/` or just `parrsam`. One row per profile. |
| Company page links | `https://www.linkedin.com/company/shopify/` or just `shopify`. One row per company. |
| Post or article links | `/posts/...`, `/feed/update/urn:li:activity:...` or `/pulse/...` links. One row per post. |
| Add recent posts of each profile and company | Off by default. Adds the recent posts shown on each profile and company page, with full details. For people, only posts they wrote or shared. |
| Max posts per profile or company | Default 5. Enforced exactly. |

```json
{
  "profileUrls": ["https://www.linkedin.com/in/parrsam/"],
  "companyUrls": ["https://www.linkedin.com/company/shopify/"],
  "postUrls": ["https://www.linkedin.com/pulse/being-father-has-made-me-better-leader-vice-versa-austen-allred/"],
  "includePosts": true,
  "maxPostsPerProfile": 3
}
```

### Output

One row per profile, company or post; `type` tells them apart. Field names never change between runs, and missing values are `null`, never a fake 0. Example profile row from a live run (shortened):

```json
{
  "type": "profile",
  "id": "satyanadella",
  "url": "https://www.linkedin.com/in/satyanadella/",
  "name": "Satya Nadella",
  "location": "Redmond, Washington, United States",
  "followers": 12266288,
  "connections": null,
  "about": "As chairman and CEO of Microsoft, I define my mission and that of my company as empowering ...",
  "experience": [
    { "company": "Microsoft", "companyUrl": "https://www.linkedin.com/company/microsoft", "location": "Greater Seattle Area", "description": null, "startDate": "2014-02", "endDate": null },
    { "company": "Starbucks", "companyUrl": "https://www.linkedin.com/company/starbucks", "location": null, "description": null, "startDate": "2017", "endDate": "2024" }
  ],
  "education": [
    { "school": "The University of Chicago Booth School of Business", "schoolUrl": "https://www.linkedin.com/school/universityofchicagoboothschoolofbusiness/", "location": null, "description": null, "startDate": "1994", "endDate": "1996" }
  ],
  "articles": [{ "title": "My annual letter: Building the frontier ecosystem", "url": "https://www.linkedin.com/pulse/my-annual-letter-building-frontier-ecosystem-satya-nadella-iujec", "publishedAt": "2026-10-21T20:41:14.000Z" }],
  "recentActivity": [{ "id": "7521344259774660609", "text": "Just wrapped our earnings call. It was a fast start to our fiscal year. ...", "activityType": "Post", "postedAt": "2026-10-28T22:56:51.348Z", "url": "https://www.linkedin.com/posts/satyanadella_just-wrapped-our-earnings-call-it-was-a-activity-7521344259774660609-7i67" }],
  "scrapedAt": "2026-10-29T18:50:25.239Z"
}
```

Profile rows have `type: "profile"`, `id`, `publicIdentifier`, `url`, `name`, `location`, `followers`, `connections`, `about`, `photoUrl`, `experience` (`company`, `companyUrl`, `location`, `description`, `startDate`, `endDate`; current roles first), `education` (`school`, `schoolUrl`, `location`, `description`, `startDate`, `endDate`), `articles`, `publications`, `projects`, `recommendations`, `similarProfiles`, `recentActivity`, `scrapedAt`.

Company rows have `type: "company"`, `id`, `slug`, `url`, `name`, `description`, `slogan`, `industry`, `companyType`, `size`, `employeeCount`, `followers`, `founded`, `headquarters`, `location` (`city`, `state`, `country`), `website`, `logoUrl`, `coverImageUrl`, `specialties`, `funding`, `featuredEmployees`, `similarPages`, `recentPosts`, `scrapedAt`.

Post rows have `type: "post"`, `id`, `activityUrn`, `contentUrn`, `url`, `title`, `headline`, `text`, `postedAt`, `likes`, `commentsCount`, `imageUrls`, `videoUrl`, `thumbnailUrl`, `author`, `comments`, `moreArticles` (articles only), `source`, `input`, `scrapedAt`.

Post rows found through a profile or company have `source: "profile"` or `"company"` and the profile or company link in `input`.

Each run also writes a `SUMMARY` record. For every input link it lists rows requested and delivered, posts found and delivered, duplicates, links not found, failed lookups, and why it stopped (`limit reached`, `no more results`, `private or not found`, `duplicate`, `temporary error`, `spending limit`, `free plan limit` or `data source unavailable`).

### Pricing

$6.50 per 1,000 profiles; $6.50 per 1,000 companies; $6.50 per 1,000 posts

### Fair billing

- No start fee, no per-run fee, no minimum charge. You pay per row saved.
- Only real rows are charged. Empty answers, private or missing profiles, companies and posts cost nothing.
- Duplicates are never charged. A post found on a company page and also pasted as a link is saved once.
- Failed lookups are not charged. They are counted in the `SUMMARY` record and listed in the log.
- `Max posts per profile or company` is exact: you never get, or pay for, more than you asked.
- For people, posts they only reacted to are skipped before any lookup, so you never pay for them.
- When you hit your spending limit, the run stops cleanly.
- Free Apify plan: up to 100 rows per run, so you can try it. Any paid plan removes the limit.

### Integrations

- **Apify API** to start runs and read datasets from any language, plus the Python and JavaScript clients (`apify-client`).
- **Zapier, Make and n8n** to send new rows to Google Sheets, HubSpot, Slack or a database.
- **MCP for AI agents:** connect the Apify MCP server to Claude, ChatGPT or another MCP client and the agent can run this Actor as a tool.
- **Schedules and webhooks** in Apify Console for daily or weekly runs.

### FAQ

**Do I need a LinkedIn account, login or cookies?**
No. You only need an Apify account. The Actor reads public data, the same as a logged-out visitor sees.

**Can it search LinkedIn for people or companies?**
No. It works from links you already have: profile, company page and post links.

**How many recent posts can I get per profile or company?**
Only the posts LinkedIn shows to logged-out visitors, usually a handful per page. For people, only posts they wrote or shared are included. For a complete post history, paste the post links you need.

**Why did I get fewer rows than I asked for?**
Open the `SUMMARY` record. It says for each link why it stopped: no more posts on the page, a duplicate, a private or missing page, a temporary error, the spending limit or the free plan limit.

**Why are some fields null?**
LinkedIn hides some details from logged-out visitors: headlines, job titles and degrees are never shown, and some profiles mask company names and descriptions. Masked text is returned as `null`, not as asterisks, and experience or education entries whose name is masked are left out.

**Does it get all comments of a post?**
No. Post rows include the public comment preview that LinkedIn shows, not the full comment list.

**Can I schedule it?**
Yes. Create a schedule in Apify Console, for example a weekly run over your company list, and connect an integration to get the new rows.

**Is it legal to scrape LinkedIn?**
The Actor collects only public data. You are responsible for how you use it: follow LinkedIn's terms and the laws where you live, and take care with personal data (for example under GDPR). This is not legal advice.

# Actor input Schema

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

Public LinkedIn profiles of people, e.g. https://www.linkedin.com/in/parrsam/ or just parrsam. One per line. One row per profile.

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

Public LinkedIn company pages, e.g. https://www.linkedin.com/company/shopify/ or just shopify. One per line. One row per company.

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

Full details of these posts or articles: text, date, likes, comment count, author and the public comment preview. Links like https://www.linkedin.com/posts/..., /feed/update/urn:li:activity:... or /pulse/.... One per line.

## `includePosts` (type: `boolean`):

On: also save the recent posts shown on each profile and company page, one row per post with full details. For people, only posts they wrote or shared are included, not posts they reacted to. Only the posts LinkedIn shows to logged-out visitors are available, usually a handful per profile or company.

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

Maximum post rows for each profile or company when recent posts are on. Enforced exactly.

## Actor input object example

```json
{
  "profileUrls": [
    "https://www.linkedin.com/in/parrsam/"
  ],
  "companyUrls": [
    "https://www.linkedin.com/company/shopify/"
  ],
  "includePosts": false,
  "maxPostsPerProfile": 3
}
```

# Actor output Schema

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

No description

## `summary` (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 = {
    "profileUrls": [
        "https://www.linkedin.com/in/parrsam/"
    ],
    "companyUrls": [
        "https://www.linkedin.com/company/shopify/"
    ],
    "maxPostsPerProfile": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("apisamurai/linkedin-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/parrsam/"],
    "companyUrls": ["https://www.linkedin.com/company/shopify/"],
    "maxPostsPerProfile": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("apisamurai/linkedin-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/parrsam/"
  ],
  "companyUrls": [
    "https://www.linkedin.com/company/shopify/"
  ],
  "maxPostsPerProfile": 3
}' |
apify call apisamurai/linkedin-scraper --silent --output-dataset

```

## MCP server setup

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