# LinkedIn Company Employees Scraper (`bgfc97/linkedin-company-employees-scraper`) Actor

Scrape employees of a LinkedIn company: name, headline, location, profile URL and photo. Public data with no cookies; full list with your own session.

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

## Pricing

from $3.50 / 1,000 employee scrapeds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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 Company Employees Scraper

Give it a **LinkedIn company** (URL or slug, e.g. `https://www.linkedin.com/company/microsoft/` or just `microsoft`) and get back its **employees** — `name`, `headline`/title, `location`, `profileUrl`, `photoUrl` — plus a **company summary** (name, industry, size, headquarters, website, followers and the **total employee count** on LinkedIn). Perfect for B2B lead-gen, recruiting/sourcing and market mapping.

It reads LinkedIn's **public company page** (the logged-out page Google indexes) with browser-grade HTTP requests (`got-scraping`: real TLS fingerprint + generated headers) routed through **Apify Proxy** — residential IPs first with a fresh session per retry, escalating to the Apify Proxy **Unblocker** group when LinkedIn bot-blocks. No headless browser needed.

### Input

```json
{
  "companyUrls": ["https://www.linkedin.com/company/microsoft/", "stripe"],
  "maxItems": 100,
  "enrichProfiles": false,
  "publicPageFetches": 4,
  "useUnblocker": true,
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
```

