# LinkedIn Profile Scraper — Public Profile Data Extraction (`herus13/linkedin-profile-scraper`) Actor

Extract public profile data from LinkedIn without login. Gets name, headline, experience, education, skills, certifications, languages, and more.

- **URL**: https://apify.com/herus13/linkedin-profile-scraper.md
- **Developed by:** [bootforge](https://apify.com/herus13) (community)
- **Categories:** Lead generation, Jobs, Automation
- **Stats:** 5 total users, 0 monthly users, 50.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 contact person data scrapes

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 Profile Scraper

The LinkedIn Profile Scraper is an Apify actor that extracts structured data from public [LinkedIn](https://www.linkedin.com) profiles using your own `li_at` session cookie. Give it profile URLs (or bare vanity slugs) and it returns name, headline, about, full experience history, education, skills, certifications, honors, projects, connection and follower counts, badges, and — optionally — contact info (email, phone, websites). It pulls every field from LinkedIn's authenticated Voyager API in a single request per profile.

Use it to build lead lists, enrich a CRM, run recruiting sourcing, or feed a talent dataset — exported to JSON, CSV, or Excel.

### Table of contents

- [What the LinkedIn profile scraper does](#what-the-linkedin-profile-scraper-does)
- [Use cases](#use-cases)
- [How to scrape LinkedIn profiles](#how-to-scrape-linkedin-profiles)
- [LinkedIn profile scraper input](#linkedin-profile-scraper-input)
- [LinkedIn profile data output](#linkedin-profile-data-output)
- [How much it costs](#how-much-it-costs)
- [Recommended proxies for LinkedIn](#recommended-proxies-for-linkedin)
- [Why this LinkedIn profile scraper](#why-this-linkedin-profile-scraper)
- [FAQ](#faq)
- [Rate this actor](#rate-this-actor-)
- [Related actors](#related-actors)

### What the LinkedIn profile scraper does

- 🧾 **25+ structured fields per profile** — name, headline, about, location, industry, current company and title, all from one authenticated call.
- 💼 **Full experience & education history** — reverse-chronological roles with company, title, location, dates, and description; schools, degrees, and years.
- 🎯 **Skills, certifications & achievements** — skills with endorsement counts, certifications, languages, honors, publications, patents, projects, courses, organizations, and test scores.
- 📊 **Exact numeric counts** — real `connection_count_numeric` and `follower_count` (the cookie path, not the public "500+" bucket).
- 🏷️ **Profile badges** — `premium`, `verified`, `influencer`, and `open_to_work` signals.
- 📇 **Optional contact enrichment** — email, phones, websites, twitter, and IM handles via a separate call, billed only when data is returned.

### Use cases

**CRM enrichment** — Name, headline, about, full experience history, education, skills, certifications, and connection/follower counts, pulled from LinkedIn's Voyager API in a single request per profile. Turns a list of profile URLs into structured records a CRM can actually key on.

**Recruiting and sourcing** — Full experience and education history is what makes candidate screening possible at list scale, rather than opening profiles one at a time.

**Lead qualification** — Headline, current role, and company tell you whether a lead is worth pursuing before outreach. `scrape_contact_info` optionally returns email, phone, and websites where the profile exposes them.

**Talent-market datasets** — Aggregate profiles across a company or function to see tenure distribution, common prior employers, and skill concentration. Requires your own `li_at` session cookie.

### How to scrape LinkedIn profiles

1. Click **Try for free** and open the actor.
2. Paste one or more `profile_urls` (full URLs or bare `/in/` slugs).
3. Add your `cookie` — the `li_at` session cookie from your logged-in LinkedIn (see the input section below).
4. Set `proxy_country` to the country where you logged in and copied the cookie.
5. Optional: enable `scrape_contact_info` for email, phone, and websites.
6. Click **Start**, then export results as **JSON, CSV, or Excel**, or pull them from the [Apify API](https://docs.apify.com/api/v2).

```json
{
  "profile_urls": ["https://www.linkedin.com/in/williamhgates/"],
  "cookie": "<your_li_at_cookie>",
  "proxy_country": "US",
  "scrape_contact_info": true
}
```

### LinkedIn profile scraper input

| Field | Description |
|---|---|
| `profile_urls` | **Required.** LinkedIn profile URLs to scrape (e.g. `https://www.linkedin.com/in/username`). |
| `cookie` | **Optional.** Your `li_at` session cookie. With it you get the full profile (skills, connection/follower counts, every section) via LinkedIn's authenticated API. **Leave it blank** to scrape the public subset LinkedIn serves logged-out (name, headline, current roles, education, location, photo). Get it in DevTools → **Application** → **Cookies** → `linkedin.com` → copy the `li_at` value. |
| `scrape_contact_info` | Fetch the contact-info endpoint (email, phone, websites, twitter, IM). Requires a cookie. Only charged when data is returned. Default `false`. |
| `proxy_country` | Residential proxy country code. When you supply a cookie it **must match the country where you generated it** — LinkedIn deauthorizes a cookie used from a different geo. Anonymous (no-cookie) runs have no such constraint. Default `VN`. |
| `max_concurrency` | Max concurrent profile requests (default 5, max 20). |
| `max_requests_per_minute` | Rate cap to avoid LinkedIn throttling (default 30, max 120). |
| `transport` | HTTP engine for the public fetch: `auto` (curl\_cffi TLS impersonation), `curl_cffi`, `httpx`, or `primp`. The authenticated cookie path uses a browser session regardless. |
| `strategy_mode` | Retry ordering: `cost_first` (default), `speed_first`, `balanced`, or `stealth_first`. |
| `request_delay` | Fixed delay in seconds between requests (default 0). |

**Two modes.** Leave `cookie` blank for **anonymous** scraping — you get the public subset LinkedIn serves logged-out (name, headline, current roles, education, location, photo), no login and no geo constraint. Supply a `li_at` cookie for the **full** authenticated profile (skills, connection/follower counts, contact info, every section). To get the cookie: sign into LinkedIn in your normal browser, open DevTools (`F12` / `Cmd+Opt+I`), go to **Application → Storage → Cookies → https://www.linkedin.com**, copy the **Value** of the `li_at` row, and paste it into the `cookie` field. Cookies typically last about a year when used from the same country — note your sign-in country and set `proxy_country` to match.

### LinkedIn profile data output

Each profile is one dataset row. Sample:

```json
{
  "public_identifier": "alice-walker-1234",
  "status": "ok",
  "profile_url": "https://www.linkedin.com/in/alice-walker-1234/",
  "name": "Alice Walker",
  "headline": "VP Engineering at TechCo",
  "location": "Boston, MA",
  "industry": "Software",
  "about": "Builder of teams and systems...",
  "connection_count_numeric": 1234,
  "follower_count": 56789,
  "open_to_work": false,
  "premium": true,
  "current_company": "TechCo",
  "current_title": "VP Engineering",
  "experience": [
    {"company": "TechCo", "title": "VP Engineering", "location": "Boston, MA", "start_date": "Mar 2022", "end_date": "Present", "description": "..."}
  ],
  "education": [
    {"school": "Stanford", "degree": "MS", "field_of_study": "Computer Science", "start_year": "2014", "end_year": "2016"}
  ],
  "skills": ["Python", "Distributed Systems", "Leadership"],
  "contact": {
    "email": "alice@techco.com",
    "phones": [{"number": "+1-555-0100", "type": "MOBILE"}],
    "websites": [{"url": "https://alice.dev/", "category": "PERSONAL"}],
    "twitter": ["alicewalker"]
  },
  "scraped_at": "2026-07-08T12:00:00+00:00"
}
```

| Field | Description |
|---|---|
| `public_identifier`, `profile_url` | LinkedIn vanity slug (stable across name changes) + source URL, for joining back to your input. |
| `status`, `error` | `ok` / `blocked` / `not_found` / `failed`, with a reason when not ok. |
| `name`, `headline`, `about`, `location`, `industry`, `profile_photo_url` | Core profile fields. |
| `current_company`, `current_title` | Current role, flattened for CSV. |
| `connection_count_numeric`, `follower_count` | Exact numeric counts (cookie path). |
| `open_to_work`, `premium`, `verified`, `influencer` | Profile badges. |
| `experience`, `education`, `certifications`, `skills`, `skill_endorsements` | Structured career sections. |
| `languages`, `volunteer`, `honors`, `publications`, `patents`, `projects`, `courses`, `organizations`, `test_scores` | Additional sections, populated when the person added them. |
| `contact` | Email, phones, websites, twitter, IM — only when `scrape_contact_info` is enabled. |
| `scraped_at` | ISO timestamp. |

By default only successfully-scraped profiles reach the dataset. A profile that is blocked, private, or missing fails fast with a specific reason rather than a silent empty row.

### How much it costs

This actor uses **pay-per-event** pricing — you pay for what you scrape, not for time.

| Event | USD |
|---|---|
| Actor start (per run) | $0.01 |
| Profile scraped | $0.005 |
| Contact info scraped (only when data returned) | $0.005 |

| Typical run | Cost |
|---|---|
| 1,000 profiles | ~$5 |
| 1,000 profiles + contact enrichment | ~$10 |
| 100 profiles | ~$0.50 |

You are never billed for a profile that comes back `blocked`, `not_found`, or `failed`, and contact enrichment is only charged when contact data is actually returned.

### Recommended proxies for LinkedIn

When you supply a cookie, LinkedIn ties session validity to IP geography — a `li_at` issued in one country is deauthorized within a request or two if the proxy exits in a different country. **Use a residential proxy whose exit country matches where you signed in** and set `proxy_country` accordingly (`US`, `GB`, `VN`, `DE`, `JP`, ...). Anonymous (no-cookie) runs still need a residential IP to avoid blocks, but the country is unconstrained.

This actor runs on **[DataImpulse](https://dataimpulse.com/?aff=404588\&utm_source=apify) residential IPs** — pay-as-you-go, per-country targeting, no monthly minimum — so the exit IP can be aligned to your cookie's origin country. If you run your own scrapers (inside or outside Apify) and need reliable residential proxies for LinkedIn or other sites, you can get DataImpulse here:

👉 **[Get DataImpulse residential proxies](https://dataimpulse.com/?aff=404588\&utm_source=apify)** (referral link)

### Why this LinkedIn profile scraper

- **Works with or without a cookie** — anonymous mode returns the public subset (name, headline, current roles, education, location) with no login; add a `li_at` cookie for the full Voyager API profile.
- **Full Voyager API data** — with a cookie, 25+ structured fields per profile, deeper than public-HTML scrapers that only see truncated counts and shallow sections.
- **One request per profile** — every field returns in a single authenticated call; no extra charge for more fields.
- **Adaptive billing** — you pay only when a profile is delivered; blocked, private, and not-found inputs are free.
- **Actionable failures** — a run that can't fetch names the cause directly (invalid cookie, geo mismatch, rate limit, anti-bot block) instead of a vague error.
- **Open source** — the underlying `linkedin-scraper` Python package ships a Typer CLI and a FastAPI server; the Apify wrapper is a thin layer, so you can inspect the parser.

### FAQ

**Is login required?** No. Leave `cookie` blank for anonymous mode — you get the public subset (name, headline, current roles, education, location, photo). A cookie is only needed for the full authenticated profile (skills, connection/follower counts, contact info). To get it: sign into LinkedIn in your browser, open DevTools → **Application** → **Cookies** → `linkedin.com`, and copy the `li_at` value into the `cookie` field. It typically stays valid about a year when used from the same country.

**Why must the proxy country match my cookie?** LinkedIn binds session validity to IP geography. A cookie generated in Vietnam used through a US IP is treated as a hijacked session and deauthorized within one or two requests. Set `proxy_country` to your sign-in country and the exit IP is aligned automatically.

**Which proxies work best for LinkedIn?** Residential proxies with per-country targeting. This actor runs on [DataImpulse](https://dataimpulse.com/?aff=404588\&utm_source=apify) residential IPs so the exit can match your cookie's origin country. Datacenter proxies get flagged quickly.

**Will my cookie get my account banned?** Stay under the default rate limits (`max_requests_per_minute: 30`, `max_concurrency: 5`) for sustainable use. LinkedIn flags accounts that pull thousands of profiles per hour, so scrape at a human pace.

**Will every field populate on every profile?** No — it depends on what the person filled in and their privacy settings. Core fields (name, headline, experience, education) almost always populate; skills, honors, projects, and others appear only when the profile owner added them.

**Is scraping LinkedIn legal?** This actor collects only data visible to your own logged-in account. You are responsible for complying with LinkedIn's terms and applicable data-protection laws, and for having a lawful basis before collecting personal data.

### Rate this actor ⭐

If the LinkedIn Profile Scraper saved you time, please **leave a review on its Apify Store page** — ratings help other people find it and tell us what to build next. Hit a bug or missing field? Open an issue or contact us through the actor's **Issues** tab and we'll fix it fast — recency and reliability are what keep this actor ranking.

### Related actors

Building a full data pipeline? Pair this actor with our other scrapers — same proxy config format, same Pydantic-validated output, all open source.

- **[LinkedIn Jobs Scraper](https://apify.com/herus13/linkedin-jobs-scraper)** — scrape LinkedIn job listings with company enrichment, salary, and recruiter info. No login required.
- **[Google Maps Business & Contact Scraper](https://apify.com/herus13/google-maps-scraper)** — scrape Google Maps businesses with emails, phone numbers, reviews, images, and social links.
- **[Indeed Scraper](https://apify.com/herus13/indeed-scraper)** — scrape Indeed job listings with company, salary, and location details.
- **[TikTok Shop Product Scraper](https://apify.com/herus13/tiktok-shop-scraper)** — scrape TikTok Shop products across 10 regions with prices, sellers, and ratings.

# Actor input Schema

## `profile_urls` (type: `array`):

List of LinkedIn profile URLs to scrape (e.g. https://www.linkedin.com/in/username)

## `cookie` (type: `string`):

<strong>Optional.</strong> With a cookie you get the full profile (skills, connection/follower counts, every section) via the authenticated API. <strong>Leave it blank</strong> to scrape the public subset LinkedIn serves logged-out (name, headline, current roles, education, location, photo) — no login needed. Find your cookie: DevTools → <strong>Application</strong> → <strong>Cookies</strong> → <code>linkedin.com</code> → <code>li\_at</code>. Generate it from the same country you select below.

## `authorized_access` (type: `boolean`):

Confirms you are scraping a profile you own or have explicit permission to access via your own li\_at cookie. Required.

## `scrape_contact_info` (type: `boolean`):

Fetches the profileContactInfo endpoint per profile. Returns email, phone, websites, twitter handles, IM contacts. Only charged when data is returned.

## `proxy_country` (type: `string`):

Residential proxy country code. <strong>Must match the country where you generated your cookie</strong> (e.g. if you logged in from Vietnam, use VN). Mismatched geo triggers LinkedIn session invalidation.

## `max_concurrency` (type: `integer`):

Maximum concurrent requests

## `max_requests_per_minute` (type: `integer`):

Rate limit for requests

## `transport` (type: `string`):

<p>HTTP engine for the public profile fetch. <b>Auto</b> uses <code>curl_cffi</code> (TLS impersonation). The authenticated cookie path uses a browser session regardless.</p>
## `strategy_mode` (type: `string`):

How the engine orders retry attempts. <code>cost\_first</code> (default) favors the cheapest working path.

## `request_delay` (type: `integer`):

Fixed delay inserted between requests. 0 = no added delay.

## Actor input object example

```json
{
  "profile_urls": [
    "https://www.linkedin.com/in/williamhgates/"
  ],
  "authorized_access": false,
  "scrape_contact_info": false,
  "proxy_country": "VN",
  "max_concurrency": 5,
  "max_requests_per_minute": 30,
  "transport": "auto",
  "strategy_mode": "cost_first",
  "request_delay": 0
}
```

# Actor output Schema

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

One row per requested profile URL — including failures, which carry status and error so every input can be joined back via public\_identifier and request\_id. Each row has core identity (name, headline, location, about, industry, profile photo), current company/title, and structured sections (experience, education, certifications, skills, languages, honors, publications, patents, projects, courses, organizations, test scores). Numeric connection/follower counts, the open\_to\_work / premium / verified / influencer badges, and the contact object (email, phone, websites, birthday) are only populated on the authenticated path — a cookie-less run returns LinkedIn's public HTML, where connection counts ship as bucketed strings like "500+" and contact info is absent. The contact object additionally requires scrape\_contact\_info to be enabled.

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

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

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

```

## MCP server setup

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