# Company Employees Scraper for LinkedIn - No Cookies (`scrapesage/linkedin-company-employees-scraper`) Actor

Find the people who work at any company on LinkedIn without a login or cookies. Filter by role keywords to get just the decision makers, and every person is checked against the company before it is returned, so namesakes and ex-staff are dropped.

- **URL**: https://apify.com/scrapesage/linkedin-company-employees-scraper.md
- **Developed by:** [Scrape Sage](https://apify.com/scrapesage) (community)
- **Categories:** Lead generation, Social media, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$5.00 / 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

## Company Employees Scraper for LinkedIn - No Cookies

**Give it companies, get the people who work there.** No login, no cookies, no session tokens - and every person is checked against the company before you are charged for them, so namesakes and ex-staff do not end up in your list.

Point it at `https://www.linkedin.com/company/stripe`, a bare slug (`stripe`) or just a company name, and get back a verified employee list: name, job title where LinkedIn publishes it, seniority, department, location, profile URL, and the company's own firmographics on every row.

### What makes this different

- **Every row is verified.** A plain web search for a company name returns namesakes (there is a real person called "Alain Vercel") and people who merely mention the company. This actor opens each candidate's public profile and confirms the company is actually their employer before emitting the row. Unverified candidates are dropped by default, and each row tells you exactly how it was confirmed via `verificationSource`.
- **Find the decision makers, not just a headcount dump.** Pass `roleKeywords` like `Head of Marketing`, `Account Executive` or `VP Engineering` and it searches those roles across every company you gave it - the "find me the VP of Sales at these 40 accounts" job, in one run.
- **No cookies, no login, no LinkedIn account.** Nothing to configure, nothing to get banned.
- **Company firmographics included free.** Industry, employee headcount, website, HQ and LinkedIn company id ride along on every row, so the output drops straight into a CRM.

### Input

| Field | Type | What it does |
|---|---|---|
| `companies` | array | Company LinkedIn URLs, slugs, or plain names. |
| `roleKeywords` | array | Only find people matching these role phrases. Each is searched separately across every company. |
| `useRoleBuckets` | boolean | When no role keywords are given, also search CEO / Founder / VP / Head of / Director / Manager. Default on. |
| `locationKeyword` | string | Extra filter phrase, e.g. `London`. |
| `maxEmployeesPerCompany` | integer | Cap per company, so one big company cannot eat the run. Default 25. |
| `maxResults` | integer | Total cap for the run. 0 = no limit. Default 100. |
| `verifyEmployment` | boolean | Open each profile and confirm the employer. Default on - turning it off is cheaper but returns unchecked matches. |
| `includeUnverified` | boolean | Also return candidates that could not be confirmed, flagged `employmentVerified: false`. Default off. |
| `searchPages` | integer | How deep to page each search. Default 2. |
| `maxConcurrency` | integer | Profiles checked in parallel. Default 6. |

### Output

One row per person. Company context is flat on every row, so a CSV export needs no joining.

```json
{
  "type": "employee",
  "fullName": "Paul Copplestone",
  "firstName": "Paul",
  "lastName": "Copplestone",
  "jobTitle": "CEO",
  "seniorityLevel": "Owner/C-Level",
  "department": "Executive",
  "headline": "CEO @ supabase.com",
  "profileUrl": "https://www.linkedin.com/in/paulcopplestone",
  "publicId": "paulcopplestone",
  "locationName": "United States",
  "city": "United States",
  "country": "United States",
  "profilePhotoUrl": "https://media.licdn.com/...",
  "followerCount": 21458,
  "connectionCountText": "500+",
  "education": "University of Auckland",
  "companyName": "Supabase",
  "companyUniversalName": "supabase",
  "companyId": 68979500,
  "companyLinkedinUrl": "https://www.linkedin.com/company/supabase",
  "companyIndustry": "Software Development",
  "companyHeadcount": 411,
  "companyWebsite": "https://supabase.com",
  "companyHqLocation": "San Francisco, California",
  "employmentVerified": true,
  "verificationSource": "profile-worksfor-url",
  "verificationConfidence": "high",
  "publicProfileAvailable": true,
  "discoverySource": "web-search",
  "leadScore": 79,
  "scrapedAt": "2026-08-07T02:31:00.000Z"
}
```

### Getting the most complete results

**Use `roleKeywords`.** It is the single biggest lever on data quality, and here is exactly why.

LinkedIn only publishes a member's job title to logged-out visitors when that member's headline is public. A role-targeted search finds precisely those people, so the rows come back with titles filled in. Measured on this actor's own runs:

| How you run it | Rows with a job title |
|---|---|
| `roleKeywords: ["VP", "Head of", "Director"]` on Stripe | **20 of 25 (80%)** |
| Broad company search, role buckets on (the default) | ~65% |
| Broad company search, role buckets off | ~17% |

So: name the roles you actually want, or leave **`useRoleBuckets`** on and it will sweep CEO / Founder / VP / Head of / Director / Manager for you. Every row still arrives verified either way - the difference is how many of them can show you a title.

### What LinkedIn does not publish to logged-out visitors

Measured, not assumed - so you know the shape of the data before you buy.

- **Job titles are not universal.** For members whose headline is private, LinkedIn returns the title as an asterisk mask (`"*** * **********"`). This actor emits an honest `null` instead of shipping you asterisks, and it will never put the company name in the title field to pad the column. A crawler user-agent does not unlock it either - that was tested across five (Chrome, Googlebot, Googlebot-mobile, Bingbot, DuckDuckBot).
- **Some members switch their public profile off entirely.** Their profile URL answers HTTP 999 to every logged-out request - permanently, from any country, on any retry. Those people are still returned when the company page or the search index vouches for them, flagged **`publicProfileAvailable: false`**, with location, photo, follower count and education null. That flag is there so you can filter rather than guess.
- **Depth is a targeted list, not a full org chart.** This finds the people publicly indexed for a company, weighted toward decision makers. It does not enumerate all 17,000 employees of a mega-corp. For a specific role across a specific list of accounts, that is exactly what you want.
- **Never returned:** private profiles, connection graphs, personal email addresses and phone numbers. This actor reads only what LinkedIn serves to a logged-out visitor.

### Pricing

Pay-per-event: **$0.005 per verified employee**. Runs that find nobody charge nothing, and every finished run tells you what to change.

### Use with AI assistants (MCP)

This actor works as a tool in any MCP-compatible assistant through the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp) - ask your agent to "find the heads of marketing at these 20 companies" and it can call this actor directly.

