# LinkedIn Public People Profile Scraper (`automation-lab/linkedin-public-people-profile-scraper`) Actor

Extract public identity, headline, location, employer, experience, and education from supplied logged-out LinkedIn profile URLs for lead enrichment and workforce research.

- **URL**: https://apify.com/automation-lab/linkedin-public-people-profile-scraper.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Lead generation, Social media
- **Stats:** 3 total users, 2 monthly users, 76.5% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.40 / 1,000 profile extracteds

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## LinkedIn Public People Profile Scraper

Turn supplied **LinkedIn public profiles** into typed professional records without asking for LinkedIn credentials or cookies. Add known `linkedin.com/in/...` URLs and receive public identity, headline, location, employer, experience, education, audience, and source fields when LinkedIn exposes them to logged-out visitors.

This Actor is designed for recurring lead enrichment and workforce research. It does not search for people, log in to LinkedIn, or claim to reveal fields that LinkedIn masks.

### What does LinkedIn Public People Profile Scraper do?

For each supplied public profile URL, the Actor:

1. validates and normalizes the LinkedIn `/in/` URL;
2. starts a bounded logged-out public web session;
3. reads LinkedIn's structured public person metadata;
4. removes values that LinkedIn replaces with asterisks;
5. normalizes public career and education fields;
6. saves one typed dataset row for each successful profile;
7. charges a profile event only for a successfully saved profile.

Duplicate input URLs are fetched once. Unavailable, private, deleted, or blocked profiles are logged and skipped. A run fails clearly if none of the supplied URLs produces a useful public profile.

### Who is this LinkedIn profile scraper for?

- **Sales operations teams** enriching known prospect profile URLs before CRM import.
- **Recruiters and talent sourcers** adding public role, employer, location, and education context to candidate lists.
- **Workforce researchers** comparing public professional attributes across a supplied cohort.
- **RevOps analysts** normalizing mixed profile URL lists into consistent records.
- **Data teams** feeding public professional metadata into spreadsheets, warehouses, and enrichment pipelines.

Use a separate profile URL finder when you need discovery. This Actor starts from URLs you already have.

### Why use this Actor?

#### No LinkedIn credentials

The input contains only public profile URLs. The Actor never requests a LinkedIn email, password, session cookie, or Sales Navigator account.

#### Typed, source-linked output

Every successful row contains canonical and fetched URLs plus an extraction timestamp. Experience and education are arrays rather than unstructured page text.

#### Honest logged-out visibility

LinkedIn sometimes masks employers, titles, dates, skills, or education details. Masked values are omitted and a `warnings` message explains the limitation. Empty arrays do not mean that the person has no experience, education, skills, or languages; they mean those fields were not exposed through the supported public surface.

#### Batch-safe behavior

The Actor validates every URL, deduplicates the supplied list, respects `maxItems`, uses bounded retries, and stops with a non-zero failure when no useful result is available.

### What LinkedIn public profile data is extracted?

| Field | Type | Meaning |
| --- | --- | --- |
| `fullName` | string | Public profile name |
| `headline` | string or null | Public professional headline |
| `location` | string or null | Public profile location |
| `countryCode` | string or null | Public country code when exposed |
| `currentEmployer` | string or null | First publicly exposed employer |
| `about` | string or null | Public profile summary |
| `experience` | array | Public title, company, company URL, and dates when exposed |
| `education` | array | Public institution, URL, degree, and years when exposed |
| `skills` | array | Skills exposed in public structured profile data |
| `languages` | array | Public languages when exposed |
| `followerCount` | number or null | Public follower count |
| `profileImageUrl` | string or null | Public profile image URL |
| `linkedinUrl` | string | Canonical profile URL returned by LinkedIn |
| `sourceUrl` | string | Normalized URL requested by the Actor |
| `scrapedAt` | string | ISO 8601 observation timestamp |
| `warnings` | array | Notices about masked public values |

### How much does it cost to extract LinkedIn public profiles?

The Actor uses pay-per-event pricing:

- one `start` event at **$0.005** for each run;
- one `profile` event for each successfully extracted and saved public profile.

