Scrape LinkedIn Company Employees for Org Mapping (2026)

Thirdwatch's LinkedIn Company Employees Scraper returns employee lists per company at $0.008 per record — name, title, profile URL, location, seniority. Built for ABM org-mapping, headcount-tracking, talent-acquisition research, and B2B competitive-research targeting buying-committee identification.

Why scrape LinkedIn company employees

ABM org-mapping is the canonical B2B sales workflow. According to LinkedIn's 2024 State of B2B Sales report, the average enterprise buying committee has 6-10 stakeholders across functional roles, and outbound conversion correlates 5-10x with multi-stakeholder targeting vs single-decision-maker outreach. For sales teams running ABM pipelines, recruiter teams researching competitor talent pools, and B2B-buyer-intent platforms, structured employee-list data is essential.

The job-to-be-done is structured. An ABM team maps decision-makers + influencers across 500 target accounts quarterly. A recruiter team identifies senior candidates at 50 competitor companies for talent-pool research. A B2B-buyer-intent platform surfaces multi-stakeholder visibility at signaling accounts. A revenue-ops team enriches Salesforce on a 1K-account ICP list with multi-contact buying-committee data. All reduce to company-handle list + employee pull + per-employee profile-URL enrichment.

How does this compare to the alternatives?

Three options for company employee data:

Approach Cost per 1,000 contacts Reliability Setup time Maintenance
ZoomInfo Org Charts / Lusha $5K–$15K/year per seat High, with email/phone Hours Per-seat license
LinkedIn Sales Navigator (paid) $1,000/seat/year Manual lookups Hours Per-seat per-month
Thirdwatch LinkedIn Company Employees Scraper $8 ($0.008 × 1,000) Production-tested 5 minutes Thirdwatch tracks LinkedIn changes

ZoomInfo Org Charts bundles email/phone enrichment but at high cost. The LinkedIn Company Employees Scraper actor page gives you raw org-mapping data at materially lower per-contact cost. Layer with Hunter or Clearbit for email-enrichment.

How to scrape company employees in 4 steps

Step 1: How do I authenticate against Apify?

Sign in at apify.com (free tier, no credit card), open Settings → Integrations, and copy your personal API token:

export APIFY_TOKEN="apify_api_xxxxxxxxxxxxxxxx"

Step 2: How do I pull employees per company?

Pass LinkedIn company-handle queries.

import os, requests, pandas as pd

ACTOR = "thirdwatch~linkedin-company-employees-scraper"
TOKEN = os.environ["APIFY_TOKEN"]

TARGET_ACCOUNTS = ["stripe", "adyen", "checkout-com",
                   "ramp", "mercury-bank", "rippling",
                   "deel", "linear", "vercel", "modal-labs"]

resp = requests.post(
    f"https://api.apify.com/v2/acts/{ACTOR}/run-sync-get-dataset-items",
    params={"token": TOKEN},
    json={"queries": TARGET_ACCOUNTS, "maxResults": 100},
    timeout=3600,
)
df = pd.DataFrame(resp.json())
print(f"{len(df)} employees across {df.company.nunique()} companies")

10 companies × 100 employees = up to 1,000 records, costing $8.

Step 3: How do I filter to decision-makers + influencers?

Multi-tier function + seniority filter.

import re

DM_TITLE_PATTERNS = re.compile(
    r"\b(VP|Vice President|Chief|CEO|CFO|COO|CTO|Director|Head of|"
    r"Senior Director|Principal|Lead|Staff)\b",
    re.I
)
INFLUENCER_PATTERNS = re.compile(
    r"\b(Manager|Senior Manager|Senior Engineer|Senior Designer)\b", re.I
)

df["is_decision_maker"] = df.headline.fillna("").apply(
    lambda h: bool(DM_TITLE_PATTERNS.search(h))
)
df["is_influencer"] = df.headline.fillna("").apply(
    lambda h: bool(INFLUENCER_PATTERNS.search(h))
)

dms = df[df.is_decision_maker]
print(f"{len(dms)} decision-makers across {dms.company.nunique()} accounts")
print(dms.groupby("company").size().sort_values(ascending=False).head(10))

Decision-maker + influencer cohort enables full buying-committee mapping per account.

Step 4: How do I track headcount over time?

Persist daily snapshots and compute deltas.

import datetime, pathlib, json

ts = datetime.datetime.utcnow().strftime("%Y%m%d")
per_company = (
    df.groupby("company")
    .agg(
        employee_count=("name", "count"),
        engineering=("headline", lambda x: x.str.contains("engineer", case=False, na=False).sum()),
        sales=("headline", lambda x: x.str.contains("sales|account exec", case=False, regex=True, na=False).sum()),
        marketing=("headline", lambda x: x.str.contains("marketing|growth", case=False, regex=True, na=False).sum()),
    )
    .reset_index()
    .assign(snapshot_date=ts)
)
out = pathlib.Path(f"snapshots/li-headcount-{ts}.json")
out.parent.mkdir(parents=True, exist_ok=True)
out.write_text(per_company.to_json(orient="records"))
print(f"Persisted {len(per_company)} per-company headcount snapshots")

Weekly snapshots build per-company headcount + function-mix trajectories useful for ABM-signal generation.

Sample output

A single LinkedIn employee record looks like this. Five rows weigh ~5 KB.

{
  "name": "Jane Doe",
  "headline": "VP Engineering at Stripe",
  "profile_url": "https://www.linkedin.com/in/janedoe",
  "company": "stripe",
  "company_url": "https://www.linkedin.com/company/stripe",
  "location": "San Francisco Bay Area",
  "seniority_inferred": "VP",
  "function_inferred": "Engineering"
}

