# LinkedIn Company Employees Scraper - $1.80 per 1,000 (`dami_studio/linkedin-company-employees-scraper`) Actor

Give it a LinkedIn company URL or a plain company name and get the people who work there: full name, headline, current job title, location and public profile URL. No login, no cookies, no API key. $0.0018 per employee - the cheapest LinkedIn company employees scraper on the market.

- **URL**: https://apify.com/dami\_studio/linkedin-company-employees-scraper.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.80 / 1,000 employee founds

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/platform/actors/running/actors-in-store#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 Company Employees Scraper

Give it a LinkedIn company URL or just a company name, get back the people who work there.

For each person you get their full name, their LinkedIn headline, the job title pulled out of that
headline, their location, their public profile URL and their profile slug. No login, no cookies, no
LinkedIn API key, no session token pasted from your browser. Nothing to set up — paste a company and
press start.

At **$0.0018 per employee ($1.80 per 1,000)** this is the cheapest LinkedIn company employees
scraper on the market.

***

### What you actually get

```json
{
  "companyName": "Stripe",
  "companyUrl": "https://www.linkedin.com/company/stripe",
  "fullName": "Patrick Collison",
  "firstName": "Patrick",
  "lastName": "Collison",
  "headline": "Stripe CEO",
  "currentTitle": "CEO",
  "location": null,
  "profileUrl": "https://www.linkedin.com/in/patrickcollison",
  "publicIdentifier": "patrickcollison",
  "currentCompany": "Stripe",
  "education": null,
  "matchStrength": "employer",
  "source": "linkedin-public-profile",
  "retrievedAt": "2026-08-15T12:41:07.884Z"
}
```

Another one, from a run against `https://www.linkedin.com/company/notionhq`:

```json
{
  "companyName": "Notion",
  "fullName": "Ivan Zhao",
  "firstName": "Ivan",
  "lastName": "Zhao",
  "headline": "Founder at Notion",
  "currentTitle": "Founder",
  "location": "San Francisco",
  "profileUrl": "https://www.linkedin.com/in/ivanhzhao",
  "publicIdentifier": "ivanhzhao",
  "currentCompany": "Notion",
  "matchStrength": "employer"
}
```

#### Field reference

| Field | What it is | Ever null? |
|---|---|---|
| `companyName` | The company as LinkedIn spells it. A company URL is resolved to this before searching. | No |
| `companyUrl` | The company URL you gave, normalised. Null if you passed a plain name. | Yes |
| `fullName` | The person's name as LinkedIn publishes it. Some surnames are shortened by LinkedIn itself ("Eric K."). | No |
| `firstName` / `lastName` | `fullName` split on the first space, for mail-merge tools. | `lastName` yes |
| `headline` | The person's LinkedIn headline, verbatim. | No |
| `currentTitle` | The job title extracted from the headline. Null when the headline is just a company name or a slogan. | Yes |
| `location` | City or region, when LinkedIn published one in the profile's indexed description. | Often |
| `profileUrl` | Canonical `https://www.linkedin.com/in/<slug>` URL. De-duplicated across locale domains. | No |
| `publicIdentifier` | The profile slug on its own. | No |
| `currentCompany` | The employer string LinkedIn published, which is usually but not always identical to `companyName`. | Sometimes |
| `education` | School, when LinkedIn published one. | Often |
| `matchStrength` | `"employer"` — LinkedIn's own text names this company as the person's employer. `"mention"` — the company appears in their profile but not in an employer position (only ever returned if you ask for it). | No |
| `source`, `query`, `retrievedAt` | Provenance, so you can audit any row. | No |

***

### How it gets employees without a login

Worth being straight about this, because it explains the limits further down.

LinkedIn's own `/company/<slug>/people/` tab is useless logged out. It answers with about 590 KB of
HTML and **zero** profile links — the employee list is replaced by a sign-in card. Any tool that
claims to read that tab is using somebody's session cookie, which is exactly the thing that gets
accounts restricted.

What LinkedIn *does* publish, deliberately, is every public profile page, written for search
engines. The page title is `<Name> - <Headline> | LinkedIn` and the meta description carries
`Experience: <Company>`, `Education: <School>` and `Location: <Place>`. That text is indexed and
publicly searchable. This Actor searches that public index, restricted to LinkedIn profile pages,
for the company you asked about, and reads the fields straight out of LinkedIn's own published
wording. Every value in a row is text LinkedIn itself put on the open web.

A LinkedIn company URL is resolved to the company's real display name first, from the public company
page. This matters: `linkedin.com/company/anthropicresearch` finds nobody, and "Anthropic" finds the
staff.

