# LinkedIn Profile Scraper - No Cookies, Pay Per Result (`thirdwatch/linkedin-profile-scraper`) Actor

Scrape LinkedIn public profiles without login or cookies. Extracts name, headline, current and past positions, education, about section, follower count, and articles.

- **URL**: https://apify.com/thirdwatch/linkedin-profile-scraper.md
- **Developed by:** [Thirdwatch](https://apify.com/thirdwatch) (community)
- **Categories:** Social media, Lead generation
- **Features:** Limited permissions
- **Stats:** 204 total users, 13 monthly users, 52.8% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $7.50 / 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

> **Thirdwatch portfolio:** 8,800+ users across 140+ public Actors, 2M+ records delivered, >95% run success. [Explore all Thirdwatch Actors](https://apify.com/thirdwatch).

Scrape structured data from public LinkedIn profile URLs and usernames. Get names, headlines, current roles, companies, locations, education, profile summaries, follower counts, profile photos, and recent articles without using a LinkedIn account or cookies.

### Value proposition

LinkedIn profile URLs are common in CRMs, applicant lists, conference exports, Google results, and prospecting workflows, but they are not directly usable as clean structured data. This actor turns public LinkedIn profile URLs into JSON records that can be loaded into a CRM, ATS, enrichment pipeline, spreadsheet, or internal research tool.

Use it when you need a reliable profile-enrichment step for:

- Sales prospecting and SDR research
- RevOps and CRM enrichment
- Recruiting and candidate research
- Founder, executive, or investor research
- Talent movement and market-mapping workflows

### What's new

- **Full profile sections**: set `fullSections: true` to get every section LinkedIn renders publicly — all experience, education, skills, licenses & certifications, volunteering, publications, honors & awards, languages, courses, projects, organizations, recommendations and activity — instead of the standard summary. It costs no extra requests: it parses the page the actor already fetched.
- **Built for bulk**: send up to 1,000 profile URLs in one run. The Actor processes multiple profiles in the same run efficiently, so large batches complete without extra configuration.
- **Per-profile failure isolation**: a profile that cannot be retrieved is skipped without a charge and never aborts the batch. Rows are written as they resolve, so a run that hits its timeout keeps everything already collected.
- **Clear not-found reporting**: when LinkedIn reports that a profile does not exist or is not public, the run lists it in its status message and in the `SUMMARY` record of the run's key-value store instead of failing. No row is written and nothing is charged for it.
- **No-login profile enrichment**: scrape public `/in/{username}` profile pages without cookies or a paid LinkedIn seat.
- **Flexible URL input**: accepts full profile URLs, `/in/...` paths, or plain usernames.

### What data you get

| Field | Description |
| --- | --- |
| `name` | Full name |
| `headline` | Public professional headline |
| `experience` | Positions with `position`, `companyName`, `startDate`, `endDate`, `duration`, `location` when available |
| `education` | Schools with `schoolName`, `degreeName`, `fieldOfStudy`, dates when available |
| `topSkills` | Skills listed on the public profile |
| `about` | Public About or summary section |
| `location` | Public profile location |
| `profile_photo_url` | Profile image URL |
| `followers_count` | Public follower count |
| `profile_url` / `linkedinUrl` | Canonical LinkedIn profile URL |
| `publicIdentifier` | The `/in/{slug}` identifier |
| `articles` | Recent public articles when available |
| `certifications` | `{name, issuer}` for licenses and certifications |
| `languages` | Languages listed on the profile |
| `volunteer_experience` | `{organization, role}` entries |
| `recommendations_count` | Number of public recommendations, when exposed |
| `sections` | Full public sections — see below. `{}` unless `fullSections` is on |
| `dataSource` | How the row was collected. Rows not read from the full public profile page carry `sections: {}` |

#### `fullSections`

With `fullSections: true`, `sections` is keyed by section — `experience`,
`education`, `skills`, `certifications`, `volunteering`, `publications`,
`honors_and_awards`, `languages`, `courses`, `projects`, `organizations`,
`patents`, `recommendations_received`, `articles`, `activity`, `about` — and each
entry is `{title, subtitle, date_range, description, url}` (only the keys that
section actually has). A section LinkedIn adds later still comes through under a
slugified key rather than being silently dropped.

`fullSections` also backfills `topSkills`, `certifications`, `languages`,
`volunteer_experience` and `recommendations_count` when the profile's structured
data left them empty. It only ever fills an empty list — it never rewrites a
value your pipeline already relies on.

Rows built from a search-result summary do not include the full profile page,
so they carry `sections: {}`. Check
`dataSource` on each row if that distinction matters to you.

### Quick-start input examples

#### 1. Enrich one profile URL

```json
{
  "profileUrls": ["https://www.linkedin.com/in/satyanadella/"],
  "maxProfiles": 1
}
```

#### 2. Enrich usernames and profile paths

```json
{
  "profileUrls": ["satyanadella", "/in/williamhgates", "https://www.linkedin.com/in/example/"],
  "maxProfiles": 3
}
```

#### 3. Batch-enrich CRM records

```json
{
  "profileUrls": [
    "https://www.linkedin.com/in/profile-one/",
    "https://www.linkedin.com/in/profile-two/",
    "https://www.linkedin.com/in/profile-three/"
  ],
  "maxProfiles": 500,
  "maxConcurrency": 10
}
```

#### 4. Every public section, in bulk

```json
{
  "profileUrls": ["reidhoffman", "satyanadella", "williamhgates"],
  "maxProfiles": 3,
  "fullSections": true
}
```

### Input parameters

| Parameter | Required | Default | Description |
| --- | --- | --- | --- |
| `profileUrls` | Yes | - | LinkedIn profile URLs, `/in/...` paths, or usernames. Up to 1,000 per run. |
| `maxProfiles` | No | `5` | Maximum number of profiles to process from the input list. |
| `maxConcurrency` | No | `10` | Profiles resolved in parallel; maximum `10`. |
| `fullSections` | No | `false` | Return every public profile section under `sections`, not just the summary. |
| `proxyConfiguration` | No | Proxy fallback | Direct lookup and free search run first. The configured proxy is used only after those paths fail. |
| `linkedinCookies` | No | - | Optional LinkedIn session cookies you provide to access profile data that requires being logged in. Only use cookies from an account you own. |
| `useFallbacks` | No | `true` | Whether to try alternate methods automatically if the primary method doesn't return data. |
| `preferFullProfile` | No | `false` | Try a deeper profile lookup before accepting a partial search result. |
| `usePremiumFallback` | No | `false` | Whether to use a higher-accuracy (potentially costlier) fallback method when the primary method fails. Off by default to avoid surprise costs. |

### Sample output snippet

```json
{
  "name": "Reid Hoffman",
  "headline": "Co-Founder, Executive Board Chair at Manas AI",
  "experience": [
    {
      "position": "Co-Founder, Executive Board Chair",
      "companyName": "Manas AI",
      "startDate": {"year": 2025}
    }
  ],
  "education": [
    {"schoolName": "Stanford University", "degreeName": "BS", "fieldOfStudy": "Symbolic Systems"}
  ],
  "topSkills": ["CEOs", "Founding", "Venture Capital"],
  "about": "Public profile summary text...",
  "location": {"parsed": {"text": "Greater Seattle Area"}},
  "followers_count": 3000000,
  "profile_url": "https://www.linkedin.com/in/reidhoffman/",
  "publicIdentifier": "reidhoffman",
  "dataSource": "linkedin_direct",
  "sections": {
    "experience": [
      {
        "title": "Co-Founder, Executive Board Chair",
        "subtitle": "Manas AI",
        "date_range": "Jan 2025 - Present 1 year 9 months",
        "description": "Manas AI leverages proprietary AI...",
        "url": "https://www.linkedin.com/company/manas-ai"
      }
    ],
    "publications": [
      {"title": "Superagency", "subtitle": "Authors Equity", "date_range": "January 28, 2025"}
    ],
    "honors_and_awards": [
      {"title": "Sigillum Magnum", "subtitle": "University of Bologna", "date_range": "Sep 2023"}
    ],
    "volunteering": [
      {"title": "Chair, Board of Directors", "subtitle": "Opportunity@Work", "date_range": "Jun 2016 - Present"}
    ],
    "skills": [{"title": "CEOs"}, {"title": "Founding"}]
  }
}
```

(`sections` shown here abbreviated; a rich profile returns 11+ sections.)

### Use cases

- **CRM enrichment**: update contact records with current title, company, location, headline, and canonical profile URL.
- **Sales prospecting**: enrich LinkedIn URLs from search exports, conference lists, founder directories, or account research.
- **Recruiting research**: summarize public candidate backgrounds before outreach or screening.
- **Investor research**: profile founders, operators, and executive teams across a portfolio or market segment.
- **Data pipelines**: normalize LinkedIn usernames and URLs into structured fields for downstream workflows.

### Limitations

- Only public profile data is returned. Restricted profiles may return limited or no data.
- Profiles that LinkedIn reports as not existing or not public are listed under `notFound` in the `SUMMARY` key-value record, not in the dataset. A run that resolves no profile at all because LinkedIn returned no profile data is marked as failed, so an empty result is never shown as a success.
- `fullSections` returns what LinkedIn renders publicly. Endorsement counts, connection-gated sections, and anything behind the login wall stay out of reach; a profile that hides a section publicly returns no key for it.
- Sections are unavailable on rows recovered through a search-engine fallback path (check the `dataSource` field), because those paths never load the profile page.
- Some fields are optional because LinkedIn profiles vary by user privacy settings and public visibility.
- The actor does not create LinkedIn sessions, send messages, connect with users, or access private LinkedIn data.

### FAQ

#### Do I need a LinkedIn account or cookies?

No. The actor uses public profile URLs and does not require a logged-in LinkedIn session.

#### What input formats work?

Full URLs, `/in/...` paths, and plain usernames are accepted when they resolve to public LinkedIn profile pages.

#### Can I enrich profiles found through Google or another scraper?

Yes. If the result resolves to a public LinkedIn `/in/{username}` profile, it can be used as input.

#### How many profiles can I scrape in one run?

The actor supports batch input. Use `maxProfiles` to control how many profiles from your input list are processed in a run.

#### Is the data fresh?

Data is pulled at run time from public profile pages, subject to what LinkedIn makes publicly visible.

### Support and custom builds

Need a custom LinkedIn enrichment flow, CRM mapper, webhook integration, or combined company-employee plus profile-enrichment actor? Contact Thirdwatch through Apify or visit [thirdwatch.dev](https://thirdwatch.dev) for custom builds.

Pairs well with [LinkedIn Company Employees Scraper](https://apify.com/thirdwatch/linkedin-company-employees-scraper?fpr=9m2cd6) to find profiles and [LinkedIn Jobs Scraper](https://apify.com/thirdwatch/linkedin-jobs-scraper?fpr=9m2cd6) to connect people data with hiring signals.

### Use cases and recipes

Step-by-step guides on [thirdwatch.dev/blog](https://thirdwatch.dev/blog):

- [Build a Candidate Shortlist from LinkedIn Profiles (2026)](https://thirdwatch.dev/blog/build-candidate-shortlist-from-linkedin-profiles)
- [Enrich Your CRM with LinkedIn Profile Data (2026 Guide)](https://thirdwatch.dev/blog/enrich-crm-with-linkedin-profile-data)
- [Find Decision-Makers by Title and Company on LinkedIn (2026)](https://thirdwatch.dev/blog/find-decision-makers-by-title-and-company)
- [Scrape LinkedIn Profiles Without Login at Scale (2026)](https://thirdwatch.dev/blog/scrape-linkedin-profiles-without-login)

Last verified: 2026-10

# Actor input Schema

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

LinkedIn profile URLs or bare slugs, one per line. Bulk-friendly: a single run handles up to 1000 profiles, and isolates each profile so one blocked or restricted profile never fails the batch.

## `maxProfiles` (type: `integer`):

Maximum number of profiles to scrape. Capped to keep exploratory runs affordable.

## `maxConcurrency` (type: `integer`):

Number of profiles resolved in parallel. Ten minimizes per-profile compute while staying within the tested request limit.

## `fullSections` (type: `boolean`):

Return every section shown on the public profile page — all experience, education, skills, licenses & certifications, volunteering, publications, honors & awards, languages, courses, projects, organizations, recommendations and activity — under a `sections` object, instead of only the summary. Adds no extra requests.

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

Optional proxy settings for the deeper profile lookup. It is used when faster lookups fail, or first when 'Prefer full profile fallback' is on.

## `linkedinCookies` (type: `string`):

Optional. Paste one or more LinkedIn 'li_at' session cookies for authenticated scraping (one cookie per line). When provided, achieves 95%+ reliability on any profile, including obscure/private ones that public scraping can't reach. Get yours from a logged-in LinkedIn session via browser DevTools > Application > Cookies > linkedin.com > li_at. WARNING: only use cookies from accounts you own -- LinkedIn may flag automated activity. Without cookies, the actor still works via public search-engine fallback for ~85% of indexed profiles.

## `useFallbacks` (type: `boolean`):

When direct LinkedIn access is blocked (common in 2026), fall back to extracting public profile data from search engines. Returns partial data (name, headline, company) for ~95% of indexed profiles.

## `preferFullProfile` (type: `boolean`):

When enabled, try a deeper profile lookup before accepting partial search results. This can return richer data but may trigger the extra-cost fallback event.

## `usePremiumFallback` (type: `boolean`):

When all other lookup methods fail, use a premium third-party profile lookup service as a final fallback. It can often retrieve a profile that other methods cannot. Each profile found this way adds a separate charge to your Apify account, on top of this actor's own price. Disabled by default to avoid surprise costs; enable only when you need maximum recall.

## Actor input object example

```json
{
  "profileUrls": [
    "satyanadella"
  ],
  "maxProfiles": 5,
  "maxConcurrency": 10,
  "fullSections": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "useFallbacks": true,
  "preferFullProfile": false,
  "usePremiumFallback": false
}
```

# Actor output Schema

## `results` (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": [
        "satyanadella"
    ],
    "maxProfiles": 5,
    "maxConcurrency": 10,
    "fullSections": false,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("thirdwatch/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": ["satyanadella"],
    "maxProfiles": 5,
    "maxConcurrency": 10,
    "fullSections": False,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("thirdwatch/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": [
    "satyanadella"
  ],
  "maxProfiles": 5,
  "maxConcurrency": 10,
  "fullSections": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call thirdwatch/linkedin-profile-scraper --silent --output-dataset

```

## MCP server setup

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