- `companyUrls` — one or more company URLs or slugs. **Required.**
- `maxItems` — max employees returned **per company** (the company summary is always returned too).
- `li_at` — **optional** LinkedIn session cookie (**yours**, never anyone else's). Leave empty for public-only scraping. Supplying it returns the **full** employee list (see below). Sent only as a request cookie; never logged or stored.
- `enrichProfiles` — for each public employee, also open their public profile to fill in `headline`/`location`/`photo` (slower, more requests). Useful in public mode where face-pile cards often lack a headline.
- `publicPageFetches` — how many times to re-fetch the company page with fresh proxy sessions to accumulate more publicly-named employees (LinkedIn rotates the guest face-pile). Ignored when `li_at` is set.
- `useUnblocker` — retry via the Apify Unblocker group when bot-blocked (default on).
- `graphqlQueryId` — advanced; override LinkedIn's people-search `queryId` if the authenticated list stops working (only used with `li_at`).
- `proxyConfiguration` — Apify Proxy config; **residential strongly recommended**.
- `timeoutSecs` — per-request timeout (default 45).

### Output

One **company** record per company, then one **employee** record per person:

```json
{ "type": "company", "companyName": "Microsoft", "companyId": "1035",
  "industry": "Software Development", "companySize": "10,001+ employees",
  "headquarters": "Redmond, WA", "website": "https://news.microsoft.com/...",
  "totalEmployeesOnLinkedIn": "231,754", "employeesReturned": 4,
  "employeesAnonymizedPublicly": 2, "authenticated": false, "dataSource": "public-company-page" }

{ "type": "employee", "companyName": "Microsoft",
  "name": "Reid Hoffman", "headline": "Co-Founder, LinkedIn, Manas AI & Inflection AI",
  "location": null, "profileUrl": "https://www.linkedin.com/in/reidhoffman",
  "photoUrl": "https://media.licdn.com/dms/image/...", "dataSource": "public-company-page" }
```

### Public vs. authenticated — read this before you run it

LinkedIn **does not let logged-out visitors browse a company's employee list.** The `/company/<x>/people/` tab redirects straight to a login wall. The public company page shows a small **"Employees at X"** face-pile, but LinkedIn **anonymizes most of it to "LinkedIn Member"** (no name, no profile link) for guests. Only employees with a fully public profile (executives, LinkedIn "influencers", public creators) come through **named** — typically **just a handful per company** (e.g. Microsoft returns ~4 named public employees), regardless of how many `publicPageFetches` you run. That is the exact public ceiling — not a bug in this actor, but how LinkedIn gates the data.

To get the **full** employee list (hundreds/thousands, with headline + location for each), supply **your own** `li_at` session cookie. The actor then resolves the company id and pulls employees through LinkedIn's internal people-search API, paginating up to `maxItems`.

**How to get your `li_at`:** log into LinkedIn in your browser → DevTools → Application → Cookies → `www.linkedin.com` → copy the `li_at` value. Use **only your own** cookie. This internal API is undocumented and LinkedIn changes it periodically; if the authenticated list ever returns nothing, paste a fresh `voyagerSearchDashClusters` `queryId` into `graphqlQueryId`.

### Honest limitations

- **Public mode returns only publicly-named employees (a handful).** Everyone else is anonymized by LinkedIn to "LinkedIn Member" and cannot be returned without login. `employeesAnonymizedPublicly` reports how many guests are shown as hidden.
- **`location` is usually empty in public mode** (face-pile cards omit it). Turn on `enrichProfiles` to backfill it from each public profile, or use `li_at`.
- **The authenticated path uses your own session and LinkedIn's private API**, which LinkedIn may change; it is provided as best-effort and requires a valid `li_at`.
- LinkedIn is one of the most aggressively defended sites on the web. Use residential proxies + Unblocker.
- Use responsibly and in line with LinkedIn's terms and applicable law. Only scrape data you are permitted to access, and only with a cookie you own.

# Actor input Schema

## `companyUrls` (type: `array`):

One or more LinkedIn company pages, as full URLs (e.g. https://www.linkedin.com/company/microsoft/) or bare slugs (e.g. microsoft). For each company the actor returns its employees plus a company summary. People-profile or job URLs are not supported here.

## `maxItems` (type: `integer`):

Maximum number of employee records to return per company. The company summary record is always returned in addition to this. Set high to get everything available.

## `li_at` (type: `string`):

OPTIONAL. Your OWN LinkedIn li_at session cookie. Leave empty to scrape only the public company page (returns company metadata, total employee count and the small set of employees LinkedIn shows publicly — most are anonymized to 'LinkedIn Member' for logged-out visitors). Provide your li_at to pull the FULL employee list through LinkedIn's internal API. Use ONLY a cookie you own and are permitted to use — never someone else's credentials. It is sent only as a request cookie and is never logged or stored.

## `enrichProfiles` (type: `boolean`):

For each employee found, also fetch their public LinkedIn profile page to fill in headline, location and photo when the company-page card does not include them. Slower and costs more requests, but produces richer records. Recommended when you need headline/location for public-mode results.

## `publicPageFetches` (type: `integer`):

How many times to re-fetch the public company page with a fresh proxy session to accumulate distinct publicly-named employees (LinkedIn rotates which employees it shows to guests). Higher = a few more names but more requests. Ignored when a li_at cookie is supplied. Typically yields only a handful of named employees regardless (see the README limitations).

## `useUnblocker` (type: `boolean`):

When residential-proxy attempts get bot-blocked (HTTP 999 / challenge), retry the same page through the Apify Proxy UNBLOCKER group, which defeats heavier anti-bot protection (may cost more per request). Recommended on. Note: the Unblocker defeats bot detection, not the login wall — pages that require login still need a li_at cookie.

## `graphqlQueryId` (type: `string`):

ADVANCED. Only used when a li_at cookie is provided. LinkedIn's internal people-search GraphQL endpoint is identified by a versioned queryId that LinkedIn changes when it deploys. A current default is built in; if the authenticated employee list stops working, paste the latest voyagerSearchDashClusters queryId here (find it in your browser's Network tab on a LinkedIn people search). Leave empty to use the default.

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

Apify Proxy settings used for the first attempts, with a fresh proxy session on every retry. Residential proxies are strongly recommended — LinkedIn aggressively bot-blocks datacenter IPs. If blocked, the actor can additionally escalate to the Unblocker group (see the option above).

## `timeoutSecs` (type: `integer`):

Timeout per HTTP request to LinkedIn, in seconds (5-90).

## Actor input object example

```json
{
  "companyUrls": [
    "https://www.linkedin.com/company/microsoft/"
  ],
  "maxItems": 100,
  "enrichProfiles": false,
  "publicPageFetches": 4,
  "useUnblocker": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "timeoutSecs": 45
}
```

# Actor output Schema

# 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 = {
    "companyUrls": [
        "https://www.linkedin.com/company/microsoft/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("bgfc97/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 = { "companyUrls": ["https://www.linkedin.com/company/microsoft/"] }

# Run the Actor and wait for it to finish
run = client.actor("bgfc97/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 '{
  "companyUrls": [
    "https://www.linkedin.com/company/microsoft/"
  ]
}' |
apify call bgfc97/linkedin-company-employees-scraper --silent --output-dataset

```

## MCP server setup

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