Requests go out through rotating datacenter addresses because the search sources rate-limit per
address. There is no residential bandwidth anywhere in this Actor — that is what keeps the price
where it is.

***

### Input

Everything is optional. Run it with empty input and you get one clearly-labelled sample row, free,
so you can see the shape of the output before spending anything.

```json
{
  "companies": [
    "https://www.linkedin.com/company/stripe",
    "https://www.linkedin.com/company/notionhq",
    "Figma"
  ],
  "resultsLimit": 50,
  "jobTitles": ["Engineer", "Recruiter"],
  "locations": ["London"],
  "searchQuery": "",
  "includeMentions": false
}
```

| Option | Meaning |
|---|---|
| `companies` | Up to 20 LinkedIn company URLs or plain company names. Company, school and showcase URLs all work. |
| `resultsLimit` | Hard cap on charged rows for the whole run, 1–500. Default 25. |
| `jobTitles` | Words that must appear in the person's public profile text. People who do not match are dropped and never charged. |
| `locations` | Same, for places. |
| `searchQuery` | Extra free-text terms folded into the public search. |
| `includeMentions` | Default `false`. When off you only get people whose public text names this company as their **employer**. Turn it on to also collect consultants, partners, alumni and commentators. |

There is no proxy setting, and that is on purpose. The Actor always uses its own rotating datacenter
addresses, which are the right tool for per-address rate limits and cost nothing per gigabyte. A
proxy box in the form would only be a way to make a run slower and more expensive.

***

### Pricing

Pay per event. Two events, nothing else:

| Event | Price |
|---|---|
| Actor start | $0.0015 per run |
| `employee-found` | **$0.0018 per employee returned** |

So 100 employees costs $0.18 plus the $0.0015 start. A thousand costs $1.80.

**What is free:**

- the labelled sample row you get from an empty run;
- every diagnostic row (`SEARCH_UNAVAILABLE`, `NO_RESULTS`, `BAD_INPUT`, `COMPANY_NOT_FOUND`,
  `TIME_BUDGET`, `SKIPPED_AFTER_EMPTY`);
- every person dropped by your `jobTitles` / `locations` filters;
- every person dropped because the company was only mentioned, not listed as their employer;
- duplicates — a person found by three different search phrasings is charged once.

You are charged once per row that actually lands in your dataset with a name and a profile URL.
A run that finds nobody costs the start fee and nothing else, and it still finishes as SUCCEEDED
with a row explaining why, rather than failing.

***

### Speed and scale, from real runs

All measured on the Apify platform at 1024 MB, not on a laptop:

| Run | Rows | Search requests | Wall clock |
|---|---|---|---|
| `company/stripe`, limit 60 | 60 | 6 | 24 s |
| `company/stripe`, limit 45 | 45 | 9 | 23 s |
| `company/stripe`, limit 20 | 20 | 3 | 11 s |
| `company/stripe` + `company/notionhq`, limit 12 | 12 | 5 | 16 s |
| a company with nothing indexed | 0 | 3 | 7–13 s |

Roughly 10 people per search request, and up to 30 on a well-indexed company. Large, well-known
employers return 150–200 distinct people before the public index runs dry; small companies return
whatever has been indexed, which can be a handful. A run that finds nobody stops early on purpose
instead of grinding through every phrasing.

***

### What this does NOT do

An honest list, because the alternative is you finding out after you have paid.

- **It is not a complete staff directory.** It returns the employees whose LinkedIn profiles are
  publicly indexed. A 40,000-person company will not give you 40,000 rows — expect the low hundreds
  for big employers, fewer for small ones. If you need every single head, no keyless tool can do
  that.
- **No emails or phone numbers.** LinkedIn does not publish them, so neither does this.
- **`location` and `education` are often null.** They only appear when they were in the profile's
  published description, which varies by profile and by how the text was indexed.
- **`currentTitle` is parsed from the headline**, not from a structured job field, because LinkedIn
  masks job titles for logged-out visitors. When someone writes a slogan instead of a title, the
  title comes back null and the raw `headline` is still there for you.
- **"Currently works there" is a judgement, not a fact.** `matchStrength: "employer"` means
  LinkedIn's own indexed text puts the company in an employer position. Someone who left last week
  and has not updated their headline will still show up. Someone who writes "ex-Stripe" will not.
- **No connection counts, followers, skills, or full work history.** Only what is on the public
  page.
- **Rate limits are real.** Public search sources throttle per address. The Actor rotates addresses
  and falls back across several independent sources, but during a bad minute a run can come back
  short. It tells you that in a free diagnostic row instead of pretending.
- **No account is ever created or used.** Nothing here logs in, and it never will.

***

### FAQ