profile_url is the canonical natural key per employee. headline is the structured title-line LinkedIn shows on the company employees page — consistent with active-current-role data. Pair with LinkedIn Profile Scraper for full profile enrichment (skills, experience, summary, certifications).

Common pitfalls

Three things go wrong in employee-mapping pipelines. LinkedIn visibility limits — companies with 10K+ employees show only top ~1K visible employees due to LinkedIn UI limits; for large enterprises, supplement with title-targeted Google search + LinkedIn URL discovery. Stale current-role data — about 5-10% of LinkedIn employee records show outdated employer (employee left but didn't update profile); cross-check via separate LinkedIn Profile fetch before treating as authoritative. Anonymized profiles — about 5-15% of LinkedIn users show "LinkedIn Member" instead of name due to privacy settings; these can't be enriched directly.

Thirdwatch's actor uses HTTP + Sec-Fetch headers at $5/1K, ~38% margin. Pair with LinkedIn Profile Scraper for deep enrichment and LinkedIn Jobs Scraper for hiring-signal cross-reference. A fourth subtle issue worth flagging: company-page employee lists show employees who have "Stripe" in their current title — but some employees move within a multi-entity organization (Stripe Atlas, Stripe Press, etc) without updating profile employer field, leading to apparent count drift. For accurate parent-company headcount tracking, normalize employer-field variants. A fifth pattern unique to ABM org-mapping: the highest-leverage decision-maker for a sales conversation is often NOT the title that owns the budget — it's the title that owns the technical decision (Director Engineering at a SaaS-buying account, not VP Finance). For accurate ABM enrichment, build a multi-tier function-mapping table per ICP segment. A sixth and final pitfall: LinkedIn Sales Navigator users see different employee-list orderings than guest users — Sales Navigator prioritizes "shared connections" + "recently active" employees; guest scraping (which the actor uses) returns a more neutral list. For ABM-research purposes, guest-list ordering is actually preferable since it's not personalized to the recruiter's network.

Operational best practices for production pipelines

Tier the cadence to match signal half-life. Headcount changes slowly (5-15% annual growth at growth-stage companies) — weekly polling on top ABM targets + monthly on long-tail covers most use cases. 60-80% cost reduction with negligible signal loss.

Snapshot raw payloads. Pipeline cost is dominated by scrape volume, not storage. Persisting raw JSON snapshots lets you re-derive metrics — particularly useful for function-mix-classifier evolution. Compress with gzip at write-time.

Schema validation. Run a daily validation suite asserting expected core fields with non-null rates above 80% (required) and 50% (optional). LinkedIn schema occasionally changes during platform UI revisions — catch drift early. A seventh and final operational pattern unique to this scraper at production scale: cross-snapshot diff alerts. Beyond detecting individual changes, build alerts on cross-snapshot field-level diffs — name changes, category re-classifications, ownership-transfers, status-changes. These structural changes precede or follow material events (acquisitions, rebrands, regulatory issues, leadership departures) and are leading indicators of organization-level disruption. Persist a structured-diff log alongside aggregate snapshots: for each entity, for each scrape, persist (field, old_value, new_value) tuples. Surface high-leverage diffs (name changes, category re-classifications, headcount shifts >10%) to human reviewers; low-leverage diffs (single-record additions, minor count updates) stay in the audit log. This pattern catches signal that pure aggregate-trend monitoring misses entirely.

Related use cases

Frequently asked questions

What's the use case for company employee scraping?

Three primary: (1) ABM org-mapping — for each target account, identify decision-makers + influencers across the buying committee; (2) headcount-trend tracking — monitor target companies' employee count + functional mix shifts as growth-signal; (3) talent-acquisition research — find candidates at competitor companies. For B2B sales, recruiter teams, and ABM pipelines, employee-list scraping is the canonical org-discovery workflow.

What data does the actor return per employee?

Per employee: name, headline (current title at the company), profile URL, location, current employer (the queried company), seniority level (when visible). For deeper enrichment, pass the resulting profile URLs to the LinkedIn Profile Scraper for full profile data (skills, experience, summary). Average company returns 10-100 visible employees per query depending on company size + LinkedIn's privacy settings.

How does LinkedIn's anti-scraping work?

LinkedIn uses Sec-Fetch headers + cookie-based session tracking. Thirdwatch's actor uses HTTP + Sec-Fetch headers to access public company-page data without cookies or login. Production-tested with 90%+ success rate. Failed queries auto-retry. Sustained polling rate: 50-100 employees per minute per proxy IP.

Can I track headcount over time?

Yes. Persist daily snapshots of (company, snapshot_date, employee_count, function_mix) tuples + compute deltas. A 50-person company growing to 80 in 30 days = 60% headcount growth = strong scaling signal. Cross-reference with LinkedIn Jobs Scraper hiring data for full pipeline visibility (postings + actual hires).

How fresh does headcount data need to be?

For ABM target-account monitoring, weekly cadence catches headcount + functional-mix shifts. For high-stakes ABM (M&A targets, IPO candidates), daily cadence. For research-only org-mapping, monthly snapshots suffice. LinkedIn employee counts update with employee profile changes — typical 2-7 day lag from actual hire/departure.

How does this compare to ZoomInfo Org Charts or Lusha?

ZoomInfo Org Charts and Lusha bundle org-mapping with email/phone enrichment + verification at $5K-$15K/year per seat. The actor delivers raw LinkedIn employee data at $0.008/record. For high-volume ABM research or platform-builder use cases, the actor is materially cheaper. For full-stack ABM operations, ZoomInfo Org Charts wins on integration.

Run the LinkedIn Company Employees Scraper on Apify Store — pay-per-record, free to try, no credit card to test.