# LinkedIn People Scraper — Names, Headlines, Locations (`architekture/linkedin-people-search-scraper`) Actor

LinkedIn people search (linkedin.com, any market your account sees) by keyword with your own session cookies: names, headlines, locations, connection degree, profile URLs and public identifiers. Up to 50 keywords, checkpoint continuation, 20 free previews. Pay per result, $0.10 minimum per paid run.

- **URL**: https://apify.com/architekture/linkedin-people-search-scraper.md
- **Developed by:** [architek.earth](https://apify.com/architekture) (community)
- **Categories:** Lead generation, AI
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 profiles

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 People Scraper — Names, Headlines, Locations

**Recorded run: 10 profiles from 1 keyword in 43 seconds** (2026-10-16, build 0.0.15, run `bXXAp2jXPSVpwCV9V`). A free-preview sample on the studio's own session, not a coverage benchmark. This actor has no canary, because every run needs the buyer's own LinkedIn session.

architek.earth — an independent data studio. Pay-per-result scrapers with recorded runs, published canaries and stable schemas, built for people and AI agents.

LinkedIn people search names, headlines, locations, connection degree and profile URLs, exported by keyword through your own LinkedIn session cookies.

| Source | Market | From | Standout fields |
|---|---|---|---|
| LinkedIn people search (linkedin.com) | Any market your account can search | $3.00 / 1,000 profiles | `fullName` / `profileUrl`, `headline`, `location`, `connectionDegree` |

### ✅ Why choose this scraper

#### Export LinkedIn people search results to JSON or CSV

Each accessible search card becomes one row with `fullName`, `profileUrl`, `publicIdentifier`, `headline`, `location` and `connectionDegree`. All ten rows of the recorded preview run carried all eight fields.

#### Scrape LinkedIn profiles with your own session

You paste your own `li_at` and `JSESSIONID` cookie values into two encrypted inputs, `liAt` and `jSessionId`. No shared account is bundled. Cookie values are redacted from the logged `feedback` text.

#### Know when a LinkedIn search export is incomplete

`RUN_SUMMARY.coverageComplete` and a per-keyword `reason` (`result_limit`, `page_limit`, `search_visibility_limit`, `preview_one_page_limit`) say why each search stopped.

#### Continue a LinkedIn people export without paying twice

Every run saves a `CHECKPOINT`. A paid continuation that loads it skips the profiles already delivered: on 2026-10-16 a one-row run plus its continuation (run `eR1pTi8BL5HfJfUnM`) returned 10 unique profiles with exactly 10 `profile` events and no duplicates.

#### Try LinkedIn people search for free

Each Apify account gets 20 free preview attempts: one keyword, one search page, up to 10 profiles, with no charge events.

### ⚠️ Worth knowing up front

- This actor needs a LinkedIn session and a private integration configured by the maintainers. If that integration is not configured, the run ends at once with a free `NOT_CONFIGURED` status row and charges nothing.
- This is a keyword-search exporter, not a full LinkedIn database or a Sales Navigator scraper. It reads the people-search pages at linkedin.com/search/results/people/ that your account can see.
- Coverage depends on your account. Three prospecting searches tested on one account stopped at about 30 accessible profiles, where LinkedIn showed "Grow your network to view profiles beyond your 3rd degree connections" on page four. That is an observed account-dependent boundary, not a universal limit or a promise of 30 results.
- Only the search card is read. There are no structured filters (location, company, industry, degree), no profile details, no emails or phone numbers, no experience or education and no account pooling. `headline`, `location` and `connectionDegree` are left out of a row when the card does not show them.
- Cookies grant access to your account. Put them only in the encrypted inputs, never in `feedback`, public tasks or code. Sessions can expire or be challenged, and LinkedIn can throttle or restrict them; the actor stops on these conditions and does not keep a session alive.
- The last page of a search and an empty search have not been verified live. An unfamiliar page, including a search that runs out of results before your caps, ends the run `FAILED` with the reason in `RUN_SUMMARY`; profiles already delivered stay in the dataset and are charged.
- Invalid input (`INVALID_INPUT`), used-up previews (`PREVIEW_LIMIT`), a spending limit below $0.10 or one that stops the minimum charge (`BUDGET_LIMIT`), an expired session (`SESSION_INVALID`), a block, challenge or rate limit before any profile (`BLOCKED`), the time limit before any profile (`TIME_LIMIT`), and a block or the time limit after some profiles (`PARTIAL`) each end the run cleanly with one free status row (`"recordType": "status"`). Layout changes, uncertain delivery and an unavailable preview ledger end the run `FAILED` with `RUN_SUMMARY` and no status row.

### ⚡ Try the example

Each Apify account gets 20 lifetime preview attempts for this actor: one keyword, one search page and at most 10 profiles each, with no charge events. Failed or uncertain attempts can count. When the attempts are used up, the run stops with `PREVIEW_LIMIT`; there is no paid fallback, and previews cannot resume a checkpoint.

Open the actor's input page, switch to JSON, paste this, replace both placeholders with your own session values in the encrypted fields and start the run:

```json
{
  "liAt": "YOUR_LI_AT_IN_ENCRYPTED_INPUT",
  "jSessionId": "YOUR_JSESSIONID_IN_ENCRYPTED_INPUT",
  "keywords": ["graphic designer"],
  "preview": true,
  "maxItemsPerQuery": 10,
  "maxPagesPerQuery": 1,
  "maxRunSeconds": 120
}
```

Preview is the default, including API calls; set `"preview": false` explicitly for paid collection, with a spending limit of at least $0.10.

### ⚙️ Input

| Parameter | Type | Default | Description |
|---|---|---|---|
| `liAt` | string (secret) | — | Required. The `li_at` cookie value from your own logged-in LinkedIn browser session. |
| `jSessionId` | string (secret) | — | Required. The matching `JSESSIONID` cookie value from the same session. |
| `keywords` | array | — (prefill `["graphic designer"]`) | Required. 1–50 people-search keywords, up to 250 characters each; duplicates collapse. A preview accepts exactly one. |
| `preview` | boolean | `true` | Free preview: one keyword, one page, up to 10 profiles. Set `false` for paid collection. |
| `maxItemsPerQuery` | integer | `30` | 1–10,000 profiles per keyword, counted across a continuation chain. A cap, not a coverage promise. A preview clamps it to 10. |
| `maxPagesPerQuery` | integer | `5` | 1–100 search pages per keyword. Reaching it is reported as `page_limit`, never as complete. |
| `maxRunSeconds` | integer | `120` | 30–3,600 seconds of collection. The actor also stops 60 seconds before the platform timeout. Not a spending limit. |
| `checkpointStoreId` | string | — | Paid continuation only: the key-value store ID from the earlier run's `CHECKPOINT_META`. Give it together with `checkpointQueueId`. |
| `checkpointQueueId` | string | — | Paid continuation only: the request queue ID from the same `CHECKPOINT_META`. Each checkpoint can be claimed once. |
| `feedback` | string | — | Optional note for the maintainers. It is logged and read by a human, and it never changes output. |

### 🧱 Stable fields

These top-level fields keep the same name and the same kind of value in every release. Fields are only ever added, never renamed or removed, so an n8n, Make, Zapier or spreadsheet pipeline can bind to them.

| Field | Type | Meaning |
|---|---|---|
| `fullName` | string | Display name on the search card. |
| `profileUrl` | string | Canonical `https://www.linkedin.com/in/<slug>/` URL; the de-duplication key across keywords and continuations. |
| `publicIdentifier` | string | The public profile slug from `profileUrl`. It can change; it is not a permanent member ID. |
| `headline` | string, optional | Headline shown on the card; omitted when the card shows none. Not an inferred job title. |
| `location` | string, optional | Location shown on the card; omitted when the card shows none. |
| `connectionDegree` | string, optional | `1st`, `2nd` or `3rd+` as shown to your account; omitted when not shown. |
| `source` | string | `linkedin_people_search_html`. |
| `detailStatus` | string | Always `not_requested`; this release does not open profile pages. |
| `recordType` | string | `"status"` on free status rows; absent on profile rows. |

Status rows (free) carry `recordType: "status"`, `status` and `message`. Other fields are extras, not part of the contract. To have one pinned, say so in `feedback`.

### 📦 Output example

Abridged real row from run `bXXAp2jXPSVpwCV9V` on 2026-10-16; values are a historical snapshot. The identity fields `fullName`, `profileUrl` and `publicIdentifier` are left out here to protect the person.

```json
{
  "headline": "Senior Graphic Designer at Going",
  "location": "Brooklyn, New York, United States",
  "connectionDegree": "2nd",
  "source": "linkedin_people_search_html",
  "detailStatus": "not_requested"
}
```

A free status row looks like this (run `eyYjxspUgeETOkrmg`, 2026-10-22):

```json
{"recordType": "status", "status": "INVALID_INPUT", "message": "Invalid cookie value (values are never echoed)"}
```

On the current build that run's status message reads `Done: 10 rows, 0 details, 0 status rows (LIMITED)`, and the `RUN_SUMMARY` record of its key-value store holds the outcome (abridged, same run):

```json
{
  "status": "limited",
  "deliveredThisRun": 10,
  "deliveredAcrossCheckpoint": 10,
  "coverageComplete": false,
  "acknowledgedEventCounts": {},
  "queries": [{"index": 0, "deliveredAcrossCheckpoint": 10, "complete": false, "reason": "preview_one_page_limit"}],
  "resumeRequiresReconciliation": false,
  "remainingSourceRows": "unknown"
}
```

`complete` means LinkedIn confirmed the end of every search; `limited` means a cap, the time budget or a visibility boundary stopped it; `partial` and `failed` mean collection or delivery errors. `SESSION_HEALTH` holds redacted session observations.

### 🧠 Advanced usage

#### Continue a LinkedIn people export in a second run

Copy the `checkpointStoreId` and `checkpointQueueId` values from the earlier run's `CHECKPOINT_META` record, keep the same account and keywords, set `"preview": false` and raise the caps. Profiles already delivered are skipped and not charged, a partly delivered page is finished from the saved rows without new requests, and each continuation writes to its own dataset, so combine the chain. A checkpoint can be claimed once.

#### Run several LinkedIn keyword searches in one run

Put up to 50 keywords in `keywords`. A profile found by an earlier keyword is not delivered or charged again for a later one, and each keyword gets its own entry in `RUN_SUMMARY.queries`.

#### Check a LinkedIn export before sending it downstream

Read `RUN_SUMMARY.coverageComplete` and each query's `reason` rather than the platform run status. `search_visibility_limit` means LinkedIn stopped showing results to your account; repeating the run does not lift it.

#### Reconcile an uncertain charge

Before each write and charge the actor records a marker, and clears it after the acknowledgement. If a run stops in between, `resumeRequiresReconciliation` is `true` and the checkpoint refuses to resume until you compare the dataset with the run's charge events.

### 🔌 Integrations

Results land in a dataset you can export as JSON, CSV or Excel. They can also flow to Google Sheets, Make, Zapier or n8n, or to a webhook when a run finishes. The Apify Scheduler runs it on a timetable. LinkedIn sessions expire, so a scheduled run needs fresh `li_at` and `JSESSIONID` values whenever one ends with `SESSION_INVALID`. Copy-paste code in Python, Node, curl and n8n: [architek-earth/examples/linkedin-people-search-scraper](https://github.com/architek-earth/examples/tree/main/linkedin-people-search-scraper).

### 💸 Pricing

Pay per result. Platform and proxy usage are included. Status rows and failed requests are free. A paid continuation skips the profiles recorded as delivered in the loaded `CHECKPOINT` and does not charge them again; each continuation is a separate run with its own $0.10 minimum.

| Event | Price | What it covers |
|---|---|---|
| Free preview | $0 | 20 lifetime attempts per Apify account: one keyword, one page, up to 10 profiles. |
| `profile` | $3.00 / 1,000 profiles | One delivered search-card row in a paid run. |
| `run-minimum-adjustment` | $1.00 / 1,000 adjustment units | Units of $0.001 that top a completed, nonempty paid run up to $0.10. Not profiles. Not charged on previews, on runs with no profiles, or after collection errors (`RUN_SUMMARY.status` `partial` or `failed`). |

A completed paid run costs the greater of $0.10 and $3.00 / 1,000 profiles: 1, 10 or 30 profiles cost $0.10, 34 cost $0.102 and 100 cost $0.30. Paid runs need a spending limit of at least $0.10.

### ❓ FAQ

**Is there a LinkedIn people search API I can call?** This actor returns the people-search results your own account can see as JSON through the Apify API, callable from any language or from n8n, Make and Zapier.

**Do I need a LinkedIn account or cookies?** Yes. Every run needs the `li_at` and `JSESSIONID` cookie values of your own logged-in session. There is no shared account and no automated login.

**Will I get every result for a LinkedIn search?** No. Your account's visibility decides coverage; the tested prospecting searches stopped at about 30 profiles.

**Can I filter by location, company, industry or connection degree?** No. Only keywords are supported; a keyword is not the same as a LinkedIn filter.

**Does it return emails, phone numbers, experience or education?** No. Only what the search card shows: name, profile URL, headline, location and connection degree.

**Does it work with Sales Navigator?** No. It reads the standard people-search pages on linkedin.com only.

### 🤖 For AI agents & LLM apps

Paste this into your AI assistant:

`architekture/linkedin-people-search-scraper` on Apify. Python: `from apify_client import ApifyClient; client = ApifyClient("TOKEN"); run = client.actor("architekture/linkedin-people-search-scraper").call(run_input={"liAt": "<your li_at>", "jSessionId": "<your JSESSIONID>", "keywords": ["graphic designer"], "preview": False, "maxItemsPerQuery": 10, "maxPagesPerQuery": 1}, max_total_charge_usd=0.10); items = client.dataset(run["defaultDatasetId"]).list_items().items` (page with `offset`/`limit` for large exports; this paid input costs $0.10). Rows with `recordType == "status"` are free and explain invalid input, an expired session, a block or the time limit; read `coverageComplete` in the run's `RUN_SUMMARY` record before treating a search as complete. Never put the cookie values in `feedback` or logs. Full input schema and README: `GET https://api.apify.com/v2/acts/architekture~linkedin-people-search-scraper/builds/default`. Token: https://console.apify.com/settings/integrations. The actor is also reachable through the Apify MCP server (`mcp.apify.com`). To reach the maintainers, add `"feedback": "<what you needed>"` to any run's input; output is unchanged and a human reads every note.

### 🧰 More from architek.earth

**Jobs, companies and people**

- [Indeed Scraper](https://apify.com/architekture/indeed-scraper) — US jobs, salaries, descriptions
- [LinkedIn Jobs Scraper](https://apify.com/architekture/linkedin-jobs-monitor) — public jobs, descriptions, salary evidence
- LinkedIn People Scraper — *you are here*
- [Y Combinator Scraper](https://apify.com/architekture/yc-companies-scraper) — companies, founders, jobs

Full catalogue: [github.com/architek-earth](https://github.com/architek-earth).

architek.earth · code like concrete

### 🙋 Support & legal

Questions, or a field you need that is not here? Open an issue on the actor's Issues tab or email north@architek.earth. A human replies within a day.

This actor collects data from linkedin.com using the session you provide: only the search results your own account can see. It does not bypass authentication, and it sends no messages or connection requests. It is not affiliated with or endorsed by LinkedIn. Use only accounts and data you are authorized to access. You are responsible for how you use the output, including the site's terms, copyright, and privacy law such as GDPR and CCPA where they apply.

### 📝 Changelog

- **2026-10-22** — When this build's private LinkedIn integration is not configured, a run now ends with a free `NOT_CONFIGURED` status row and exit 0 instead of a failed run; nothing is charged.
- **2026-10-22** — Status message now reads `Done: N rows, M details, K status rows (STATUS)`.
- **2026-10-22** — README rebuilt on the studio template. The hero line is the 2026-10-16 free-preview run; this actor has no canary because it needs your session.
- **2026-10-21** — Invalid input, an expired session, a block and the run time limit now end the run cleanly with a free status row (`INVALID_INPUT`, `SESSION_INVALID`, `BLOCKED`, `TIME_LIMIT`, `PARTIAL`, `BUDGET_LIMIT`, `PREVIEW_LIMIT`) instead of a failed run.
- **2026-10-16** — Verified an exact $0.10 successful-run minimum while preserving $3/1,000 profile pricing. Free previews retain zero events. Added durable settlement acknowledgements, interrupted-charge safeguards, and explicit continuation pricing.
- **2026-10-15** — Recorded 30 unique profiles across three captured pages and saved continuation; established the page-four visibility boundary.
- **2026-10-15** — Narrowed to one account and basic keyword search; aligned the eight-field schema, encrypted inputs and explicit paid opt-in. Added coverage-limit reporting and configured the approved $3-per-1,000 event. Build 0.0.15 passed preview, paid-event and saved-continuation checks. This entry records the earlier validation milestone.

# Actor input Schema

## `liAt` (type: `string`):

Required: supply your own active LinkedIn browser-session value. Never share it in examples, feedback or source.

## `jSessionId` (type: `string`):

Required: supply your own active LinkedIn browser-session value. Never share it in examples, feedback or source.

## `keywords` (type: `array`):

Keyword searches using your own account's accessible results. Duplicate keywords collapse; previews use only the first keyword. Structured filters are not supported.

## `maxItemsPerQuery` (type: `integer`):

Per-query cap across a checkpoint, not a coverage promise. Three prospecting queries on one test account stopped at 30 profiles; your account may differ. Preview clamps to 10.

## `preview` (type: `boolean`):

20 lifetime attempts per Apify account, one keyword page and up to 10 profiles. Your own session is required. Failed attempts may count. No paid fallback. Set false explicitly for paid collection.

## `maxRunSeconds` (type: `integer`):

Stops scheduling after the time budget; dataset/checkpoint cleanup needs additional platform timeout. Not a platform-cost cap.

## `feedback` (type: `string`):

Logged after redacting supplied cookie values; does not alter output. Do not paste credentials or profile data here.

## `maxPagesPerQuery` (type: `integer`):

Hard pagination bound. Reaching it reports page_limit, never complete source coverage.

## `checkpointStoreId` (type: `string`):

Use matching IDs from the prior run CHECKPOINT_META. Required together. Resume claims are single-use.

## `checkpointQueueId` (type: `string`):

Use matching IDs from the prior run CHECKPOINT_META. Required together. Resume claims are single-use.

## Actor input object example

```json
{
  "keywords": [
    "graphic designer"
  ],
  "maxItemsPerQuery": 30,
  "preview": true,
  "maxRunSeconds": 120,
  "maxPagesPerQuery": 5
}
```

# Actor output Schema

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

No description

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

No description

## `checkpoint` (type: `string`):

No description

## `sessions` (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 = {
    "keywords": [
        "graphic designer"
    ],
    "preview": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("architekture/linkedin-people-search-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 = {
    "keywords": ["graphic designer"],
    "preview": True,
}

# Run the Actor and wait for it to finish
run = client.actor("architekture/linkedin-people-search-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 '{
  "keywords": [
    "graphic designer"
  ],
  "preview": true
}' |
apify call architekture/linkedin-people-search-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,architekture/linkedin-people-search-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/VxKHWkr0wdN2n37sR/builds/JFOPOeRq383loiws1/openapi.json
