{
  "data": {
    "id": "CSf1eVuAUi59biXia",
    "actId": "HiQGqCcdufptzP7GA",
    "userId": "IYgBDiXtHOijAaUel",
    "startedAt": "2026-10-22T17:52:42.634Z",
    "finishedAt": "2026-10-22T17:52:55.569Z",
    "status": "SUCCEEDED",
    "meta": {
      "origin": "CLI"
    },
    "stats": {
      "durationMillis": 12814,
      "runTimeSecs": 12.814,
      "computeUnits": 0.014237777777777778,
      "imageSizeBytes": 359370240
    },
    "options": {
      "useCache": true,
      "betaPackages": false,
      "memoryMbytes": 4096,
      "diskMbytes": 8192
    },
    "createdByOrganizationMemberUserId": "QYo53EZkJk0prePWY",
    "exitCode": 0,
    "inputSchema": "{\n  \"title\": \"LinkedIn Company Headcount & Team Directory Scraper Input\",\n  \"description\": \"Provide at least one company URL, domain, or name. Headcount and firmographics work without a cookie; employee rows are optional and require your own LinkedIn session cookie.\",\n  \"type\": \"object\",\n  \"schemaVersion\": 1,\n  \"properties\": {\n    \"companyUrls\": {\n      \"title\": \"Company LinkedIn URLs\",\n      \"type\": \"array\",\n      \"description\": \"LinkedIn company page URLs. Accepts https://www.linkedin.com/company/stripe/, linkedin.com/company/stripe, or company/stripe.\",\n      \"editor\": \"stringList\",\n      \"default\": [],\n      \"prefill\": []\n    },\n    \"companyDomains\": {\n      \"title\": \"Company domains\",\n      \"type\": \"array\",\n      \"description\": \"Company website domains, e.g. stripe.com or notion.so. The resolver follows LinkedIn's page website to pick the correct same-name company.\",\n      \"editor\": \"stringList\",\n      \"default\": [],\n      \"prefill\": [\n        \"stripe.com\"\n      ]\n    },\n    \"companyNames\": {\n      \"title\": \"Company names\",\n      \"type\": \"array\",\n      \"description\": \"Company display names, e.g. Stripe or Microsoft. Name-only input is validated; ambiguous bare names (Notion, Linear, Cal) return an error row asking for a URL or domain.\",\n      \"editor\": \"stringList\",\n      \"default\": [],\n      \"prefill\": []\n    },\n    \"includeEmployees\": {\n      \"title\": \"Include employee roster\",\n      \"type\": \"boolean\",\n      \"description\": \"When true, also request the employee roster. Requires a valid LinkedIn session cookie and is capped by LinkedIn at 2,500 visible results per query.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"maxEmployees\": {\n      \"title\": \"Max employees per company\",\n      \"type\": \"integer\",\n      \"description\": \"Roster cap per company (1-2500). Ignored when includeEmployees is false. Large companies are sampled.\",\n      \"default\": 100,\n      \"minimum\": 1,\n      \"maximum\": 2500,\n      \"prefill\": 100\n    },\n    \"maxItemsTotal\": {\n      \"title\": \"Max dataset items\",\n      \"type\": \"integer\",\n      \"description\": \"Hard cap across company summaries, employee rows, and error rows (1-10000).\",\n      \"default\": 500,\n      \"minimum\": 1,\n      \"maximum\": 10000,\n      \"prefill\": 1\n    },\n    \"startPage\": {\n      \"title\": \"Roster start page\",\n      \"type\": \"integer\",\n      \"description\": \"Resume the roster from this page (1-250, 10 employees per page). Use it to continue a capped run.\",\n      \"default\": 1,\n      \"minimum\": 1,\n      \"maximum\": 250,\n      \"prefill\": 1\n    },\n    \"titleKeywords\": {\n      \"title\": \"Title / headline keywords\",\n      \"type\": \"string\",\n      \"description\": \"Roster filter: free-text role or headline match, e.g. Software Engineer or VP Sales. Cookie roster only.\",\n      \"editor\": \"textfield\",\n      \"prefill\": \"\"\n    },\n    \"location\": {\n      \"title\": \"Location\",\n      \"type\": \"string\",\n      \"description\": \"Roster filter: best-effort location match on the employee's LinkedIn location, e.g. London. Cookie roster only.\",\n      \"editor\": \"textfield\",\n      \"prefill\": \"\"\n    },\n    \"seniorityLevels\": {\n      \"title\": \"Seniority levels\",\n      \"type\": \"array\",\n      \"description\": \"Roster filter: one or more LinkedIn seniority levels. Empty means all levels. Cookie roster only. Allowed values: Entry, Associate, Mid-Senior, Director, Executive.\",\n      \"editor\": \"stringList\",\n      \"items\": {\n        \"type\": \"string\"\n      },\n      \"default\": [],\n      \"prefill\": []\n    },\n    \"functions\": {\n      \"title\": \"Job functions\",\n      \"type\": \"array\",\n      \"description\": \"Roster filter: one or more LinkedIn job functions. Empty means all functions. Cookie roster only. Allowed values: Engineering, Sales, Marketing, Operations, Finance, Human Resources, Design, Product, Customer Service, Information Technology, Legal, Other.\",\n      \"editor\": \"stringList\",\n      \"items\": {\n        \"type\": \"string\"\n      },\n      \"default\": [],\n      \"prefill\": []\n    },\n    \"connectionDegree\": {\n      \"title\": \"Connection degree\",\n      \"type\": \"string\",\n      \"description\": \"Roster filter: restrict to 1st, 2nd, or 3rd+ degree connections. Cookie roster only.\",\n      \"enum\": [\n        \"\",\n        \"F\",\n        \"S\",\n        \"O\"\n      ],\n      \"enumTitles\": [\n        \"All connections\",\n        \"1st degree only\",\n        \"2nd degree only\",\n        \"3rd degree+\"\n      ],\n      \"default\": \"\",\n      \"prefill\": \"\"\n    },\n    \"language\": {\n      \"title\": \"Profile language\",\n      \"type\": \"string\",\n      \"description\": \"Roster filter: primary profile language. Cookie roster only.\",\n      \"enum\": [\n        \"\",\n        \"en\",\n        \"es\",\n        \"fr\",\n        \"de\",\n        \"pt\",\n        \"it\",\n        \"nl\",\n        \"zh\",\n        \"ja\"\n      ],\n      \"enumTitles\": [\n        \"Any language\",\n        \"English\",\n        \"Spanish\",\n        \"French\",\n        \"German\",\n        \"Portuguese\",\n        \"Italian\",\n        \"Dutch\",\n        \"Chinese\",\n        \"Japanese\"\n      ],\n      \"default\": \"\",\n      \"prefill\": \"\"\n    },\n    \"cookies\": {\n      \"title\": \"LinkedIn cookie (optional)\",\n      \"type\": \"string\",\n      \"description\": \"Optional LinkedIn session cookie for the employee roster. Accepts the li_at value or a full cookies JSON array. Never required for headcount/firmographics.\",\n      \"editor\": \"textarea\",\n      \"isSecret\": true\n    },\n    \"proxyConfiguration\": {\n      \"title\": \"Proxy configuration\",\n      \"type\": \"object\",\n      \"description\": \"Optional advanced override. The actor works without a proxy and chooses a working connection automatically.\",\n      \"editor\": \"proxy\"\n    }\n  }\n}",
    "readme": "# LinkedIn Company Headcount & Team Directory Scraper\r\n\r\nGet a company's LinkedIn-reported headcount and firmographics without logging in — employee count, size band, followers, industry, headquarters, type, website, address, about text, specialties, and logo. Add your own LinkedIn session cookie only when you also want the optional employee roster.\r\n\r\n## What this actor does\r\n\r\n- **Cookieless headcount first:** one `recordType: company` row per input with LinkedIn's reported employee count, size band, followers, industry, HQ, type, website, address, specialties, and logo.\r\n- **Domain-aware company resolution:** accepts LinkedIn URLs, company domains, and names; mixed inputs are allowed. A URL is trusted, a domain is confirmed against the page's website (including rebranded hosts such as `notion.so` → `notion.com`), and a name must match the page exactly with a matching website or enough follower authority.\r\n- **Honest ambiguity handling:** bare-name inputs such as Notion, Linear, or Cal can collide with a different same-name LinkedIn page. Those return an explicit error row instead of a silent wrong-company match; domain forms such as `cal.com` resolve normally.\r\n- **Optional cookie roster:** with a valid cookie, fetches up to 2,500 visible employees per company in 10-row pages, with title, location, seniority, function, connection degree, language, and resume-from-page filters.\r\n- **Explicit coverage and confidence:** every company row carries `headcountConfidence`, `employeesReported`, `employeesReturned`, and a `coverage` block. Error rows have an `errorCode`, so a missing roster never looks like a complete one.\r\n- **Empty fields are omitted:** missing values are left out instead of being returned as `null`.\r\n\r\n## Output per company (`recordType: \"company\"`)\r\n\r\n- `input` — the value you supplied\r\n- `companyName`, `companySlug`, `companyUrl`\r\n- `linkedinCompanyId` — numeric LinkedIn organization ID\r\n- `resolutionMethod` — `provided_url`, `domain_slug`, or `name_variant`\r\n- `resolutionConfidence`, `confidence` — `high` for a validated page\r\n- `resolutionCandidates` — alternate slugs tried, when any\r\n- `linkedinEmployeeCount` — LinkedIn-reported employee count\r\n- `linkedinEmployeeCountSource` — `public_company_page`\r\n- `companySizeRange` — LinkedIn's band, e.g. `5,001-10,000 employees`\r\n- `headcountConfidence` — `high` when the count is inside the band or the band is open-ended; `medium` up to 2x above; `low` above 2x\r\n- `headcount` — `{ reported, sizeBand, asOf, source, audited: false }`; the count is never described as audited\r\n- `followerCount`, `industry`, `headquarters`, `companyType`\r\n- `website`, `primaryAddress`, `address`\r\n- `about`, `tagline`, `specialties[]`, `locations[]`, `logoUrl`\r\n- `employeesReported` — LinkedIn's company count\r\n- `employeesReturned`, `employeesCoveragePct`\r\n- `rosterMode` — `cookieless` or `cookie`\r\n- `rosterAvailable`, `rosterReportedTotal`, `rosterRowsReturned`, `rosterCoveragePct`, `rosterConfidence`, `rosterReason`\r\n- `coverage` — `{ employeesReturned, employeesReported, rosterReportedTotal, rosterCoveragePct, rosterAvailable, rosterConfidence }`\r\n- `filtersApplied` — the roster filters that were sent\r\n- `sourceMode` — `cookieless_public_page`\r\n- `warnings[]` — human-readable caveats\r\n- `recordType`, `scrapedAt`\r\n\r\n## Output per employee (`recordType: \"employee\"`)\r\n\r\n- `companySlug`, `companyName`, `currentCompany`\r\n- `name`, `firstName`, `lastName`, `publicIdentifier`\r\n- `headline`, `currentTitle`, `currentDepartment`, `department`\r\n- `seniority`, `senioritySource` — derived from the title when LinkedIn does not expose a seniority field\r\n- `location`, `country`\r\n- `profileUrl`\r\n- `profilePicture`, `profileImageUrl`, `profilePictureUrl`\r\n- `tenure`, `tenureYears`, `tenureSource` — only when LinkedIn exposes a duration\r\n- `connectionDegree`\r\n- `industryName`, `currentCompanyLogo`\r\n- `openToWork`, `premium`, `verifiedStatus` — only when the badge is present\r\n- `email`, `emailSource` — only if an email is explicitly visible; usually absent\r\n- `source` — `cookie-roster`\r\n- `sourceMode` — `cookie_voyager`\r\n- `companyFilterApplied` — `true`; rows are only returned when the company filter was applied\r\n- `confidence` — `high` with a headline, `medium` otherwise\r\n- `recordType`, `scrapedAt`\r\n\r\n## Output per error (`recordType: \"error\"`)\r\n\r\n- `input`, `companySlug`, `companyName` (when known)\r\n- `errorCode` — `ambiguous_company_name`, `company_not_found`, `company_unresolved`, `rate_limited` (the public company page returned 999/429), `cookie_missing`, `cookie_invalid`, `company_id_unresolved`, `roster_rate_limited`, `roster_request_budget_reached`, or `roster_unavailable`\r\n- `error`, `message`, `help`\r\n- `retryable`\r\n- `resolutionCandidates`, `rejectedCandidates` — for resolution failures\r\n- `recordType`, `scrapedAt`\r\n\r\n## Input\r\n\r\n| Field | Type | Default | Description |\r\n|---|---|---|---|\r\n| `companyUrls` | array | `[]` | LinkedIn company URLs, e.g. `https://www.linkedin.com/company/stripe/` |\r\n| `companyDomains` | array | `[]` | Company domains, e.g. `stripe.com`, `notion.so`, or `cal.com` |\r\n| `companyNames` | array | `[]` | Company names, e.g. `Stripe`; ambiguous names need a URL or domain |\r\n| `includeEmployees` | boolean | `false` | Also request the optional employee roster (requires a valid cookie) |\r\n| `maxEmployees` | integer | `100` | Roster cap per company (1–2500); ignored without `includeEmployees` |\r\n| `maxItemsTotal` | integer | `500` | Hard cap on all dataset rows (1–10000) |\r\n| `startPage` | integer | `1` | Resume the roster from this 10-row page (1–250) |\r\n| `titleKeywords` | string | – | Roster filter on role/headline, e.g. `Software Engineer` |\r\n| `location` | string | – | Best-effort roster filter on the employee's LinkedIn location |\r\n| `seniorityLevels` | array | `[]` | `Entry`, `Associate`, `Mid-Senior`, `Director`, `Executive` |\r\n| `functions` | array | `[]` | `Engineering`, `Sales`, `Marketing`, `Operations`, `Finance`, `Human Resources`, `Design`, `Product`, `Customer Service`, `Information Technology`, `Legal`, `Other` |\r\n| `connectionDegree` | string | `\"\"` | `\"\"` (all), `F` (1st), `S` (2nd), `O` (3rd+) |\r\n| `language` | string | `\"\"` | Profile language: `en`, `es`, `fr`, `de`, `pt`, `it`, `nl`, `zh`, `ja` |\r\n| `cookies` | string | – | Optional LinkedIn cookie for the roster (`li_at` or a full cookies JSON array) |\r\n| `proxyConfiguration` | object | – | Optional advanced override; no proxy setup is required |\r\n\r\nProvide at least one of `companyUrls`, `companyDomains`, or `companyNames`. You can mix them in one run.\r\n\r\n### Example: cookieless headcount for mixed inputs\r\n\r\n```json\r\n{\r\n  \"companyUrls\": [\"https://www.linkedin.com/company/stripe/\"],\r\n  \"companyDomains\": [\"notion.so\", \"linear.app\"],\r\n  \"includeEmployees\": false,\r\n  \"maxItemsTotal\": 10\r\n}\r\n```\r\n\r\n### Example: batch headcount by name\r\n\r\n```json\r\n{\r\n  \"companyNames\": [\"Microsoft\", \"HubSpot\", \"Figma\"],\r\n  \"includeEmployees\": false,\r\n  \"maxItemsTotal\": 20\r\n}\r\n```\r\n\r\n### Example: roster for one company with a cookie\r\n\r\n```json\r\n{\r\n  \"companyDomains\": [\"raycast.com\"],\r\n  \"includeEmployees\": true,\r\n  \"maxEmployees\": 50,\r\n  \"titleKeywords\": \"Engineer\",\r\n  \"seniorityLevels\": [\"Mid-Senior\", \"Director\"],\r\n  \"maxItemsTotal\": 100,\r\n  \"cookies\": \"YOUR_LI_AT_COOKIE\"\r\n}\r\n```\r\n\r\n### Example: resume a capped roster\r\n\r\n```json\r\n{\r\n  \"companyUrls\": [\"https://www.linkedin.com/company/microsoft/\"],\r\n  \"includeEmployees\": true,\r\n  \"maxEmployees\": 100,\r\n  \"startPage\": 26,\r\n  \"maxItemsTotal\": 200,\r\n  \"cookies\": \"YOUR_LI_AT_COOKIE\"\r\n}\r\n```\r\n\r\n## Use cases\r\n\r\n- **Account research** — capture headcount, size band, HQ, industry, and website for a list of target companies without a LinkedIn login.\r\n- **Market mapping** — compare headcount and follower counts across a segment of public and private companies.\r\n- **Recruiting and sourcing** — pair cookieless firmographics with an optional roster when you have a session that can see the people tab.\r\n- **Sales operations** — enrich CRM accounts with LinkedIn-reported size and industry fields.\r\n- **Competitive tracking** — periodically snapshot headcount, followers, and specialties for competitor pages.\r\n- **Data quality checks** — use `headcountConfidence` to flag companies whose reported count and size band disagree.\r\n\r\n## Limitations and caps\r\n\r\n- **Headcount is LinkedIn-reported, not audited.** The public count can differ from LinkedIn's own size band; both fields are returned and `headcountConfidence` labels the gap. It is not a payroll, HRIS, or verified workforce count.\r\n- **The roster is optional and cookie-gated.** Without a valid cookie only the company row is returned, with an explicit warning and no employee rows.\r\n- **LinkedIn caps a roster query at 2,500 visible results.** Pages contain 10 rows, so a query can need up to 250 requests. The actor budgets about 250 roster requests per run to stay inside LinkedIn's daily limit; when the budget is used, the remaining companies get an explicit error row and a later run can resume with `startPage`. Large companies are samples rather than complete workforces.\r\n- **`maxEmployees` is the per-company cap.** If LinkedIn reports more employees than the cap, the row set is a sample; `rosterReportedTotal` and `rosterCoveragePct` make the shortfall visible.\r\n- **Filters are best-effort.** Title, seniority, function, connection degree, and language are sent to LinkedIn; location is matched against the returned location text. Missing fields are not used to exclude a row.\r\n- **Email is not harvested.** It is returned only when an email is explicitly visible on the result; expect none. Tenure is returned only when LinkedIn exposes a duration.\r\n- **Past employees are not supported.** The actor returns current employees when a roster is requested.\r\n- **Name-only resolution is restricted.** Ambiguous bare names (Notion, Linear, Cal, and similar) return an error row. Pass the LinkedIn URL or the company domain instead (for example `cal.com` for Cal.com).\r\n- **Public pages can rate-limit.** If LinkedIn throttles the company page itself, the actor emits a retryable `rate_limited` error row instead of a company row. If it throttles a roster request, the company row is still returned with a warning. Retry later or narrow the input list.\r\n\r\n## FAQ\r\n\r\n**Do I need a LinkedIn cookie for headcount?**\r\nNo. Company name, LinkedIn-reported employee count, size band, followers, industry, HQ, type, website, address, about, specialties, and logo come from the public company page.\r\n\r\n**When do I need a cookie?**\r\nOnly for the employee roster. Set `includeEmployees` to `true` and add a valid `li_at` value or full cookie export. The cookie is never required for the company row.\r\n\r\n**Why did I get an error row instead of employees?**\r\nThe run tells you which case applies: `cookie_missing` (no cookie), `cookie_invalid` (expired or rejected session), `company_id_unresolved` (the roster filter could not be mapped), `roster_rate_limited` (LinkedIn returned 999/429), or `roster_request_budget_reached` (the ~250-request run budget was used). Company headcount is still returned whenever the page resolves.\r\n\r\n**Why does the employee count disagree with the size band?**\r\nLinkedIn shows two independent fields. A company can report 7,000 employees while its self-selected band says 501–1,000. The actor publishes both and labels the count `high`, `medium`, or `low` confidence rather than presenting either as audited.\r\n\r\n**Why is the roster smaller than the company's headcount?**\r\nLinkedIn caps a single query at 2,500 visible results and serves 10 per page; the daily request limit is about 250. For a large employer, the roster is a sample. Raise `maxEmployees`, split the request with `startPage`, or narrow the filters.\r\n\r\n**Why did my company name resolve to a different company?**\r\nSome names are shared by several LinkedIn pages. The actor refuses the low-confidence name match and asks for a URL or domain. For example, `notion.so` resolves to the right Notion page, while the name alone is treated as ambiguous.\r\n\r\n**Can I get email addresses?**\r\nOnly if LinkedIn explicitly shows an email in the result. The actor does not guess or construct emails, so most records have no email field.\r\n\r\n**Can I get tenure?**\r\nOnly when LinkedIn exposes a duration for the person. Otherwise `tenure` and `tenureYears` are omitted instead of estimated.\r\n\r\n**Does the actor return past employees?**\r\nNo. The roster is current employees only.\r\n\r\n**Is this affiliated with LinkedIn?**\r\nNo. This is an independent, third-party actor. It uses publicly visible company pages and, when you supply one, your own LinkedIn session for the roster. You are responsible for how you use the data.\r\n",
    "actorDefinition": {
      "actorSpecification": 1,
      "name": "linkedin-company-headcount-and-team-directory",
      "title": "LinkedIn Company Headcount & Team Directory Scraper",
      "description": "Get LinkedIn-reported headcount, size band, followers, industry, HQ, website, address, specialties, and logo for any company without a login, plus an optional employee roster when you supply your own LinkedIn cookie.",
      "version": "2.0",
      "buildTag": "latest",
      "environmentVariables": {},
      "dockerfile": "./Dockerfile",
      "readme": "# LinkedIn Company Headcount & Team Directory Scraper\r\n\r\nGet a company's LinkedIn-reported headcount and firmographics without logging in — employee count, size band, followers, industry, headquarters, type, website, address, about text, specialties, and logo. Add your own LinkedIn session cookie only when you also want the optional employee roster.\r\n\r\n## What this actor does\r\n\r\n- **Cookieless headcount first:** one `recordType: company` row per input with LinkedIn's reported employee count, size band, followers, industry, HQ, type, website, address, specialties, and logo.\r\n- **Domain-aware company resolution:** accepts LinkedIn URLs, company domains, and names; mixed inputs are allowed. A URL is trusted, a domain is confirmed against the page's website (including rebranded hosts such as `notion.so` → `notion.com`), and a name must match the page exactly with a matching website or enough follower authority.\r\n- **Honest ambiguity handling:** bare-name inputs such as Notion, Linear, or Cal can collide with a different same-name LinkedIn page. Those return an explicit error row instead of a silent wrong-company match; domain forms such as `cal.com` resolve normally.\r\n- **Optional cookie roster:** with a valid cookie, fetches up to 2,500 visible employees per company in 10-row pages, with title, location, seniority, function, connection degree, language, and resume-from-page filters.\r\n- **Explicit coverage and confidence:** every company row carries `headcountConfidence`, `employeesReported`, `employeesReturned`, and a `coverage` block. Error rows have an `errorCode`, so a missing roster never looks like a complete one.\r\n- **Empty fields are omitted:** missing values are left out instead of being returned as `null`.\r\n\r\n## Output per company (`recordType: \"company\"`)\r\n\r\n- `input` — the value you supplied\r\n- `companyName`, `companySlug`, `companyUrl`\r\n- `linkedinCompanyId` — numeric LinkedIn organization ID\r\n- `resolutionMethod` — `provided_url`, `domain_slug`, or `name_variant`\r\n- `resolutionConfidence`, `confidence` — `high` for a validated page\r\n- `resolutionCandidates` — alternate slugs tried, when any\r\n- `linkedinEmployeeCount` — LinkedIn-reported employee count\r\n- `linkedinEmployeeCountSource` — `public_company_page`\r\n- `companySizeRange` — LinkedIn's band, e.g. `5,001-10,000 employees`\r\n- `headcountConfidence` — `high` when the count is inside the band or the band is open-ended; `medium` up to 2x above; `low` above 2x\r\n- `headcount` — `{ reported, sizeBand, asOf, source, audited: false }`; the count is never described as audited\r\n- `followerCount`, `industry`, `headquarters`, `companyType`\r\n- `website`, `primaryAddress`, `address`\r\n- `about`, `tagline`, `specialties[]`, `locations[]`, `logoUrl`\r\n- `employeesReported` — LinkedIn's company count\r\n- `employeesReturned`, `employeesCoveragePct`\r\n- `rosterMode` — `cookieless` or `cookie`\r\n- `rosterAvailable`, `rosterReportedTotal`, `rosterRowsReturned`, `rosterCoveragePct`, `rosterConfidence`, `rosterReason`\r\n- `coverage` — `{ employeesReturned, employeesReported, rosterReportedTotal, rosterCoveragePct, rosterAvailable, rosterConfidence }`\r\n- `filtersApplied` — the roster filters that were sent\r\n- `sourceMode` — `cookieless_public_page`\r\n- `warnings[]` — human-readable caveats\r\n- `recordType`, `scrapedAt`\r\n\r\n## Output per employee (`recordType: \"employee\"`)\r\n\r\n- `companySlug`, `companyName`, `currentCompany`\r\n- `name`, `firstName`, `lastName`, `publicIdentifier`\r\n- `headline`, `currentTitle`, `currentDepartment`, `department`\r\n- `seniority`, `senioritySource` — derived from the title when LinkedIn does not expose a seniority field\r\n- `location`, `country`\r\n- `profileUrl`\r\n- `profilePicture`, `profileImageUrl`, `profilePictureUrl`\r\n- `tenure`, `tenureYears`, `tenureSource` — only when LinkedIn exposes a duration\r\n- `connectionDegree`\r\n- `industryName`, `currentCompanyLogo`\r\n- `openToWork`, `premium`, `verifiedStatus` — only when the badge is present\r\n- `email`, `emailSource` — only if an email is explicitly visible; usually absent\r\n- `source` — `cookie-roster`\r\n- `sourceMode` — `cookie_voyager`\r\n- `companyFilterApplied` — `true`; rows are only returned when the company filter was applied\r\n- `confidence` — `high` with a headline, `medium` otherwise\r\n- `recordType`, `scrapedAt`\r\n\r\n## Output per error (`recordType: \"error\"`)\r\n\r\n- `input`, `companySlug`, `companyName` (when known)\r\n- `errorCode` — `ambiguous_company_name`, `company_not_found`, `company_unresolved`, `rate_limited` (the public company page returned 999/429), `cookie_missing`, `cookie_invalid`, `company_id_unresolved`, `roster_rate_limited`, `roster_request_budget_reached`, or `roster_unavailable`\r\n- `error`, `message`, `help`\r\n- `retryable`\r\n- `resolutionCandidates`, `rejectedCandidates` — for resolution failures\r\n- `recordType`, `scrapedAt`\r\n\r\n## Input\r\n\r\n| Field | Type | Default | Description |\r\n|---|---|---|---|\r\n| `companyUrls` | array | `[]` | LinkedIn company URLs, e.g. `https://www.linkedin.com/company/stripe/` |\r\n| `companyDomains` | array | `[]` | Company domains, e.g. `stripe.com`, `notion.so`, or `cal.com` |\r\n| `companyNames` | array | `[]` | Company names, e.g. `Stripe`; ambiguous names need a URL or domain |\r\n| `includeEmployees` | boolean | `false` | Also request the optional employee roster (requires a valid cookie) |\r\n| `maxEmployees` | integer | `100` | Roster cap per company (1–2500); ignored without `includeEmployees` |\r\n| `maxItemsTotal` | integer | `500` | Hard cap on all dataset rows (1–10000) |\r\n| `startPage` | integer | `1` | Resume the roster from this 10-row page (1–250) |\r\n| `titleKeywords` | string | – | Roster filter on role/headline, e.g. `Software Engineer` |\r\n| `location` | string | – | Best-effort roster filter on the employee's LinkedIn location |\r\n| `seniorityLevels` | array | `[]` | `Entry`, `Associate`, `Mid-Senior`, `Director`, `Executive` |\r\n| `functions` | array | `[]` | `Engineering`, `Sales`, `Marketing`, `Operations`, `Finance`, `Human Resources`, `Design`, `Product`, `Customer Service`, `Information Technology`, `Legal`, `Other` |\r\n| `connectionDegree` | string | `\"\"` | `\"\"` (all), `F` (1st), `S` (2nd), `O` (3rd+) |\r\n| `language` | string | `\"\"` | Profile language: `en`, `es`, `fr`, `de`, `pt`, `it`, `nl`, `zh`, `ja` |\r\n| `cookies` | string | – | Optional LinkedIn cookie for the roster (`li_at` or a full cookies JSON array) |\r\n| `proxyConfiguration` | object | – | Optional advanced override; no proxy setup is required |\r\n\r\nProvide at least one of `companyUrls`, `companyDomains`, or `companyNames`. You can mix them in one run.\r\n\r\n### Example: cookieless headcount for mixed inputs\r\n\r\n```json\r\n{\r\n  \"companyUrls\": [\"https://www.linkedin.com/company/stripe/\"],\r\n  \"companyDomains\": [\"notion.so\", \"linear.app\"],\r\n  \"includeEmployees\": false,\r\n  \"maxItemsTotal\": 10\r\n}\r\n```\r\n\r\n### Example: batch headcount by name\r\n\r\n```json\r\n{\r\n  \"companyNames\": [\"Microsoft\", \"HubSpot\", \"Figma\"],\r\n  \"includeEmployees\": false,\r\n  \"maxItemsTotal\": 20\r\n}\r\n```\r\n\r\n### Example: roster for one company with a cookie\r\n\r\n```json\r\n{\r\n  \"companyDomains\": [\"raycast.com\"],\r\n  \"includeEmployees\": true,\r\n  \"maxEmployees\": 50,\r\n  \"titleKeywords\": \"Engineer\",\r\n  \"seniorityLevels\": [\"Mid-Senior\", \"Director\"],\r\n  \"maxItemsTotal\": 100,\r\n  \"cookies\": \"YOUR_LI_AT_COOKIE\"\r\n}\r\n```\r\n\r\n### Example: resume a capped roster\r\n\r\n```json\r\n{\r\n  \"companyUrls\": [\"https://www.linkedin.com/company/microsoft/\"],\r\n  \"includeEmployees\": true,\r\n  \"maxEmployees\": 100,\r\n  \"startPage\": 26,\r\n  \"maxItemsTotal\": 200,\r\n  \"cookies\": \"YOUR_LI_AT_COOKIE\"\r\n}\r\n```\r\n\r\n## Use cases\r\n\r\n- **Account research** — capture headcount, size band, HQ, industry, and website for a list of target companies without a LinkedIn login.\r\n- **Market mapping** — compare headcount and follower counts across a segment of public and private companies.\r\n- **Recruiting and sourcing** — pair cookieless firmographics with an optional roster when you have a session that can see the people tab.\r\n- **Sales operations** — enrich CRM accounts with LinkedIn-reported size and industry fields.\r\n- **Competitive tracking** — periodically snapshot headcount, followers, and specialties for competitor pages.\r\n- **Data quality checks** — use `headcountConfidence` to flag companies whose reported count and size band disagree.\r\n\r\n## Limitations and caps\r\n\r\n- **Headcount is LinkedIn-reported, not audited.** The public count can differ from LinkedIn's own size band; both fields are returned and `headcountConfidence` labels the gap. It is not a payroll, HRIS, or verified workforce count.\r\n- **The roster is optional and cookie-gated.** Without a valid cookie only the company row is returned, with an explicit warning and no employee rows.\r\n- **LinkedIn caps a roster query at 2,500 visible results.** Pages contain 10 rows, so a query can need up to 250 requests. The actor budgets about 250 roster requests per run to stay inside LinkedIn's daily limit; when the budget is used, the remaining companies get an explicit error row and a later run can resume with `startPage`. Large companies are samples rather than complete workforces.\r\n- **`maxEmployees` is the per-company cap.** If LinkedIn reports more employees than the cap, the row set is a sample; `rosterReportedTotal` and `rosterCoveragePct` make the shortfall visible.\r\n- **Filters are best-effort.** Title, seniority, function, connection degree, and language are sent to LinkedIn; location is matched against the returned location text. Missing fields are not used to exclude a row.\r\n- **Email is not harvested.** It is returned only when an email is explicitly visible on the result; expect none. Tenure is returned only when LinkedIn exposes a duration.\r\n- **Past employees are not supported.** The actor returns current employees when a roster is requested.\r\n- **Name-only resolution is restricted.** Ambiguous bare names (Notion, Linear, Cal, and similar) return an error row. Pass the LinkedIn URL or the company domain instead (for example `cal.com` for Cal.com).\r\n- **Public pages can rate-limit.** If LinkedIn throttles the company page itself, the actor emits a retryable `rate_limited` error row instead of a company row. If it throttles a roster request, the company row is still returned with a warning. Retry later or narrow the input list.\r\n\r\n## FAQ\r\n\r\n**Do I need a LinkedIn cookie for headcount?**\r\nNo. Company name, LinkedIn-reported employee count, size band, followers, industry, HQ, type, website, address, about, specialties, and logo come from the public company page.\r\n\r\n**When do I need a cookie?**\r\nOnly for the employee roster. Set `includeEmployees` to `true` and add a valid `li_at` value or full cookie export. The cookie is never required for the company row.\r\n\r\n**Why did I get an error row instead of employees?**\r\nThe run tells you which case applies: `cookie_missing` (no cookie), `cookie_invalid` (expired or rejected session), `company_id_unresolved` (the roster filter could not be mapped), `roster_rate_limited` (LinkedIn returned 999/429), or `roster_request_budget_reached` (the ~250-request run budget was used). Company headcount is still returned whenever the page resolves.\r\n\r\n**Why does the employee count disagree with the size band?**\r\nLinkedIn shows two independent fields. A company can report 7,000 employees while its self-selected band says 501–1,000. The actor publishes both and labels the count `high`, `medium`, or `low` confidence rather than presenting either as audited.\r\n\r\n**Why is the roster smaller than the company's headcount?**\r\nLinkedIn caps a single query at 2,500 visible results and serves 10 per page; the daily request limit is about 250. For a large employer, the roster is a sample. Raise `maxEmployees`, split the request with `startPage`, or narrow the filters.\r\n\r\n**Why did my company name resolve to a different company?**\r\nSome names are shared by several LinkedIn pages. The actor refuses the low-confidence name match and asks for a URL or domain. For example, `notion.so` resolves to the right Notion page, while the name alone is treated as ambiguous.\r\n\r\n**Can I get email addresses?**\r\nOnly if LinkedIn explicitly shows an email in the result. The actor does not guess or construct emails, so most records have no email field.\r\n\r\n**Can I get tenure?**\r\nOnly when LinkedIn exposes a duration for the person. Otherwise `tenure` and `tenureYears` are omitted instead of estimated.\r\n\r\n**Does the actor return past employees?**\r\nNo. The roster is current employees only.\r\n\r\n**Is this affiliated with LinkedIn?**\r\nNo. This is an independent, third-party actor. It uses publicly visible company pages and, when you supply one, your own LinkedIn session for the roster. You are responsible for how you use the data.\r\n",
      "input": {
        "title": "LinkedIn Company Headcount & Team Directory Scraper Input",
        "description": "Provide at least one company URL, domain, or name. Headcount and firmographics work without a cookie; employee rows are optional and require your own LinkedIn session cookie.",
        "type": "object",
        "schemaVersion": 1,
        "properties": {
          "companyUrls": {
            "title": "Company LinkedIn URLs",
            "type": "array",
            "description": "LinkedIn company page URLs. Accepts https://www.linkedin.com/company/stripe/, linkedin.com/company/stripe, or company/stripe.",
            "editor": "stringList",
            "default": [],
            "prefill": []
          },
          "companyDomains": {
            "title": "Company domains",
            "type": "array",
            "description": "Company website domains, e.g. stripe.com or notion.so. The resolver follows LinkedIn's page website to pick the correct same-name company.",
            "editor": "stringList",
            "default": [],
            "prefill": [
              "stripe.com"
            ]
          },
          "companyNames": {
            "title": "Company names",
            "type": "array",
            "description": "Company display names, e.g. Stripe or Microsoft. Name-only input is validated; ambiguous bare names (Notion, Linear, Cal) return an error row asking for a URL or domain.",
            "editor": "stringList",
            "default": [],
            "prefill": []
          },
          "includeEmployees": {
            "title": "Include employee roster",
            "type": "boolean",
            "description": "When true, also request the employee roster. Requires a valid LinkedIn session cookie and is capped by LinkedIn at 2,500 visible results per query.",
            "default": false,
            "prefill": false
          },
          "maxEmployees": {
            "title": "Max employees per company",
            "type": "integer",
            "description": "Roster cap per company (1-2500). Ignored when includeEmployees is false. Large companies are sampled.",
            "default": 100,
            "minimum": 1,
            "maximum": 2500,
            "prefill": 100
          },
          "maxItemsTotal": {
            "title": "Max dataset items",
            "type": "integer",
            "description": "Hard cap across company summaries, employee rows, and error rows (1-10000).",
            "default": 500,
            "minimum": 1,
            "maximum": 10000,
            "prefill": 1
          },
          "startPage": {
            "title": "Roster start page",
            "type": "integer",
            "description": "Resume the roster from this page (1-250, 10 employees per page). Use it to continue a capped run.",
            "default": 1,
            "minimum": 1,
            "maximum": 250,
            "prefill": 1
          },
          "titleKeywords": {
            "title": "Title / headline keywords",
            "type": "string",
            "description": "Roster filter: free-text role or headline match, e.g. Software Engineer or VP Sales. Cookie roster only.",
            "editor": "textfield",
            "prefill": ""
          },
          "location": {
            "title": "Location",
            "type": "string",
            "description": "Roster filter: best-effort location match on the employee's LinkedIn location, e.g. London. Cookie roster only.",
            "editor": "textfield",
            "prefill": ""
          },
          "seniorityLevels": {
            "title": "Seniority levels",
            "type": "array",
            "description": "Roster filter: one or more LinkedIn seniority levels. Empty means all levels. Cookie roster only. Allowed values: Entry, Associate, Mid-Senior, Director, Executive.",
            "editor": "stringList",
            "items": {
              "type": "string"
            },
            "default": [],
            "prefill": []
          },
          "functions": {
            "title": "Job functions",
            "type": "array",
            "description": "Roster filter: one or more LinkedIn job functions. Empty means all functions. Cookie roster only. Allowed values: Engineering, Sales, Marketing, Operations, Finance, Human Resources, Design, Product, Customer Service, Information Technology, Legal, Other.",
            "editor": "stringList",
            "items": {
              "type": "string"
            },
            "default": [],
            "prefill": []
          },
          "connectionDegree": {
            "title": "Connection degree",
            "type": "string",
            "description": "Roster filter: restrict to 1st, 2nd, or 3rd+ degree connections. Cookie roster only.",
            "enum": [
              "",
              "F",
              "S",
              "O"
            ],
            "enumTitles": [
              "All connections",
              "1st degree only",
              "2nd degree only",
              "3rd degree+"
            ],
            "default": "",
            "prefill": ""
          },
          "language": {
            "title": "Profile language",
            "type": "string",
            "description": "Roster filter: primary profile language. Cookie roster only.",
            "enum": [
              "",
              "en",
              "es",
              "fr",
              "de",
              "pt",
              "it",
              "nl",
              "zh",
              "ja"
            ],
            "enumTitles": [
              "Any language",
              "English",
              "Spanish",
              "French",
              "German",
              "Portuguese",
              "Italian",
              "Dutch",
              "Chinese",
              "Japanese"
            ],
            "default": "",
            "prefill": ""
          },
          "cookies": {
            "title": "LinkedIn cookie (optional)",
            "type": "string",
            "description": "Optional LinkedIn session cookie for the employee roster. Accepts the li_at value or a full cookies JSON array. Never required for headcount/firmographics.",
            "editor": "textarea",
            "isSecret": true
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Optional advanced override. The actor works without a proxy and chooses a working connection automatically.",
            "editor": "proxy"
          }
        }
      },
      "output": {
        "actorOutputSchemaVersion": 1,
        "title": "LinkedIn Company Headcount & Team Directory Scraper Output",
        "description": "Company summaries with LinkedIn-reported headcount and firmographics, optional employee roster rows, and explicit error rows for unresolved or cookie-blocked inputs.",
        "properties": {
          "records": {
            "type": "string",
            "title": "Company headcount and employee records",
            "description": "Dataset containing company summary rows, employee rows, and error rows.",
            "template": "{{links.apiDefaultDatasetUrl}}/items"
          }
        }
      },
      "storages": {
        "dataset": {
          "actorSpecification": 1,
          "title": "Company headcount and employee records",
          "views": {
            "overview": {
              "title": "Company headcount and employee records",
              "transformation": {
                "fields": [
                  "recordType",
                  "companyName",
                  "linkedinEmployeeCount",
                  "companySizeRange",
                  "followerCount",
                  "industry",
                  "name",
                  "currentTitle",
                  "profileUrl"
                ]
              },
              "display": {
                "component": "table",
                "properties": {
                  "recordType": {
                    "label": "Type",
                    "format": "text"
                  },
                  "companyName": {
                    "label": "Company",
                    "format": "text"
                  },
                  "linkedinEmployeeCount": {
                    "label": "Employees (LinkedIn)",
                    "format": "number"
                  },
                  "companySizeRange": {
                    "label": "Size band",
                    "format": "text"
                  },
                  "followerCount": {
                    "label": "Followers",
                    "format": "number"
                  },
                  "industry": {
                    "label": "Industry",
                    "format": "text"
                  },
                  "name": {
                    "label": "Employee",
                    "format": "text"
                  },
                  "currentTitle": {
                    "label": "Title",
                    "format": "text"
                  },
                  "profileUrl": {
                    "label": "Profile URL",
                    "format": "link"
                  }
                }
              }
            }
          }
        }
      }
    },
    "buildNumber": "2.0.1",
    "imageDigest": "ee0a0dfe6b12e6ed875ab4b7be286a366f39b6efe902e594cfc3bbe5dc5c71a3",
    "actVersion": {
      "sourceType": "SOURCE_FILES",
      "buildTag": "latest",
      "versionNumber": "2.0"
    },
    "usage": {
      "ACTOR_COMPUTE_UNITS": 0.014237777777777778
    }
  }
}