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

Scrape public LinkedIn profiles: name, headline, location, about, experience, education, skills and photo. Optional email with your own session. No cookies needed for public data.

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

## Pricing

$3.40 / 1,000 profile scrapeds

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 Profile Scraper (People)

Scrape **public LinkedIn people profiles** — one or many — into clean structured JSON: full name, headline, location, about/summary, work **experience** (title, company, dates), **education**, **skills**, profile **photo**, follower count and any publicly listed contact links. It reads LinkedIn's **public profile page** (the logged-out `public_profile_v3` page that Google indexes), which embeds a rich schema.org `Person` JSON-LD block plus server-rendered Experience/Education/About sections — **no login required** for public data.

Requests use browser-grade HTTP fingerprints (`got-scraping`: real TLS + generated headers) routed through **Apify Proxy**. Residential IPs are tried first with a fresh session per retry; if LinkedIn throws an auth-wall, the actor automatically escalates to the Apify Proxy **Unblocker** group, which defeats heavier anti-bot protection.

### Input

```json
{
  "profileUrls": [
    "https://www.linkedin.com/in/williamhgates/",
    "satyanadella"
  ],
  "maxItems": 100,
  "useUnblocker": true,
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
```

- `profileUrls` — LinkedIn people-profile URLs or bare vanity usernames (e.g. `williamhgates`). Required.
- `maxItems` — cap on how many profiles from the list to scrape (default 100).
- `li_at` — **optional** LinkedIn session cookie (**yours**, never someone else's). Leave empty for public-only scraping. Supplying it reduces auth-wall blocks and can reach gated profiles. Sent only as a request cookie; never logged or stored.
- `useUnblocker` — when residential attempts are auth-walled, retry via the Unblocker proxy group (default on).
- `proxyConfiguration` — Apify Proxy config; **residential** strongly recommended.
- `timeoutSecs` — per-request timeout in seconds (default 45).
- `includeRawJsonLd` — also attach the raw schema.org `Person` JSON-LD to each record.

### Output (one record per profile)

```json
{
  "source": "profile",
  "input": "https://www.linkedin.com/in/williamhgates/",
  "url": "https://www.linkedin.com/in/williamhgates",
  "scrapedVia": "residential",
  "authenticated": false,
  "fullName": "Bill Gates",
  "firstName": "Bill",
  "lastName": "Gates",
  "headline": "Chair, Gates Foundation and Founder, Breakthrough Energy",
  "location": "Seattle, Washington, United States",
  "country": "US",
  "about": "Chair of the Gates Foundation. Founder of Breakthrough Energy. Co-founder of Microsoft...",
  "photoUrl": "https://media.licdn.com/dms/image/.../profile-displayphoto...",
  "followers": 40681488,
  "connections": null,
  "currentJobTitles": ["Co-chair", "Founder", "Co-founder"],
  "experience": [
    { "title": "Co-chair", "company": "Gates Foundation", "companyUrl": "https://www.linkedin.com/company/gates-foundation", "dateRange": "2000 - Present 26 years", "location": null }
  ],
  "education": [
    { "school": "Harvard University", "degree": null, "dateRange": "1973 - 1975" }
  ],
  "skills": [],
  "languages": [],
  "email": null,
  "emailsFound": [],
  "websites": ["https://www.linkedin.com/in/williamhgates"]
}
```

### Honest limitations

- **Email / phone are almost never public.** LinkedIn hides contact info behind login and (usually) a 1st-degree connection, so `email` is typically `null`. The actor still surfaces any genuinely public email/website it finds. To pull contact details you must supply your own `li_at` cookie, and even then some fields require being connected to the person.
- **Skills** and some sections are only present when the person exposes them publicly; when absent they come back as empty arrays.
- LinkedIn is one of the most aggressively defended sites on the web. Public-figure/creator profiles scrape reliably; low-profile or region-restricted accounts are more likely to hit an auth-wall — enable the Unblocker escalation or provide an `li_at` cookie for those.
- Use responsibly and in line with LinkedIn's terms and applicable law. Only scrape data you are permitted to access.

# Actor input Schema

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

One or more LinkedIn people-profile URLs (e.g. https://www.linkedin.com/in/williamhgates/) or bare vanity usernames (e.g. williamhgates). Each is scraped from its public profile page. Company or job URLs are not supported here — use the LinkedIn Jobs & Company scraper for those.

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

Maximum number of profiles to scrape from the list above, in case a very long list is provided. Set high to scrape everything.

## `li_at` (type: `string`):

OPTIONAL. Your own LinkedIn li\_at session cookie. Leave empty to scrape only public data (works for most public figures/creators). Provide it to reduce auth-wall blocks and reach fuller data on gated profiles. Use ONLY a cookie you own and are allowed to use — never share credentials. The actor sends it as a request cookie and never stores or logs it.

## `useUnblocker` (type: `boolean`):

When residential-proxy attempts get auth-walled, retry the same profile through the Apify Proxy UNBLOCKER group, which defeats heavier anti-bot protection (may cost more per request). Recommended on.

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

Apify Proxy settings used for the first attempts, with a fresh proxy session on every retry. Residential proxies are strongly recommended — LinkedIn aggressively auth-walls datacenter IPs. If blocked, the actor can additionally escalate to the Unblocker group (see the option above).

## `timeoutSecs` (type: `integer`):

Timeout per HTTP request to LinkedIn, in seconds (5-90).

## `includeRawJsonLd` (type: `boolean`):

Also include the raw schema.org Person JSON-LD block found on the profile page in each output record, for debugging or advanced use.

## Actor input object example

```json
{
  "profileUrls": [
    "https://www.linkedin.com/in/williamhgates/"
  ],
  "maxItems": 100,
  "useUnblocker": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "timeoutSecs": 45,
  "includeRawJsonLd": false
}
```

# Actor output Schema

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

Scrape public LinkedIn people profiles by URL or username — name, headline, location, about/summary, work experience, education, skills, photo and follower count. Reads the public profile page (no login required) via got-scraping routed through Apify residential proxy, with automatic escalation to the Unblocker group. Accepts an optional li\_at session cookie for fuller data.

# 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("bgfc97/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/williamhgates/"] }

# Run the Actor and wait for it to finish
run = client.actor("bgfc97/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/williamhgates/"
  ]
}' |
apify call bgfc97/linkedin-profile-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,bgfc97/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/01QrE418DI1jrKHQH/builds/6gPevFpnGMazFRHeC/openapi.json