| Apify plan | Run start | Per successful profile |
| --- | ---: | ---: |
| Free | $0.005 | $0.00460 |
| Bronze | $0.005 | $0.00400 |
| Silver | $0.005 | $0.00312 |
| Gold | $0.005 | $0.00240 |
| Platinum | $0.005 | $0.00160 |
| Diamond | $0.005 | $0.00112 |

Failed, unavailable, duplicate, or rejected URLs do not produce a profile event. On the Bronze plan, 1 successful profile costs **$0.009**, 25 cost **$0.105**, and 100 cost **$0.405**, including the run-start event.

As a usage example, a run with 25 supplied URLs and 22 successful public profiles costs **$0.093** on Bronze. Batch URLs in one run when practical so that you pay the start event once.

### Getting started

1. Open the Actor input page in Apify Console.
2. Add one or more public `https://www.linkedin.com/in/...` URLs.
3. Set **Maximum profiles** to the largest number you want processed.
4. Click **Start**.
5. Open the default dataset.
6. Review `warnings` before using career fields in a workflow.
7. Export the rows as JSON, CSV, Excel, XML, or RSS, or fetch them through the Dataset API.

### Input parameters

#### LinkedIn profile URLs (`startUrls`)

Required. Add between 1 and 1,000 public LinkedIn `/in/` profile URLs.

```json
{
  "startUrls": [
    { "url": "https://www.linkedin.com/in/williamhgates/" },
    { "url": "https://www.linkedin.com/in/satyanadella/" }
  ]
}
```

The Actor accepts the request-list-source format used by Apify's URL editor. Other domains, company pages, job pages, search pages, and malformed URLs fail validation.

#### Maximum profiles (`maxItems`)

Optional integer from 1 to 1,000. The default is 10. Processing considers at most this many unique normalized input URLs.

```json
{
  "startUrls": [
    { "url": "https://www.linkedin.com/in/satyanadella/" },
    { "url": "https://www.linkedin.com/in/satyanadella/" },
    { "url": "https://www.linkedin.com/in/jeffweiner08/" }
  ],
  "maxItems": 2
}
```

The duplicate Satya Nadella URL is fetched once.

### Output example

A current logged-out public result has this shape:

```json
{
  "fullName": "Bill Gates",
  "headline": "Gates Foundation",
  "location": "Seattle, Washington, United States",
  "countryCode": "US",
  "currentEmployer": "Gates Foundation",
  "about": "Chair of the Gates Foundation. Founder of Breakthrough Energy. Co-founder of Microsoft…",
  "experience": [
    {
      "title": null,
      "company": "Gates Foundation",
      "companyUrl": "https://www.linkedin.com/company/gates-foundation",
      "startDate": null,
      "endDate": null
    }
  ],
  "education": [
    {
      "institution": "Harvard University",
      "institutionUrl": "https://www.linkedin.com/school/harvard-university/",
      "degree": null,
      "startYear": 1973,
      "endYear": 1975
    }
  ],
  "skills": [],
  "languages": [],
  "followerCount": 40601541,
  "profileImageUrl": "https://media.licdn.com/dms/image/...",
  "linkedinUrl": "https://www.linkedin.com/in/williamhgates",
  "sourceUrl": "https://www.linkedin.com/in/williamhgates/",
  "scrapedAt": "2026-08-26T06:36:19.398Z",
  "warnings": [
    "LinkedIn masked one or more logged-out experience fields; masked values were omitted."
  ]
}
```

Public values, counts, image URLs, and visibility change over time. Treat this as the output shape, not a permanent snapshot of the person.

### Build a lead-enrichment workflow

A practical recurring workflow is:

1. collect profile URLs through a consented CRM, event list, or public search workflow;
2. deduplicate URLs in your source system;
3. run this Actor on the known URLs;
4. join results back on `sourceUrl` or `linkedinUrl`;
5. segment by public headline, location, or employer;
6. review warnings and null fields instead of treating them as negative facts;
7. schedule a later run only when you have a lawful need to refresh public observations.