**Do I need a LinkedIn account, cookie, or session token?**
No. Nothing to paste, nothing to connect. It only reads pages LinkedIn publishes to the open web.

**Will this get my LinkedIn account banned?**
Your account is not involved at any point. There is nothing to ban.

**How many employees will I get for a given company?**
For a large, well-covered employer, typically 150–200 distinct people. For a small company, whatever
is publicly indexed — sometimes a dozen. Set `resultsLimit` to the most you are willing to pay for;
you are only charged for rows you actually receive.

**Can I search by job title, like "only recruiters"?**
Yes. Put the words in `jobTitles`. They are added to the public search and also applied as a filter
on the way out, and anyone filtered out is not charged.

**Can I pass a plain company name instead of a URL?**
Yes. `"Figma"` works. A URL is slightly more precise because the Actor resolves it to LinkedIn's own
spelling of the company first.

**Why do some rows have a null `location`?**
Because LinkedIn did not publish one in that profile's indexed description. It is never invented.

**What is `matchStrength` for?**
It tells you how the person was matched. `"employer"` is the default output and means LinkedIn's own
text names this company as where they work. `"mention"` means the company shows up in their profile
some other way — a consultant, a partner, an alum, somebody writing about the company. Those are
excluded unless you set `includeMentions: true`.

**What happens if the search sources are down?**
You get an uncharged diagnostic row saying so, and the run finishes as SUCCEEDED. You are never
billed per-employee for a run that returned no employees. A run that has not found anybody also
stops early rather than grinding away on your clock — if that happens you will see a
`SEARCH_UNAVAILABLE` or `SKIPPED_AFTER_EMPTY` row, and re-running usually works.

**Does it work for schools and showcase pages?**
Yes — `linkedin.com/school/...` and `linkedin.com/showcase/...` URLs are accepted too.

**Can I run several companies at once?**
Up to 20 per run. `resultsLimit` is the cap across the whole run, not per company, so give it room
if you are doing a batch.

**How do I get more people for one company?**
Raise `resultsLimit`, and add `searchQuery` terms that split the workforce ("engineering", "sales",
"Dublin"). Different phrasings surface different slices of the public index.

***

### Output notes for automation

Rows are pushed as they are found, so you can stream the dataset while the run is still going.
Sample and diagnostic rows are always tagged — filter them out with `_sample != true` and
`_diagnostic != true`, or just check `charged == true`, which is only ever set on rows you paid for.

# Actor input Schema

## `companies` (type: `array`):

LinkedIn company URLs (https://www.linkedin.com/company/stripe) or plain company names. Leave empty to get one free labelled sample row.

## `resultsLimit` (type: `integer`):

Hard cap on charged employee rows for the whole run, across all companies. 1-500.

## `jobTitles` (type: `array`):

Only keep people whose public profile text contains one of these words, e.g. Software Engineer. Filtered-out people are never charged.

## `locations` (type: `array`):

Only keep people whose public profile text contains one of these places, e.g. London. Filtered-out people are never charged.

## `searchQuery` (type: `string`):

Free-text terms added to the public search, e.g. recruiting OR talent.

## `includeMentions` (type: `boolean`):

Off by default. When off, a person is only returned if LinkedIn's own public text names the company as their employer. Turn it on to also get consultants, partners, alumni and anyone whose profile merely mentions the company.

## Actor input object example

```json
{
  "companies": [
    "https://www.linkedin.com/company/stripe"
  ],
  "resultsLimit": 25,
  "jobTitles": [],
  "locations": []
}
```

# Actor output Schema

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

One row per person in the default dataset: companyName, companyUrl, fullName, firstName, lastName, headline, currentTitle, location, profileUrl, publicIdentifier, currentCompany, education, matchStrength. Empty or blocked runs return a single uncharged row instead.

# 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 = {
    "companies": [
        "https://www.linkedin.com/company/stripe"
    ],
    "resultsLimit": 25,
    "jobTitles": [],
    "locations": [],
    "searchQuery": "",
    "includeMentions": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/linkedin-company-employees-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 = {
    "companies": ["https://www.linkedin.com/company/stripe"],
    "resultsLimit": 25,
    "jobTitles": [],
    "locations": [],
    "searchQuery": "",
    "includeMentions": False,
}

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/linkedin-company-employees-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 '{
  "companies": [
    "https://www.linkedin.com/company/stripe"
  ],
  "resultsLimit": 25,
  "jobTitles": [],
  "locations": [],
  "searchQuery": "",
  "includeMentions": false
}' |
apify call dami_studio/linkedin-company-employees-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/linkedin-company-employees-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/nfLQaQLnLdTAJA8dL/builds/UAeAXOOF6IthvYQ5i/openapi.json
