# LinkedIn Profile Scraper (`axiomworks/linkedin-profile-scraper`) Actor

Scrape public LinkedIn profiles from profile URLs or usernames. Returns name, headline, location, about, current positions, experience, education, follower count, recent posts and profile URL, with optional similar-profile URLs. No LinkedIn login or cookies needed.

- **URL**: https://apify.com/axiomworks/linkedin-profile-scraper.md
- **Developed by:** [Axiom Works](https://apify.com/axiomworks) (community)
- **Categories:** Lead generation, Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.38 / 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.
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 Profile Scraper

### What does LinkedIn Profile Scraper do?

LinkedIn Profile Scraper reads the public, logged-out page of each LinkedIn profile you give it and returns one structured dataset row per unique profile. You provide `/in/` profile URLs or bare public identifiers such as `satyanadella`, and the Actor returns the name, headline, location, about text, current positions, experience, education, follower count, recent posts and the "People also viewed" links that the page exposes.

The Actor needs no LinkedIn account, no cookies and no session token. It only requests the profile pages you list. It does not use LinkedIn search, it does not crawl company pages, and it does not open the suggested profiles it finds; those URLs are returned as output values only. Duplicate identifiers in your input are fetched once. Country sub-domains, query strings and trailing slashes are normalised to `https://www.linkedin.com/in/<identifier>`.

Typical uses include enriching a CRM list with headlines and current employers, checking that a list of speaker or candidate profiles is still public, building lead lists from profiles you already know, and collecting public professional background for research. This Actor is independent and has no affiliation with LinkedIn.

Two things are worth knowing before you start:

- **Hidden or missing profiles.** Some profiles return HTTP 999 on every attempt, usually because they are hidden from logged-out visitors or do not exist. After the retries run out, the Actor pushes a row with `error: "not_public_or_blocked"` (or `"not_found"`) and does not charge for it. If no profile at all can be extracted, the run fails with an explanation.
- **Limited profiles.** LinkedIn sometimes serves a reduced public page with masked values. Those rows are flagged with `isLimitedProfile: true`. The Actor never tries to reveal masked values.

### What data can you get?

Each row contains the fields below. Scalar fields that the page does not expose are `null`, and list fields that are unavailable are empty arrays.

| Field | Type | Description |
|---|---|---|
| `id` | string | Stable public identifier, the same as `publicIdentifier`. |
| `sourceUrl` | string | The profile page that was requested. |
| `url` | string | Normalised public profile URL. |
| `publicIdentifier` | string | The identifier from the `/in/` URL. |
| `fullName` | string | Name shown on the public profile. |
| `headline` | string | Headline under the name. |
| `location` | string | Location text shown on the profile. |
| `countryCode` | string | Country code from structured profile data, when present. |
| `about` | string | Summary or about text. |
| `profilePictureUrl` | string | Public profile picture URL. |
| `followers` | integer | Follower count when shown. |
| `connections` | string | Connection count text such as `500+`. |
| `badges` | string | Short badge or descriptor text, when present. |
| `currentPositions` | array | Current employers with company, company URL, location and start date. |
| `jobTitles` | array | Job titles listed in structured data. |
| `experience` | array | Past and present roles with title, company, dates, location and description. |
| `education` | array | Schools with degree text and dates. |
| `pastOrganizations` | array | Organisations the person is an alumnus of. |
| `languages` | array | Languages listed. |
| `awards` | array | Awards listed. |
| `websites` | array | External websites listed on the profile. |
| `recentPosts` | array | Recent posts found in the page's structured data. |
| `articles` | array | Articles found in the page's structured data. |
| `alsoViewed` | array | Profile URLs shown in "People also viewed". |
| `isLimitedProfile` | boolean | True when the page contained masked values. |
| `enrichment` | object | Present only when `enrich` is true, see below. |
| `error` | string | Present only on rows that could not be extracted. |
| `scrapedAt` | string | ISO timestamp of the extraction. |

**Optional enrichment.** With `enrich: true`, each extracted row gets an `enrichment` object with `seniority`, `department`, `firstName`, `lastName`, `currentCompanySlug` and `totalYearsExperience`. These are computed by rules from the fields above, with no extra requests. Enrichment does not use any AI service and sends no profile data to a third party.

### How to use LinkedIn Profile Scraper

1. Open the Actor in Apify Console and go to the Input tab.
2. Paste one or more LinkedIn profile URLs or public identifiers into **Profile URLs or identifiers**.
3. Set **Maximum profiles** to the number of rows you want.
4. Leave the proxy setting on Apify residential proxy. LinkedIn commonly answers datacenter addresses with HTTP 999.
5. Turn on **Derive enrichment** if you want the extra `enrichment` object; it costs extra per result.
6. Click Start. When the run finishes, open the Output tab to view, filter and download the dataset as JSON, CSV, Excel or HTML.

The Actor keeps a modest pace: it waits at least one second between requests and retries with exponential backoff and a fresh proxy session when it sees HTTP 999, 429 or a server error.

### Input

| Field | Type | Description |
|---|---|---|
| `profileUrls` | array of strings | Public profile URLs or identifiers to extract. Must be a non-empty list, otherwise the run fails with a clear message. |
| `maxItems` | integer | Maximum number of unique profile rows to return, 1-1000, default 50. Hidden or blocked profiles count towards this limit. |
| `includePosts` | boolean | Include recent posts and articles found in the page's structured data. Default true. |
| `includeSimilarProfiles` | boolean | Include the "People also viewed" profile URLs in `alsoViewed`. They are not crawled. Default true. |
| `enrich` | boolean | Derive `seniority`, `department`, name parts, company slug and years of experience (rule-based, no AI). Costs extra per result. Default false. |
| `maxRetries` | integer | Retries for HTTP 999, 429 and server errors, 0 to 10. Default 4. |
| `proxyConfiguration` | object | Apify Proxy settings. Residential proxy is the default. |

```json
{
    "profileUrls": ["https://www.linkedin.com/in/satyanadella", "williamhgates"],
    "maxItems": 2,
    "includePosts": true,
    "includeSimilarProfiles": true,
    "enrich": false
}
```

### Output

This is a real row from a run on linkedin.com/in/satyanadella (lists shortened):

```json
{
    "id": "satyanadella",
    "sourceUrl": "https://www.linkedin.com/in/satyanadella",
    "url": "https://www.linkedin.com/in/satyanadella",
    "publicIdentifier": "satyanadella",
    "fullName": "Satya Nadella",
    "headline": "Chairman and CEO at Microsoft",
    "location": "Redmond, Washington, United States",
    "countryCode": "US",
    "about": "As chairman and CEO of Microsoft, I define my mission and that of my company as empowering every person and every organization on the planet to achieve more.",
    "profilePictureUrl": "https://media.licdn.com/dms/image/v2/C5603AQHHUuOSlRVA1w/profile-displayphoto-shrink_200_200/profile-displayphoto-shrink_200_200/0/1579726625398?e=2147483647&v=beta&t=Rr7WT9uBM0byOij0oT_KirejIMVE4HK4r8NGIp0zjdI",
    "followers": 12195507,
    "connections": "500+",
    "badges": "Creator, Top Voice",
    "currentPositions": [
        {
            "company": "Microsoft",
            "companyUrl": "https://www.linkedin.com/company/microsoft",
            "location": "Greater Seattle Area",
            "startDate": null
        },
        {
            "company": "University of Chicago",
            "companyUrl": "https://www.linkedin.com/school/uchicago/",
            "location": null,
            "startDate": null
        }
    ],
    "jobTitles": [
        "Chairman and CEO",
        "Member Board Of Trustees"
    ],
    "experience": [
        {
            "title": "Chairman and CEO",
            "subtitle": "Microsoft",
            "startDate": "Feb 2014",
            "endDate": "Present",
            "duration": "12 years 8 months",
            "location": "Greater Seattle Area",
            "description": null,
            "companyUrl": "https://www.linkedin.com/company/microsoft"
        },
        {
            "title": "Member Board Of Trustees",
            "subtitle": "University of Chicago",
            "startDate": "2018",
            "endDate": "Present",
            "duration": "8 years",
            "location": null,
            "description": null,
            "companyUrl": "https://www.linkedin.com/school/uchicago/"
        }
    ],
    "education": [
        {
            "title": "The University of Chicago Booth School of Business",
            "subtitle": null,
            "startDate": "1994",
            "endDate": "1996",
            "companyUrl": "https://www.linkedin.com/school/universityofchicagoboothschoolofbusiness/"
        },
        {
            "title": "Manipal Institute of Technology, Manipal",
            "subtitle": "Bachelor’s Degree Electrical Engineering",
            "startDate": null,
            "endDate": null,
            "companyUrl": "https://www.linkedin.com/school/manipal-institute-of-technology/"
        }
    ],
    "pastOrganizations": [
        {
            "name": "Starbucks",
            "url": "https://www.linkedin.com/company/starbucks",
            "type": "Organization",
            "startDate": null,
            "endDate": null
        },
        {
            "name": "The Business Council U.S.",
            "url": "https://www.linkedin.com/company/the-business-council-us",
            "type": "Organization",
            "startDate": null,
            "endDate": null
        }
    ],
    "languages": [],
    "awards": [],
    "websites": [
        "https://snscratchpad.com/"
    ],
    "recentPosts": [
        {
            "url": "https://www.linkedin.com/posts/satyanadella_the-motivation-behind-the-new-copilot-intelligence-activity-7509276499837902849-DFP-",
            "text": "The motivation behind the new Copilot: intelligence is accelerating fast. Now we need to diffuse it everywhere.",
            "datePublished": "2026-09-25T15:43:53.171Z",
            "likes": 922
        }
    ],
    "articles": [
        {
            "url": "https://www.linkedin.com/pulse/how-do-we-build-frontier-intelligence-ecosystem-satya-nadella-73jhc",
            "headline": "How do we build a frontier intelligence ecosystem?",
            "datePublished": "2026-06-02T19:41:31.000+00:00",
            "likes": 2538
        }
    ],
    "alsoViewed": [
        "https://www.linkedin.com/in/tony-bates-679227a5",
        "https://www.linkedin.com/in/charlesphillips1"
    ],
    "isLimitedProfile": false,
    "scrapedAt": "2026-09-30T18:09:57.142Z"
}
```

Rows for `experience` take `location` only from the location line of each card and use `null` when the card has none. Company and school URLs are returned without tracking parameters.

A profile that is hidden or missing produces a short row like this (illustrative), and it is not charged:

```json
{
    "id": "example-person",
    "sourceUrl": "https://www.linkedin.com/in/example-person",
    "url": "https://www.linkedin.com/in/example-person",
    "publicIdentifier": "example-person",
    "fullName": null,
    "isLimitedProfile": false,
    "scrapedAt": "2025-01-15T12:00:00.000Z",
    "error": "not_public_or_blocked"
}
```

The dataset has an overview view with the most useful columns, and you can export it in any format Apify supports.

### How much does it cost to scrape LinkedIn profiles?

The Actor uses pay-per-event pricing. The `result` event is charged once for each extracted profile row, whether it is a full or a limited profile. The `enriched-result` event is charged once for each row that gets an `enrichment` object, only when `enrich` is true. Rows with an `error` are never charged. See the Pricing tab for current rates. Platform usage such as proxy traffic and compute is shown in your run's cost summary.

### Use with the API

You can start the Actor from code with the Apify API clients or plain HTTP.

**Python**

```python
import os

from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("axiomworks/linkedin-profile-scraper").call(
    run_input={"profileUrls": ["satyanadella"], "maxItems": 1}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["fullName"], item["headline"])
```

**JavaScript**

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('axiomworks/linkedin-profile-scraper').call({
    profileUrls: ['satyanadella'],
    maxItems: 1,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
process.stdout.write(JSON.stringify(items, null, 2));
```

**cURL**

```bash
curl -X POST "https://api.apify.com/v2/acts/axiomworks~linkedin-profile-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"profileUrls": ["satyanadella"], "maxItems": 1}'
```

You can also schedule runs, send results to Google Sheets, or connect the Actor to Zapier, Make and webhooks with Apify integrations.

### Use with AI agents (MCP)

You can call this Actor from any MCP client through the Apify MCP server. Add this to your client configuration:

```json
{
    "mcpServers": {
        "apify": {
            "url": "https://mcp.apify.com?tools=axiomworks/linkedin-profile-scraper"
        }
    }
}
```

Example prompts:

- "Get the headline, location and current company for linkedin.com/in/satyanadella."
- "Extract these five public LinkedIn profiles and tell me which ones list an education entry."
- "Scrape this profile with enrichment on and report the seniority and department."

### FAQ

**Does this need a LinkedIn account?** No. It requests publicly visible pages without login or cookies, and it cannot see anything that requires a login.

**Why is a field empty?** LinkedIn may serve a limited public profile, omit that field, or change its page markup. The Actor does not reveal masked values.

**Why did a profile return an error row?** HTTP 999 on every attempt usually means the profile is hidden from logged-out visitors or does not exist. Raising `maxRetries` rarely helps for hidden profiles. Confirm the URL opens in a private browser window.

**Does it fetch company pages or the suggested profiles?** No. Company and suggested profile URLs are returned as values only.

**Can I search by keyword or company?** No. The Actor takes profile URLs or identifiers that you already have.

**How many profiles can I run at once?** Profiles are fetched one after another at a polite pace, so large lists take longer. Split very large lists across several runs.

**Does enrichment use AI?** No. It uses fixed rules on the extracted fields and makes no extra requests.

### Is it legal to scrape LinkedIn?

This Actor only reads information that LinkedIn shows to anyone without logging in, and it does not bypass logins or CAPTCHAs. Data about people can still be personal data. Use it for a legitimate purpose, follow the privacy law that applies to you, such as GDPR, and check LinkedIn's terms of service and your own legal requirements before you rely on the results. This is general information and not legal advice.

### Feedback

If a field is empty when the profile page clearly shows it, or you want another field added, open an issue from the Actor's Issues tab and include the profile URL and the run ID.

# Actor input Schema

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

Public LinkedIn profile URLs or identifiers to extract, e.g. satyanadella. Country subdomains are normalized to www.linkedin.com.

## `maxItems` (type: `integer`):

Maximum number of unique profile rows to return, 1-1000, default 50. Hidden or blocked profiles count towards this limit.

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

Include recent posts and articles found in the public page JSON-LD.

## `includeSimilarProfiles` (type: `boolean`):

Include public profile URLs shown in People also viewed; these URLs are not crawled.

## `enrich` (type: `boolean`):

Derive seniority, department, name parts, company slug and years of experience from the extracted fields (rule-based, no AI). Costs extra per result. Default false.

## `maxRetries` (type: `integer`):

Retry HTTP 999, 429, or server errors this many times with fresh proxy sessions.

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

Use Apify residential proxy for logged-out LinkedIn pages; datacenter IPs often receive HTTP 999.

## Actor input object example

```json
{
  "profileUrls": [
    "https://www.linkedin.com/in/satyanadella",
    "https://www.linkedin.com/in/williamhgates"
  ],
  "maxItems": 2,
  "includePosts": true,
  "includeSimilarProfiles": true,
  "enrich": false,
  "maxRetries": 4,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset of public profile rows

# 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/satyanadella",
        "https://www.linkedin.com/in/williamhgates"
    ],
    "maxItems": 2,
    "includePosts": true,
    "enrich": false,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiomworks/linkedin-profile-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/satyanadella",
        "https://www.linkedin.com/in/williamhgates",
    ],
    "maxItems": 2,
    "includePosts": True,
    "enrich": False,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("axiomworks/linkedin-profile-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/satyanadella",
    "https://www.linkedin.com/in/williamhgates"
  ],
  "maxItems": 2,
  "includePosts": true,
  "enrich": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call axiomworks/linkedin-profile-scraper --silent --output-dataset

```

## MCP server setup

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