The Actor does not perform outreach or infer contact details.

### Run workforce research responsibly

For aggregate research:

- define the cohort before running the Actor;
- retain `scrapedAt` with each observation;
- distinguish `null` and empty arrays from confirmed absence;
- avoid conclusions based on a field LinkedIn masks selectively;
- aggregate where individual identification is unnecessary;
- keep only the data needed for the research purpose.

### Schedule recurring profile enrichment

Apify schedules can rerun the same task daily, weekly, or monthly. Use recurring runs only when changes matter to your workflow. Store snapshots in your own destination if you need comparisons; this Actor returns the current public observation and does not create alerts or compare historical runs itself.

Useful patterns include:

- refresh known account executives before quarterly territory planning;
- update a consented recruiting pipeline weekly;
- observe a defined public leadership cohort monthly;
- trigger a downstream CRM import through a webhook after success.

### Export to spreadsheets and data pipelines

The default dataset works with:

- JSON and JSONL for services and warehouses;
- CSV or Excel for analysts and recruiters;
- the Apify Google Sheets integration;
- webhooks for downstream automation;
- Make, Zapier, and other Apify integrations;
- Dataset API reads from Node.js, Python, or any HTTP client.

Nested `experience` and `education` arrays are preserved in JSON. For flat spreadsheet workflows, transform those arrays downstream or select the top-level `currentEmployer` field.

### API usage with cURL

Start a run and wait for completion:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~linkedin-public-people-profile-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "startUrls": [
      {"url": "https://www.linkedin.com/in/williamhgates/"}
    ],
    "maxItems": 1
  }'
```

Keep your Apify token in a secret manager. Do not place it in source code or a public task.

### API usage with JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor(
  'automation-lab/linkedin-public-people-profile-scraper'
).call({
  startUrls: [
    { url: 'https://www.linkedin.com/in/satyanadella/' },
    { url: 'https://www.linkedin.com/in/jeffweiner08/' },
  ],
  maxItems: 2,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const profile of items) {
  console.log(profile.fullName, profile.currentEmployer, profile.linkedinUrl);
}
```

### API usage with Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor(
    "automation-lab/linkedin-public-people-profile-scraper"
).call(run_input={
    "startUrls": [
        {"url": "https://www.linkedin.com/in/williamhgates/"}
    ],
    "maxItems": 1,
})

for profile in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(profile["fullName"], profile.get("headline"))
```

### Use with Apify MCP

Add the Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/linkedin-public-people-profile-scraper"
```

**Claude Desktop setup:** add this server object to `claude_desktop_config.json`.

**Cursor setup:** add the same server object under MCP settings.

**VS Code setup:** add the same HTTP server URL to the editor's MCP server configuration.

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

Example prompts:

- “Run the LinkedIn Public People Profile Scraper for these three public profile URLs and return name, location, employer, and warnings.”
- “Enrich this supplied executive profile list and export the successful public rows as CSV.”
- “Summarize the publicly exposed education fields for this defined LinkedIn profile cohort.”

### Limits and expected failure behavior

- Only public LinkedIn `/in/` URLs are supported.
- LinkedIn decides which logged-out fields are exposed.
- Masked asterisk values are discarded.
- Private, deleted, invalid, or unavailable profiles produce no dataset row.
- A run can succeed with fewer rows than supplied URLs when some profiles are unavailable.
- A run fails when every supplied profile fails extraction.
- The Actor does not log in, solve CAPTCHAs, bypass profile privacy, search LinkedIn, extract emails, download media files, or retrieve private connection data.
- Public page structure and visibility can change without notice.

### Troubleshooting

#### Why is experience or education incomplete?

LinkedIn often shows only part of a profile to logged-out visitors and may replace values with asterisks. Check `warnings`. The Actor intentionally returns only fields exposed through the supported public surface.

#### Why did I receive fewer rows than URLs?

Review the run log for skipped URLs. Common causes are a private or deleted profile, a malformed `/in/` URL, temporary LinkedIn blocking, or no public Person metadata. Retry temporary failures later, but do not expect the Actor to reveal private profiles.

