# LinkedIn Profile Scraper - Search People, No Cookie Needed (`s-r/linkedin-profile-scraper`) Actor

Find people by what they do and get their public LinkedIn profile: name, headline, location, current employer, follower and connection counts, About text and education. Search by phrase or pass profile URLs. No login and no session cookie of your own.

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

## Pricing

Pay per event

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?

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

Find people by what they do, and get their public LinkedIn profile. No login,
no session cookie of your own, nothing to paste from your browser.

Type the kind of phrase you would use to describe someone, like
`ecommerce manager netherlands`, and get back a table of people: name, role,
current employer, location, follower and connection counts, their About text
and their education.

You can also pass profile URLs you already have, as full links or bare slugs,
and combine both in one run.

### What you get, and the one thing you do not

| Field | Where it comes from |
|---|---|
| `name`, `first_name`, `last_name` | The profile |
| `headline` | **The search index** |
| `current_company` | The profile's own page title |
| `location`, `followers`, `connections` | The profile |
| `about` | The profile |
| `education` | The profile |
| `positions` | The profile: company and location |

**Job titles per position are not available.** LinkedIn ships that field empty
to anonymous visitors, on every position, on every profile tested. So
`positions` tells you where somebody worked and roughly where they were based,
not what they were called there. Dates are withheld the same way.

The row carries `titles_available` so you can see this is a property of the
source rather than a gap in the run. If LinkedIn ever changes it, that flag
goes true and the column fills itself.

**This is why `headline` matters.** The search index kept the person's role
from when their profile was crawlable, so the index knows the role and the live
page knows the employer. One search returned "Edo Voets - E-Commerce Manager"
while the live page for the same person says "Moët Hennessy Nederland BV".
Neither half is complete on its own, which is why both are on the row.

### Searching

**People searches** takes a phrase per line and looks it up in the public
profile index. **Search pages per phrase** decides how deep, at roughly seven
to eleven profiles per page.

Write the phrase the way the person would describe themselves, because that is
what the index matched on. `head of procurement retail germany` works;
`decision maker in supply chain` does not, because nobody writes that on their
profile.

**Country** steers both halves: it picks the index's market and decides where
the profile is read from, and LinkedIn serves the page in that country's
language, so a Dutch profile read through `nl` comes back with Dutch labels.

### Errors

| Code | Meaning |
|---|---|
| `blocked` | The profile could not be read after every attempt |
| `search_failed` | The index could not be searched for that phrase |
| `no_results` | Nothing matched and no URLs were given |
| `bad_input` | Neither a search phrase nor a URL was given |

A profile that was found but not read still appears as a row, with `fetched:
false` and whatever the index knew about it. That is deliberate: the name,
headline and URL are worth keeping even when the page itself refused.

Raise **Attempts per profile** if you see `blocked`. **Only profiles that were
actually read are billed.**

### A note on reliability

Access here is narrow and can change without warning. If a run suddenly returns
`blocked` across the board where it worked last week, that is what has
happened; it is not your search phrase. Check `profilesRead` against
`profilesFound` in the run summary, which is exactly the ratio that tells the
two apart.

### Related actors

`linkedin-jobs-scraper` for job postings, `linkedin-ads-library` for what a
company is advertising, and the company actors for the organisations these
people work at.

# Actor input Schema

## `searches` (type: `array`):

One phrase per line, written the way you would describe the person: "ecommerce manager netherlands". Each becomes a search of the public profile index.

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

Profiles you already have. A full link or a bare slug both work. Combine with searches or use on their own.

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

Stop after this many. Also the cost ceiling for the run.

## `searchPages` (type: `integer`):

How deep to go in the index per search phrase. Each page adds roughly seven to eleven profiles.

## `country` (type: `string`):

Two-letter country code. Steers both the search index and where the profile is read from, and LinkedIn serves the profile in that country's language.

## `language` (type: `string`):

Two-letter language code for the search.

## `concurrency` (type: `integer`):

How many profiles to read at once.

## `attempts` (type: `integer`):

How often to retry a refused profile with a different agent and a fresh exit before giving up on it.

## Actor input object example

```json
{
  "searches": [
    "head of procurement retail germany"
  ],
  "profileUrls": [
    "https://www.linkedin.com/in/williamhgates",
    "satyanadella"
  ],
  "maxProfiles": 50,
  "searchPages": 3,
  "country": "us",
  "language": "nl",
  "concurrency": 3,
  "attempts": 5
}
```

# Actor output Schema

## `profiles` (type: `string`):

One row per person.

## `summary` (type: `string`):

How many were found and read, and how many carried a headline, an About text and an education history.

## `errors` (type: `string`):

Profiles that could not be read.

# 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 = {
    "searches": [
        "ecommerce manager netherlands"
    ],
    "profileUrls": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/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 = {
    "searches": ["ecommerce manager netherlands"],
    "profileUrls": [],
}

# Run the Actor and wait for it to finish
run = client.actor("s-r/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 '{
  "searches": [
    "ecommerce manager netherlands"
  ],
  "profileUrls": []
}' |
apify call s-r/linkedin-profile-scraper --silent --output-dataset

```

## MCP server setup

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