### Agent-ready: autonomous payments (x402 & Skyfire)

This actor is **agent-ready** — AI agents can discover it, run it, and **pay for it autonomously**, with no Apify account and no human in the loop. It uses [pay-per-event](https://docs.apify.com/platform/actors/publishing/monetize/pay-per-event) pricing and [limited permissions](https://docs.apify.com/platform/actors/development/permissions), so it qualifies for Apify's agentic-payment standards:

- **[x402](https://docs.apify.com/platform/integrations/x402)** — an open, HTTP-native payment protocol. Agents pay per run in USDC on the Base network directly through the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp) — no account, no API key.
- **[Skyfire](https://docs.apify.com/platform/integrations/skyfire)** — agent-to-service payments for fully autonomous AI-agent workflows.

Building an AI agent, MCP tool, or autonomous data pipeline? This scraper is ready to plug in and pay as it goes.

### Legal

This actor collects only data that LinkedIn publishes to logged-out visitors. It does not log in, does not use cookies or session tokens, and does not attempt to reach private profiles or connection graphs. Employee names and roles at a company are business contact information, but they still relate to identifiable people - if you are in the EU or UK, you are the data controller for what you do with the output, so make sure you have a lawful basis (usually legitimate interest for B2B prospecting) and honour deletion requests. Do not use this output for spam.

This actor is not affiliated with, endorsed by, or sponsored by LinkedIn Corporation. LinkedIn is a trademark of LinkedIn Corporation.

# Actor input Schema

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

Company LinkedIn URLs (https://www.linkedin.com/company/apify), bare slugs (apify) or plain company names (Apify). URLs and slugs are the most accurate - a plain name is matched against the company page LinkedIn resolves for it.

## `roleKeywords` (type: `array`):

Only look for people whose profile matches these role phrases, e.g. "Head of Marketing", "Account Executive", "VP Engineering". Each phrase is searched separately, so 3 phrases across 10 companies finds those 3 roles at all 10. Leave empty to get a cross-section of the whole company.

## `useRoleBuckets` (type: `boolean`):

When no role keywords are given, additionally search CEO, Founder, VP, Head of, Director and Manager at each company. This finds more decision makers AND returns more job titles, because LinkedIn only publishes a title to logged-out visitors when the member's headline is public - a role-targeted search matches exactly those people. Costs a few extra requests per company.

## `locationKeyword` (type: `string`):

Optional extra filter phrase, e.g. "London" or "Germany". Narrows the search to profiles that mention it. Leave empty for all locations.

## `maxEmployeesPerCompany` (type: `integer`):

How many verified people to return for each company before moving to the next one. Keeps a big company from consuming the whole run.

## `maxResults` (type: `integer`):

Total cap across every company. Set 0 for no limit (explicit opt-in).

## `verifyEmployment` (type: `boolean`):

Open each candidate's public profile and confirm the company actually appears as their employer, then enrich the row with location, photo, education and follower count. Turning this OFF is faster and cheaper but returns unchecked search matches - including people who merely mention the company.

## `includeUnverified` (type: `boolean`):

Also return candidates whose employment could not be confirmed, flagged with employmentVerified = false. Useful when a company is small or rebranded and you would rather filter the rows yourself.

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

How deep to page the web search for each company/role query. More pages find more people but add requests; pagination stops early when it goes dry.

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

How many profiles to check in parallel. Lower is gentler on rate limits and steadier; higher is faster.

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

LinkedIn needs residential proxies for reliable logged-out access. Keep the default (Apify residential) unless you know what you are changing.

## `urlsFromFile` (type: `string`):

Paste a list of URLs (one per line), OR one link to a .txt/.csv file, Google Sheet or Google Drive file containing them. Lets you import many Start URLs at once instead of typing each. Google Sheet/Drive share links are handled automatically.

## Actor input object example

```json
{
  "companies": [
    "https://www.linkedin.com/company/apify"
  ],
  "roleKeywords": [
    "Head of Marketing",
    "VP Engineering"
  ],
  "useRoleBuckets": true,
  "maxEmployeesPerCompany": 25,
  "maxResults": 100,
  "verifyEmployment": true,
  "includeUnverified": false,
  "searchPages": 2,
  "maxConcurrency": 6,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

Every verified employee as a JSON item in the default dataset - name, job title, seniority, department, location, profile URL, verification provenance and company firmographics.

# 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/apify",
        "supabase"
    ],
    "roleKeywords": [],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    },
    "urlsFromFile": ""
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapesage/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/apify",
        "supabase",
    ],
    "roleKeywords": [],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
    "urlsFromFile": "",
}

# Run the Actor and wait for it to finish
run = client.actor("scrapesage/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/apify",
    "supabase"
  ],
  "roleKeywords": [],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "urlsFromFile": ""
}' |
apify call scrapesage/linkedin-company-employees-scraper --silent --output-dataset

```

## MCP server setup

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