#### Why did the entire run fail?

The Actor fails if no useful profile was extracted. Check that the input uses public `linkedin.com/in/...` URLs and test one known public profile before retrying a large batch.

#### Does an empty array mean the person has none?

No. An empty `skills`, `languages`, `experience`, or `education` array means no entries were exposed through the logged-out structured surface at extraction time.

### Tips for reliable runs

- Prefer canonical public profile URLs copied from LinkedIn.
- Put multiple URLs into one run instead of starting one run per profile.
- Keep `maxItems` close to the intended batch size.
- Deduplicate upstream as well as relying on Actor deduplication.
- Preserve `warnings` in downstream systems.
- Use `scrapedAt` when comparing observations.
- Do not use a temporary field omission as evidence that a person left a role or institution.

### Legal and responsible use

Scrape only public data you are permitted to process. Follow applicable laws, contractual obligations, LinkedIn's terms, and Apify's policies. Establish a lawful purpose, minimize collected fields, secure exports, honor deletion or access rights where applicable, and avoid sensitive decisions based solely on scraped data.

This Actor is a technical data-extraction tool, not legal advice. You are responsible for your inputs, processing purpose, retention, and downstream use.

### Related automation-lab Actors

- [LinkedIn Profile URL Finder](https://apify.com/automation-lab/linkedin-profile-url-finder) discovers likely public profile URLs before enrichment.
- [LinkedIn Public Profile Search Scraper](https://apify.com/automation-lab/linkedin-public-profile-search-scraper) returns public profile search result cards.
- [LinkedIn Company Employees Scraper](https://apify.com/automation-lab/linkedin-company-employees-scraper) supports company-centered workforce discovery.
- [LinkedIn Profile Contact Enricher](https://apify.com/automation-lab/linkedin-profile-contact-enricher) adds source-attributed public company contact context when you supply official domains.

Choose this Actor when you already have public person profile URLs and need normalized public professional records.

### FAQ

#### Does it require a LinkedIn account?

No. It uses logged-out public surfaces and Apify Proxy sessions.

#### Can I provide profile slugs instead of URLs?

No. Full public `/in/` URLs make scope explicit and reduce ambiguity.

#### Does it find emails or phone numbers?

No. It extracts professional profile fields exposed publicly by LinkedIn.

#### Does it search for people?

No. Supply known public profile URLs. Use a related URL finder or public profile search Actor for discovery.

#### Are all fields guaranteed?

No. `fullName` is required for a successful row; every other public field can be null or empty when LinkedIn does not expose it.

#### Can I schedule it?

Yes. Use an Apify Task and schedule, then send the dataset to your chosen destination.

#### Is each failed URL charged as a profile?

No. The `profile` event is emitted only after a useful profile has been parsed and before its row is saved.

# Actor input Schema

## `startUrls` (type: `array`):

Public linkedin.com/in/... profile URLs to enrich. Duplicate URLs are processed once.

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

Maximum number of unique supplied profile URLs to process.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.linkedin.com/in/williamhgates/"
    },
    {
      "url": "https://www.linkedin.com/in/satyanadella/"
    }
  ],
  "maxItems": 10
}
```

# Actor output Schema

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

Default dataset containing successfully extracted public profiles.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.linkedin.com/in/williamhgates/"
        },
        {
            "url": "https://www.linkedin.com/in/satyanadella/"
        }
    ],
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/linkedin-public-people-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 = {
    "startUrls": [
        { "url": "https://www.linkedin.com/in/williamhgates/" },
        { "url": "https://www.linkedin.com/in/satyanadella/" },
    ],
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/linkedin-public-people-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 '{
  "startUrls": [
    {
      "url": "https://www.linkedin.com/in/williamhgates/"
    },
    {
      "url": "https://www.linkedin.com/in/satyanadella/"
    }
  ],
  "maxItems": 10
}' |
apify call automation-lab/linkedin-public-people-profile-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/linkedin-public-people-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/upW63ob7bIqYTD9Zl/builds/H9JzOcvVhIQ8oeExd/openapi.json
