LinkedIn Company Employees API
Get a company employee list from LinkedIn. Give it a company name or a LinkedIn company URL and it returns the people who work there, one row per person, with name, job title, location and public profile URL. By default it opens each person's public profile and keeps only the people who show a current role at the company, so anyone who has moved on is dropped and never charged. Job title keywords and locations narrow the list, and switching the profile check off gives a faster list built from search results alone. It needs no LinkedIn login and no cookie. Expect a partial list: it can only find people whose public profiles show up in search results, which in testing was roughly 10 to 45% of a small company, 7 to 19% of a mid-size one and under 1% of a very large one. A fresh run with profile checks takes about 3 to 10 minutes per company.
Input parameters
| PARAMETER | TYPE | REQ | DEFAULT | DESCRIPTION |
|---|---|---|---|---|
| companies | string[] | yes | — | Companies to list, as LinkedIn company URLs (https://www.linkedin.com/company/microsoft) or company names (Microsoft). A URL is exact; a name is matched to its LinkedIn company page first. Up to 50 per run. — drives your bill |
| titleKeywords | string[] | no | — | Return only people whose public page mentions one of these job titles, for example engineer, sales or head of marketing. Each keyword is also its own search, which reaches people a plain company search ranks too deep to find. Up to 20. |
| locations | string[] | no | — | Return only people in these cities, regions or countries, for example Dublin or United States. People whose public profile shows a different location are left out. Up to 10. |
| maxResultsPerCompany | integer | no | 100 | Stop after this many people per company, 1 to 1,000. You are charged only for people actually returned. Large companies rarely return their full headcount. — drives your bill |
| verifyEmployment | boolean | no | true | Open each person's public profile and keep only people with a current role at the company; checked rows also carry location, work history, education and follower count where LinkedIn shows them. Set to false for a faster list from search results alone (name, headline, profile URL), limited to people whose search result lists the company as their experience. Some of them may have left since. |
| maxSearchQueriesPerCompany | integer | no | 40 | Cap on the public searches run per company, 1 to 100. Each search returns about ten people, so more searches reach more of a large company and fewer make a quicker run. |
| maxAgeDays | integer | no | — | Serve results fetched within this many days from the shared cache, up to 90. 0 always fetches fresh. Left empty, profiles are reused for up to 7 days, company pages for 30 and searches for 1. |
Output schema
| FIELD | TYPE | DESCRIPTION | NULLABLE |
|---|---|---|---|
| result_type | string | employee for a person at a requested company; error for a company that could not be found or searched. Error rows are never charged as a person. | no |
| companyName | string | The company the person was found for, as named on its LinkedIn page | no |
| companySlug | string | The company's LinkedIn handle, the last part of its company page URL | no |
| companyUrl | string | The company's public LinkedIn page | no |
| fullName | string | Name as shown on the public profile or search result | no |
| headline | string | The professional headline under the person's name | yes |
| currentTitle | string | Title of the current role, read from the profile or from a "title at company" headline. Missing on some rows, because LinkedIn hides many job titles from signed-out visitors | yes |
| currentCompany | string | Employer of the current role, as the profile or search result shows it | yes |
| location | string | City or area from the public profile, present when the profile was opened | yes |
| profileUrl | string | Canonical public profile URL, with tracking parameters removed | no |
| slug | string | The profile's public identifier. Stable per person, so it is the key for deduplicating and for comparing one run with the next | no |
| verified | boolean | true when the public profile confirms a current role at the company; null when the profile was not opened (checks off, or a per-company limit reached) or could not be opened. People whose profile shows they work elsewhere are not returned, so false does not occur | yes |
| matchReason | string | How the row was decided. current-position or current-company: the profile links this company's page. company-name: a weaker match on the employer's name. profile-unavailable or search-experience: not opened, and the search result lists the company as the person's experience | no |
| foundBy | string | The public search that found the person, or company-page, so a list can be audited and reproduced | no |
| about | string | The public About text. Checked rows only | yes |
| positions | object[] | Work history with titles and dates. Checked rows only, and present only on the few profiles whose experience section LinkedIn shows to signed-out visitors | yes |
| education | object[] | Schools on the public profile, with dates where shown. Checked rows only | yes |
| followers | integer | Follower count on the public profile. Checked rows only | yes |
| connections | integer | Connection count on the public profile, which LinkedIn caps at 500. Checked rows only | yes |
| photoUrl | string | Public profile photo link, when the person has one. Checked rows only | yes |
| memberId | string | LinkedIn's numeric member id from the public profile. Checked rows only | yes |
| fromCache | boolean | true when the row was served from the shared cache rather than fetched in this run | no |
| fetched_at | string | When the data behind the row was fetched, as ISO 8601 UTC. For a cached row, the original fetch time | no |
| requestedCompany | string | Error rows only. The companies entry the error is about, exactly as given | yes |
| error_type | string | Error rows only. CompanyNotFound, CompanyPageUnavailable, SearchUnavailable or InvalidInput | yes |
| error_message | string | Error rows only. What went wrong, in plain words | yes |
Worked examples
{ "companies": ["https://www.linkedin.com/company/stripe"] }
{
"companies": ["https://www.linkedin.com/company/stripe", "Intercom"],
"titleKeywords": ["engineer", "recruiter"],
"locations": ["Dublin"],
"maxResultsPerCompany": 50
}
{
"companies": ["Supabase", "Linear", "Brex"],
"titleKeywords": ["vp", "head of", "director", "chief"],
"maxResultsPerCompany": 25
}
{
"companies": ["https://www.linkedin.com/company/microsoft"],
"titleKeywords": ["recruiter"],
"verifyEmployment": false
}
Coverage
Code
Start a run, then read the Employees view
# A run with profile checks takes minutes, so start it and read the results when it finishes.
curl -X POST "https://api.apify.com/v2/acts/johnvc~linkedin-company-employees-api/runs" \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"companies": ["https://www.linkedin.com/company/stripe"], "titleKeywords": ["engineer"], "maxResultsPerCompany": 50}'
# The response carries data.defaultDatasetId. Once the run has SUCCEEDED:
curl "https://api.apify.com/v2/datasets/DATASET_ID/items?view=overview" \
-H "Authorization: Bearer $APIFY_TOKEN"
Fast list in one call, without profile checks
curl -X POST "https://api.apify.com/v2/acts/johnvc~linkedin-company-employees-api/run-sync-get-dataset-items" \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"companies": ["https://www.linkedin.com/company/microsoft"], "titleKeywords": ["recruiter"], "maxResultsPerCompany": 30, "verifyEmployment": false}'
Python
from apify_client import ApifyClient
client = ApifyClient("APIFY_TOKEN")
run = client.actor("johnvc/linkedin-company-employees-api").call(
run_input={
"companies": ["https://www.linkedin.com/company/stripe", "Intercom"],
"titleKeywords": ["engineer", "recruiter"],
"locations": ["Dublin"],
"maxResultsPerCompany": 50,
}
)
for row in client.dataset(run.default_dataset_id).iterate_items():
if row.get("result_type") == "employee":
print(row.get("fullName"), row.get("currentTitle"), row.get("verified"), row.get("profileUrl"))
MCP
claude mcp add --transport http linkedin-company-employees \ "https://mcp.apify.com/?tools=actors,docs,johnvc/linkedin-company-employees-api"
Sample output row (synthetic, not a real person)
{
"result_type": "employee",
"companyName": "Example Corp",
"companySlug": "example-corp",
"companyUrl": "https://www.linkedin.com/company/example-corp",
"fullName": "Jane Doe",
"headline": "Senior Data Engineer at Example Corp",
"currentTitle": "Senior Data Engineer",
"currentCompany": "Example Corp",
"location": "Dublin, Ireland",
"profileUrl": "https://www.linkedin.com/in/example-profile",
"slug": "example-profile",
"verified": true,
"matchReason": "current-position",
"foundBy": "site:linkedin.com/in \"Example Corp\" engineer",
"fromCache": false,
"fetched_at": "2026-10-02T09:15:00Z"
}
What people use it for
- Talent mapping a competitor's team by title and city
- Account mapping for sales, down to the decision makers at each account
- Finding the people at a company who hold a given role
- CRM hygiene, confirming which contacts still work at an account
- Checking a startup's founders and senior hires before an investor call
- Feeding an AI agent structured people data over MCP
More sources for Hiring signals and talent intelligence, Lead sourcing and CRM enrichment, Investor and funding research, Grounding AI agents and MCP tools →