# LinkedIn Profile Search + Email ✅ No Cookies (`atomus/linkedin-profile-search`) Actor

🔍 Search 500M+ people by job title, seniority, skills, location and company, and get each one back as a full profile: work history, education, skills, languages and badges. Optional verified email per person. Max results goes up to 10,000 per run, and you pay per profile returned.

- **URL**: https://apify.com/atomus/linkedin-profile-search.md
- **Developed by:** [Atomus APIs](https://apify.com/atomus) (community)
- **Categories:** Lead generation, Social media, Automation
- **Stats:** 1 total users, 1 monthly users, 92.9% runs succeeded, 2 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $6.00 / 1,000 profile 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/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 Profile Search + Email

<table width="100%" style="border:none;border-radius:10px;background:#120306">
<tr><td style="padding:34px;border:none">
<span style="color:#F59E0B;font-size:13px;font-weight:700;letter-spacing:2px">LINKEDIN PROFILE SEARCH &nbsp;&bull;&nbsp; LINKEDIN PEOPLE SEARCH API</span><br><br>
<span style="color:#F5F5F6;font-size:40px;font-weight:800;letter-spacing:-1.2px">Search by who they are.<br>Get the whole profile.</span><br><br>
<span style="color:#D6D3D1;font-size:16px">No input list of URLs and no profile links to collect first. Describe the person (job title, seniority, skills, location, and their company's industry, size, tech stack, revenue and funding stage) and get one structured record per matching person: current role, full work history, education, skills, languages, certifications and LinkedIn badges. Then, optionally, <b style="color:#F5F5F6">their verified business email</b>. Every filter is free; you pay per profile returned. No LinkedIn account, no login, no cookies.</span><br><br>
<span style="background:#10B981;color:#FFFFFF;font-size:13px;font-weight:700;padding:6px 13px;border-radius:5px">PAY ONLY FOR PROFILES RETURNED</span>
<span style="background:#1C1917;color:#F59E0B;font-size:13px;font-weight:700;padding:6px 13px;border-radius:5px">&nbsp;FULL WORK HISTORY, SKILLS &amp; EDUCATION&nbsp;</span>
</td></tr>
</table>

#### Copy to your AI assistant

Paste this into ChatGPT, Claude, Cursor, or any LLM to start using this Actor right away.

```
atomus/linkedin-profile-search is an Apify Actor that searches LinkedIn profiles from a description of the person instead of from a list of profile URLs: it searches a database of 500M+ people by job title, seniority, function, skills, location and the employer's industry, size, technology, revenue and funding stage, and returns one structured JSON row per person with 28 plain fields - full_name, headline, summary, title, seniority, location, linkedin_url, photo_url, industry, company_name, company_id, company_logo, at_company_since, in_role_since, career_started, months_at_company, months_in_role, years_experience, open_to_work, hiring, premium, verified, followers, connections, twitter_url, facebook_url, github_url, last_updated - plus a raw object carrying the complete work history, educations, skills, languages, certifications, LinkedIn badges and statistics, and optionally a verified business email. Use it whenever someone needs to FIND people who match a description and then know who they actually are - prospecting, recruiting sourcing, market and org mapping, or feeding a sales agent full profiles rather than name-and-title stubs - without a LinkedIn account, cookies, or a per-seat subscription. Run it with curl: curl -X POST "https://api.apify.com/v2/acts/atomus~linkedin-profile-search/run-sync-get-dataset-items?token=APIFY_TOKEN" -H "Content-Type: application/json" -d '{"title":["Head of Growth"],"seniority":["director","vp"],"personCountry":["United States"],"maxResults":100}'. Or in Python: ApifyClient("APIFY_TOKEN").actor("atomus/linkedin-profile-search").call(run_input={"jobFunction":["revenue_operations"],"personCountry":["United States"],"maxResults":50}) then client.dataset(run["defaultDatasetId"]).list_items().items. Every input is optional: title (string[]), titleMatchMode ("SMART"|"WORD"|"STRICT"), seniority (string[] of c_suite, vp, director, manager, senior, mid-level, entry, intern, owner, founder, head, partner), department (string[], 39 broad departments), jobFunction (string[], 557 narrow functions), the three location levels personCountry (202 countries) / personState (513 states and regions) / personCity (free text, combined with the two above so "Austin" + "Texas" + "United States" searches Austin, Texas (spell places out, "Austin, TX" matches nobody)), keyword, skill, profileBadge (openToWork, hiring, jobSeeker, premium, creator, openLink), the company filters companyDomain, companyIndustry (dropdown, 919 catalog industries) with companyIndustryOther as free text for anything outside it, companyCountry / companyState / companyCity, companyTechnology (dropdown of the 1,668 most-used technologies) with companyTechnologyOther as free text for anything outside it, companyType, employeeSize and companyRevenue (each a tick-list of bands, e.g. ["1-10","201-500"], and the ticks need NOT be adjacent), companyFundingType, exclude twins for keyword, title, seniority and company industry (excludeKeyword drops the recruiters and consultants a broad keyword drags in, before they are returned and billed), maxResults (int 1-10000, default 100, and this is your spend cap), skipFirst (int, default 0: skip the first N matches of the SAME search and start there, so a second run continues where the first stopped instead of paying for those people again; every row carries total_matches so you know how many are left), findEmail (bool, adds a verified business email per person, paid Apify plans only, and much slower) and includeCompanyDetails (bool, adds a company_details firmographic block). Fields no longer in the form still work when sent by API: minEmployees, maxEmployees, minRevenue, maxRevenue, fullName, previousTitle, certification, language, degree, fieldOfStudy, minCurrentJobYears, minTotalExperienceYears, companyLinkedin, companyNaics, companySic and the remaining exclude twins. Type free-text values in English: the data is indexed in English, so "Alemanha" matches 0 where "Germany" matches 296,021. Use department OR jobFunction, never both: they combine with OR upstream, so filling both either changes nothing or widens the search and the bill. Every row carries a status ("success" | "not_found" | "error"); you are charged 0.006 USD per profile returned, plus 0.006 per email actually found and 0.0035 per company_details returned, while not_found and error rows are free. Full input schema, every enum and default, and the complete output field list: GET https://api.apify.com/v2/acts/atomus~linkedin-profile-search/build/default
```

***

### LinkedIn MCP Server: use these Actors from ChatGPT, Claude or Cursor

Point your AI assistant at Atomus and it can map a market on its own: find the people, read their full profiles, and enrich the companies behind them. No glue code, no scraping logic in your prompts.

```json
{
  "mcpServers": {
    "atomus": {
      "url": "https://mcp.apify.com?tools=atomus/linkedin-profile-search,atomus/linkedin-profile-scraper,atomus/linkedin-company-employees,atomus/linkedin-company-scraper",
      "headers": { "Authorization": "Bearer YOUR_APIFY_TOKEN" }
    }
  }
}
```

Then ask, in plain language:

> "Find 100 heads of revenue operations at Series B software companies in the US, then pull the full firmographics for every company they work at."

That one sentence uses two Actors in a row. Pinning the `tools=` list is what keeps your assistant on these Actors instead of reaching for whatever scraper it finds first.

***

### How to search LinkedIn profiles

#### Find a role in one query

```json
{
  "title": ["Head of Marketing"],
  "seniority": ["director", "vp"],
  "companyIndustry": ["software"],
  "employeeSize": ["51-100", "101-200", "201-500", "501-1000"],
  "personCountry": ["United States"],
  "maxResults": 100
}
```

Person filters and company filters combine with AND, so each one you add narrows the list. Every filter here is free: only the profiles that come back are billed.

#### Search by skill instead of by title

```json
{ "skill": ["Kubernetes", "Terraform"], "seniority": ["senior", "manager"], "personCountry": ["Germany"], "maxResults": 100 }
```

Titles lie and vary by company; skills are what the person listed about themselves. This is the search a recruiter wants and a title-only tool cannot run.

#### Target a niche function, not a whole department

```json
{ "jobFunction": ["revenue_operations"], "personCountry": ["United States"], "maxResults": 100 }
```

Measured live: the `sales` department matches 28,449,940 people, while the `revenue_operations` function matches 86,195. Use `jobFunction` when you want the niche and leave `department` empty.

#### People at companies running a specific technology

```json
{
  "seniority": ["c_suite", "vp"],
  "companyTechnology": ["salesforce"],
  "companyIndustry": ["financial services"],
  "maxResults": 200
}
```

`companyTechnology` and `companyIndustry` only accept values from the supported catalogs (`salesforce`, `react`, `software`, `financial services`), so a free-text guess quietly matches nothing.

#### Catch companies at the moment they start hiring and spending

```json
{
  "title": ["Head of Sales", "VP Sales"],
  "companyFundingType": ["series_a", "series_b"],
  "employeeSize": ["11-20", "21-50", "51-100", "101-200"],
  "maxResults": 150
}
```

Funding stage plus headcount is the timing filter: a company that just raised and is still small is the one about to build a team.

#### Filter on hiring and open-to-work signals

```json
{ "profileBadge": ["openToWork"], "skill": ["React"], "personCountry": ["Portugal"], "maxResults": 100 }
```

`openToWork` and `hiring` are LinkedIn's own badges, so they are current-state signals: who is open to moving, and who is actively recruiting.

#### Add the verified business email

```json
{
  "title": ["Account Executive"],
  "companyIndustry": ["software"],
  "personCountry": ["United Kingdom"],
  "maxResults": 100,
  "findEmail": true
}
```

Emails are a paid add-on on paid Apify plans, charged only when an email is actually found. The run gets much slower and the first rows take minutes: see the warning under **Input** before you turn it on.

#### Everyone at a named account list

```json
{
  "companyLinkedin": [
    "https://www.linkedin.com/company/stripe",
    "https://www.linkedin.com/company/figma"
  ],
  "seniority": ["director", "vp", "c_suite"],
  "maxResults": 200
}
```

`companyLinkedin` pins exact companies. `companyDomain` is broader and also drags in subsidiaries.

***

### Input

Every parameter is optional. Leave them all empty and the search is unconstrained, capped only by `maxResults`.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `maxResults` | integer | `100` | 1 to 10,000 profiles. This is your hard spend cap: you pay per profile returned, so a run can never cost more than this. |
| `title` | string\[] | (none) | Current job titles to match, e.g. `["Account Executive"]`. |
| `titleMatchMode` | string | `SMART` | `SMART` (fuzzy, catches "Sr. Software Engineer"), `WORD` (whole words), `STRICT` (exact title). Also applies to `excludeTitle`. |
| `seniority` | string\[] | (none) | `c_suite`, `vp`, `director`, `manager`, `senior`, `mid-level`, `entry`, `intern`, `owner`, `founder`, `head`, `partner`. |
| `department` | string\[] | (none) | 39 broad departments (35 current plus 4 legacy aliases), e.g. `sales`, `marketing`, `engineering_technical`. |
| `jobFunction` | string\[] | (none) | 557 narrow functions, each prefixed by its department: `Sales › Revenue Operations`, `Medical Health › Clinical Trials`. |
| `findEmail` | boolean | `false` | Add-on: a verified business email per person. Paid Apify plans only. Billed only when an email is found. |
| `includeCompanyDetails` | boolean | `false` | Add-on: the full firmographic record of each person's current company, in `company_details`. Billed per profile that returns a company. |

**Free person filters:** `personCountry`, `personState`, `personCity`, `keyword` (headline / summary text), `skill`, `profileBadge` (`openToWork`, `hiring`, `jobSeeker`, `premium`, `creator`, `openLink`).

**Free company filters:** `companyCountry`, `companyState`, `companyCity`, `companyDomain`, `companyIndustry`, `companyTechnology`, `companyType` (`public_company`, `privately_held`, `self_owned`, `self_employed`, `partnership`, `non_profit`, `educational`, `government_agency`), `employeeSize`, `companyRevenue`, `companyFundingType` (19 stages from `pre_seed` and `angel` through `series_a`–`series_f`, `private_equity`, `ipo` and `post_ipo`).

**Free exclusions:** `excludeKeyword`, `excludeTitle`, `excludeSeniority`, `excludeCompanyIndustry`. Exclusion happens upstream, so an excluded person is never returned and never billed.

> **`excludeKeyword` is what keeps a broad keyword affordable.** Searching `keyword: ["payments"]` also brings in every recruiter and consultant who wrote *payments* in their headline, and you pay for those rows because billing is per profile returned. Excluding drops them before they are returned. Measured live on the c-suite baseline of 8,628,955: `payments` alone matches 6,912, and `payments` minus `recruiter` matches 6,911. It searches the same place `keyword` does (headline and summary), so type it in English too.

> **Company size and revenue are one tick-list each, and the ticks do not have to be next to each other.** `employeeSize` takes any of `1-10`, `11-20`, `21-50`, `51-100`, `101-200`, `201-500`, `501-1000`, `1001-2000`, `2001-5000`, `5001-10000`, `10000+`; `companyRevenue` takes `0-100000` through `10000000000+`. Ticking `1-10` and `201-500` returns exactly those two groups and none of the companies in between, in a single search. Measured live on the c-suite baseline: `1-10` alone matches 1,285,255 and `201-500` alone 349,539, and the two together come back as 1,634,794, the exact sum, not the 3,191,599 that searching 1 to 500 returns.

**Filters that still work but are no longer in the form.** The form was cut from 58 fields to 29 so that the ones that matter are findable. These keep working exactly as before in a saved task or an API call, they are simply not rendered any more: `minEmployees`, `maxEmployees`, `minRevenue`, `maxRevenue` (superseded by the two band tick-lists above, and ignored as a pair as soon as a band is ticked), `fullName`, `previousTitle`, `certification`, `language`, `degree`, `fieldOfStudy`, `minCurrentJobYears`, `minTotalExperienceYears`, `companyLinkedin`, `companyNaics`, `companySic`, `location`, `companyLocation`, and the exclude twins `excludeDepartment`, `excludeJobFunction`, `excludePersonCountry`, `excludePersonState`, `excludePersonCity`, `excludeCompanyCountry`, `excludeCompanyState`, `excludeCompanyCity`, `excludeCompanyTechnology`, `excludeCompanyType`, `excludeLocation`, `excludeCompanyLocation`.

> **Type free-text values in English.** Anything you type by hand (`title`, `keyword`, `skill`, `personCity`, `companyCity`) goes to the search as written, and the data is indexed in English. Measured live: `Germany` matches 296,021 c-suite people and `Alemanha` matches 0; `United States` matches 2,905,694 and `Estados Unidos` matches 0. Watch out for the quiet version of this: `Spain` matches 109,723 and `Espanha` matches **2**, which looks like a working run rather than an empty one. Casing and accents are safe: `São Paulo`, `Sao Paulo` and `sao paulo` all match the same 69,452.

> **Department and Job function are the same filter at two levels of detail. Use one or the other, never both.** They combine with OR upstream, so filling both either changes nothing (measured live: `sales` alone matches 28,449,940 people, and `sales` + `revenue_operations` matches 28,449,940 too, because the function already sits inside the department) or *widens* your results and your bill (a function from a different department gets ADDED). Want a whole department? Use `department`. Want a niche? Use `jobFunction` and leave `department` empty. This does **not** apply to the exclude twins, where combining them legitimately drops both groups.

> **A continent works too.** `personCountry` and `companyCountry` list the six continents above the 202 countries, because the provider matches them: `Europe` returns 2,135,173 people and `North America` 3,354,584. Named blocs do not: `European Union`, `Latin America`, `Middle East` and `Nordics` all match nobody, so they are not offered.

> **Location is three fields, not one: country, state and city.** They combine into a single place, so country `United States` + state `Texas` + city `Austin` searches Austin, Texas. Country and state are dropdowns; city is free text because no usable list of every city exists. **Spell places out.** Measured live: `Austin, TX` matches 0 people and `Austin, Texas` matches 23,273; `London, UK` matches 0 and `London` matches 114,442. The same applies to the company side (`companyCountry`, `companyState`, `companyCity`).

> **`companyIndustry` and `companyTechnology` are dropdowns of the data source's own catalog:** all 919 industries, and the 1,668 technologies used by 500+ companies out of the 16,041 it knows. The option values are the source's own lowercase spelling (`software`, `salesforce`), which is what these fields already accepted, so an existing API call keeps working. The LinkedIn-style label is the wrong one: `Computer Software` matches 0, `software` matches 161,323. For a value outside either dropdown, use `companyIndustryOther` or `companyTechnologyOther`: both are free text and are merged into the same filter. They matter because the option lists are a snapshot, and Apify refuses a run whose value is not in a field's list, so an industry the data source adds later would stop a saved run rather than merely not filter it.

> **`companyNaics` and `companySic` need the full code.** `541511` and `7372` work; the sector prefixes `54` and `73` match nothing at all. Both are API-only now, listed above.

> **⏳ The email add-on makes a run take minutes instead of seconds.** Email lookup is an asynchronous batch job on the provider's side. Up to 100 profiles it is submitted in one piece and every result arrives together at the finish, so the dataset stays empty until then. Above 100 the emails are bought 100 at a time and each page is delivered as soon as it is verified, so rows appear as the run goes. Either way, watch the run status message: it reports how many emails have been found so far. Do not abort. If you do stop the run, hit **Resurrect** in the Apify console: it resumes from its checkpoint, nothing is re-submitted, and nothing is charged twice.

***

### What data does the LinkedIn Profile Search return?

One row per person, each carrying a `status` (`success` | `not_found` | `error`). The dataset opens with **37 columns**: 28 plain fields describing the person, including how long they have been in the role, plus the add-on fields, the run status and `raw`, which carries the complete profile underneath. Every promoted field below is pulled out of that same person record, so none of them costs an extra credit.

| Group | Fields |
|---|---|
| **Identity** | `full_name` · `headline` · `summary` · `title` (current role) · `seniority` · `location` · `linkedin_url` · `photo_url` · `industry` |
| **Company** | `company_name` · `company_id` · `company_logo` |
| **Tenure** | `at_company_since` · `in_role_since` · `career_started`, and the same three as durations: `months_at_company` · `months_in_role` · `years_experience` |
| **Signals** | `open_to_work` · `hiring` · `premium` · `verified` · `followers` · `connections` |
| **Other profiles** | `twitter_url` · `facebook_url` · `github_url` |
| **Email (add-on)** | `email` · `email_status` (e.g. `VALID`), present only when `findEmail` is on **and** a deliverable email was found |
| **Company details (add-on)** | `company_details`, the full firmographic block: funding rounds, every office, complete tech stack, industries, revenue band. Present only when `includeCompanyDetails` is on and the person has a company |
| **Full profile** | `raw`: `profile` (name, headline, summary, picture, industry), `position_groups` (complete work history with company, dates and titles), `educations`, `skills`, `languages`, `certifications`, `member_badges`, `statistics` (follower and connection counts), `volunteer_experiences`, `link` (LinkedIn and other profile URLs) |
| **Freshness** | `last_updated`, when the upstream source last refreshed this person (`YYYY-MM-DD`) |
| **Provenance** | `_metadata.extracted_at`, ISO timestamp of the lookup |

Firmographics live **only** in `company_details`, the paid add-on. They are stripped out of `raw`, so a run without the add-on never receives them.

#### Example row

```json
{
  "status": "success",
  "full_name": "Leonardo Specht",
  "headline": "SWE @ Stripe | Ex Amazon, Meta",
  "title": "Software Engineer",
  "company_name": "Stripe",
  "location": "Dublin, County Dublin, Ireland, Europe",
  "seniority": "senior",
  "linkedin_url": "https://www.linkedin.com/in/leospecht",
  "photo_url": "https://images.apifyusercontent.com/...",
  "months_at_company": 41,
  "months_in_role": 41,
  "years_experience": 11,
  "open_to_work": false,
  "hiring": false,
  "followers": 4182,
  "last_updated": "2026-07-20",
  "email": "lspecht@stripe.com",
  "email_status": "VALID",
  "raw": {
    "profile": { "full_name": "Leonardo Specht", "summary": "...", "industry": "Computer Software" },
    "position_groups": [
      { "company": { "name": "Stripe" }, "date": { "start": "2022", "end": null },
        "profile_positions": [{ "title": "Software Engineer", "location": "Dublin" }] }
    ],
    "educations": [{ "school": { "name": "UFRGS" }, "degree_name": "BSc", "field_of_study": "Computer Science" }],
    "skills": ["Go", "Kubernetes", "Distributed Systems"],
    "languages": ["English", "Portuguese"],
    "member_badges": { "premium": true, "open_to_work": false }
  },
  "_metadata": { "extracted_at": "2026-09-04T12:44:21.000Z" }
}
```

`status: "not_found"` means the filters matched nobody, and it is free. `status: "error"` carries a plain-language `reason` and an `error_kind`, and is also free.

#### What one real search returned

Measured on a live run, 2026-09-22, searching `Head of Growth` in the United States for 25 people: **25 of 25 came back with a real name**, a company, a title and a seniority, and **20 of 25 carried a business email**, every one of them with `email_status: "VALID"`. The `last_updated` on the first row was 2026-09-21, the day before the run.

One search is one search, not a guarantee, and fill rates move with how niche your filters are. It is worth publishing anyway, because the quiet failure mode of this category is a row that costs the same as a real one and identifies nobody: an anonymous "LinkedIn Member" placeholder, or a name with nothing attached. Every row here carries `status`, and you are billed only for the ones that come back.

#### Where the data comes from

The Actor queries a continuously refreshed database of enriched professional profiles rather than crawling LinkedIn itself, which is why there is no cookie, no session and no ban risk. It filters on each person's **current** title and company, so you get people in the role today, and `last_updated` on every row tells you how recent that record is.

***

### How much does it cost to search LinkedIn profiles?

**$0.006 per profile returned** ($6.00 per 1,000). Pay-per-event: `not_found` and `error` rows are free, and `maxResults` is a hard cap on both the profiles and the bill. There is no per-search fee, so the search itself never costs anything.

| Profiles | Cost |
|---|---|
| 100 | $0.60 |
| 1,000 | $6.00 |
| 2,500 | $15.00 |
| 10,000 | $60.00 |

**Add-ons, only when you turn them on:**

| Add-on | Price | Charged when |
|---|---|---|
| Verified business email | $0.006 per email ($6.00 per 1,000) | Only when a deliverable email is found. A person with no verifiable email is free. Paid Apify plans only. |
| Full company details | $0.0035 per company ($3.50 per 1,000) | Only on profiles that actually return a company. |

There is **no search fee and no floor**: filters cost nothing however aggressive they are, and a run that matches nobody charges nothing. If you set Apify's maximum-charge cap below the cost of a single profile, the run stops before doing any paid work and tells you so, rather than half-billing.

**Free plan:** 10 profiles per calendar month so you can inspect every field before paying. The counter resets on the 1st. Turning the email add-on on from a free plan does not fail the run: the add-on is skipped and never charged, and your profiles are still delivered in full.

***

### What do people use LinkedIn Profile Search for?

- **Prospecting from a description**: name the buyer by title, seniority, industry and company size, and get the people instead of a list of URLs to enrich later.
- **Recruiting sourcing**: search on skills, languages, certifications, degrees, previous titles, years of experience and the `openToWork` badge, then sort the export by `months_in_role` to find the people who have been in the same seat longest.
- **Org and market mapping**: pull every director and above in a function across an industry, and see where they worked before.
- **Technographic targeting**: find decision-makers at companies already running a specific technology, so the pitch writes itself.
- **Funding-triggered outreach**: catch Series A and B companies while the budget is new.
- **Competitor and talent-flow research**: `position_groups` carries the complete work history, so you can see who moved from where.
- **CRM and warehouse enrichment**: pull people by company domain or LinkedIn URL and load structured rows into HubSpot, Salesforce or your database.
- **Territory and market sizing**: tick **Count only** and the match count tells you how many people fit before you spend anything.
- **AI agent context**: hand an agent full profiles rather than name-and-title stubs, so it can qualify without a second lookup.

***

### LinkedIn Profile Search vs cookie-based scrapers vs Apollo-style databases

| | This LinkedIn Profile Search | Apollo / ZoomInfo / Lusha | Cookie-based LinkedIn scrapers |
|---|---|---|---|
| **What you start from** | A description of the person | A description of the person | A search page you are logged into |
| **Pricing** | Pay per profile returned ($0.006), hard spend cap per run | Per-seat subscriptions, usually annual | Subscription plus your own account |
| **Commitment** | None: run once and stop | Contract and seat count | Ongoing tool plus account risk |
| **Account / ban risk** | None (no account, no cookies) | None | High: your LinkedIn account can be restricted |
| **Depth per person** | 28 plain fields (tenure, buying signals, photo, follower counts) plus full work history, educations, skills, languages and certifications in `raw` | Contact record, shallow history | Whatever the search page shows you |
| **Targeting depth** | 557 job functions, 39 departments, 12 seniorities, plus company tech, revenue and funding | Comparable, behind the platform UI | Whatever the search page shows you |
| **Emails** | Add-on, billed only when found | Bundled into plan credits | Rarely, and unverified |
| **Freshness** | `last_updated` on every row, so you can see it | Not exposed per record | Live, at your account's risk |
| **Automation** | API, scheduler and MCP out of the box | API on higher tiers | Manual, or a fragile browser session |
| **Best for** | Pay-as-you-go search, pipelines, AI agents | Teams wanting one all-in-one sales platform | One-off manual list pulls |

***

### FAQ

#### What is a LinkedIn profile search?

A LinkedIn profile search finds people by what is true about them rather than by their URL: job title, seniority, function, skills, location, and the industry, size, technology, revenue and funding stage of the company they work at. You describe the person and get back the matching profiles, instead of collecting profile links first and enriching them one by one.

#### How do I search LinkedIn profiles without an account or cookies?

Fill in the filters and run the Actor. It queries an enriched profile database rather than crawling LinkedIn, so there is no login, no session cookie, no browser and no ban risk. Filters in, structured profile rows out.

#### Do I get real names, or anonymous "LinkedIn Member" rows?

On a live run of 25 people (`Head of Growth`, United States, 2026-09-22) all 25 came back named, with company, title and seniority. That is one search rather than a promise, but it is the thing worth checking in any profile-search tool, because an anonymous row costs the same as a real one and identifies nobody.

#### What is the difference between this and the LinkedIn Profile Scraper?

This one **finds** people from a description and returns their profiles. The [LinkedIn Profile Scraper](https://apify.com/atomus/linkedin-profile-scraper) starts from profile URLs you already have and enriches them. Use this Actor when you do not have the list yet, and that one when you do.

#### Can I use this from ChatGPT or Claude?

Yes, two ways. Paste the "Copy to your AI assistant" block above into any LLM and it will write the call for you. Or connect the **LinkedIn MCP server** config above, and every Atomus Actor becomes a native tool your assistant can call on its own, including chaining several in one request.

#### How much does it cost?

$0.006 per profile returned ($6 per 1,000). Emails are $0.006 each and only when found; full company details are $0.0035 each. `not_found` and `error` rows are free, and the search itself is free. Free Apify plans include 10 profiles per month so you can check the output before paying.

#### How do I control what I spend?

Set `maxResults`. You are charged per profile returned and the run stops at your cap, so the maximum cost of a run is known before you start. Filters themselves are always free, so narrowing the audience only ever lowers the bill. To check a filter set for nothing at all, tick **Count only**: it reports how many people match and pulls none.

#### Should I use Department or Job function?

One or the other, never both. They are two levels of the same taxonomy and combine with OR, so filling both either changes nothing or widens your search. Use `department` for a whole department and `jobFunction` for a niche: that is the difference between all 28,449,940 people in Sales and the 86,195 in Revenue Operations.

#### Do I get email addresses?

Yes, as an opt-in add-on on paid Apify plans. Turn on `findEmail` and each person comes back with a verified business `email` and an `email_status`. You are charged only for emails actually found. Expect the run to take much longer, and up to 100 profiles to produce nothing until the end.

#### Why is my run with emails on taking so long and showing no results?

That is normal up to 100 profiles: at that size the lookup is one batch job, so the results all arrive together at the finish. Above 100 the emails are bought 100 at a time and each page is delivered as soon as it is verified, so rows appear as the run goes. Either way the run status message reports progress, and if you stop the run use **Resurrect**, which resumes from the checkpoint without re-charging.

#### How many profiles can one run return?

Up to 10,000. The underlying source surfaces at most a few thousand people per query, so a very broad search returns what exists rather than the number you asked for, and you are never charged for profiles that do not exist. For a bigger pull, split the query by location, seniority or company size, or use `skipFirst` to continue the same search where the last run stopped.

#### How fresh is the data?

Every row carries `last_updated`, the date the upstream source last refreshed that person, so you always know how stale a record is before you use it. On the 2026-09-22 test run the first row had been refreshed the previous day.

#### Is it legal to use?

This Actor returns professional and business data from licensed and publicly available sources. You are responsible for using the output in line with applicable laws (GDPR/CCPA), platform terms, and your own compliance requirements. It is an independent tool, not affiliated with LinkedIn, Apollo, ZoomInfo or Lusha.

#### Can I run this on a schedule?

Yes. Apify [Schedules](https://docs.apify.com/platform/schedules) run the Actor on a cron interval and [webhooks](https://docs.apify.com/platform/integrations/webhooks) push each finished run into your systems, which is how a funding-stage filter becomes a weekly feed of newly funded accounts.

***

### All Atomus scrapers

<span style="background:#10B981;color:#FFFFFF;font-size:13px;font-weight:700;padding:6px 13px;border-radius:5px">2.4M+ RESULTS DELIVERED</span>

### Support

### ⚠️ Disclaimer

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by LinkedIn Corporation, Apollo.io, ZoomInfo or Lusha. All trademarks are property of their respective owners.

Use the data returned by this Actor in compliance with applicable data protection laws (GDPR, CCPA) and the terms of the platforms involved. Do not use it for spam, harassment, or unlawful purposes.

# Actor input Schema

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

Hard cap on how many profiles to return. This is your spend cap (you pay per profile returned). The run stops once it hits this or runs out of matches. LinkedIn surfaces at most a few thousand per query. ⏱️ With the email add-on on, plan on about 1 hour of run time per 5,000 profiles and set the run timeout to match (Run options, Timeout). A run that reaches its timeout first keeps everything it delivered and tells you how to Resurrect it for the rest.

## `countOnly` (type: `boolean`):

Answer how many people match these filters and stop, without pulling any. Free: nothing is charged, and the count is the whole match total, not capped by Max results. Use it to check a filter set before paying for the real run. Limited to 50 previews per month per account.

## `skipFirst` (type: `integer`):

Already pulled profiles from this exact search and want the next batch? Put how many you already have here and the run starts right after them, so you never pay twice for the same profile. Leave it at 0 to start from the top. Every profile comes back with total\_matches, the size of the whole list, so you always know how much is left. Keep the filters identical: a different search is a different list.

## `sectionRole` (type: `string`):

UI section

## `title` (type: `array`):

Match people whose CURRENT title contains any of these, e.g. "Software Engineer", "Account Executive". Leave empty for all titles. Write titles in English: the data source only indexes English job titles.

## `titleMatchMode` (type: `string`):

SMART = fuzzy (recommended, catches "Sr. Software Engineer"). WORD = whole words. STRICT = exact title only. Also applies to the Exclude titles filter below.

## `seniority` (type: `array`):

Keep only these seniority levels. Leave empty for all.

## `department` (type: `array`):

Keep only people in these broad departments, the ENTIRE department. Use this OR "Job function", never both: measured live, Sales alone matches 28,449,940 people and Sales + Revenue Operations matches 28,449,940 too, because the function already sits inside the department. A function from a DIFFERENT department gets ADDED to your results instead (the two combine with OR), widening your search and your bill, never narrowing it.

## `jobFunction` (type: `array`):

Keep only people in these specific job functions. Pick these INSTEAD of a department when you want precision: Revenue Operations (86,195 people) rather than all of Sales (28,449,940). Every option is prefixed with its department, so typing "sales" narrows the list to the ~20 sales functions instead of scrolling all 557. Leave "Department" empty when you use this: filling both either changes nothing or widens your results.

## `excludeTitle` (type: `array`):

Drop people whose CURRENT title matches any of these (uses the Title match mode above), e.g. exclude "intern", "assistant". Leave empty to skip. Write titles in English, same as the field above.

## `excludeSeniority` (type: `array`):

Drop people at these seniority levels. Leave empty to skip.

## `sectionPersonLocation` (type: `string`):

UI section

## `personCountry` (type: `array`):

Keep only people living in these countries. Pick from the list: every option is a value this data source is known to accept. Typing a place it does not know returns nobody at all. Leave empty for all.

## `personState` (type: `array`):

Keep only people living in these states, provinces or regions. Combined with the country above. Pick from the list: every option is a value this data source is known to accept. Typing a place it does not know returns nobody at all. Leave empty for all.

## `personCity` (type: `array`):

Keep only people living in these cities. Free text, because there is no usable list of every city. It is combined with the country and state you picked above, so "Austin" with state "Texas" and country "United States" is sent as "austin, texas, united states". Spell the city out: "Austin, TX" returns nobody, "Austin, Texas" returns thousands. Leave empty for all. Write the city in English. "Munich" works, "Munchen" does not, and a city name in your own language can return a handful of wrong people instead of none, which is harder to notice.

## `sectionPersonExtras` (type: `string`):

UI section

## `keyword` (type: `array`):

Free-text keywords matched in the person's headline/summary, e.g. "kubernetes", "payments". Leave empty to skip. Write keywords in English: profiles are indexed in English.

## `excludeKeyword` (type: `array`):

Drop people whose headline/summary matches any of these, e.g. search "payments" but exclude "recruiter", "consultant". Excluded people are never returned, so you are never charged for them. Leave empty to skip. Write keywords in English, same as the field above.

## `skill` (type: `array`):

Free-text skills the person lists, e.g. "Kubernetes", "Salesforce". Leave empty to skip. Write skills in English: "machine learning", not "aprendizado de maquina".

## `profileBadge` (type: `array`):

Keep only people carrying these LinkedIn badges. "hiring" and "openToWork" are strong intent signals. Leave empty for all.

## `companyDomain` (type: `array`):

Keep only people at companies with these website domains, e.g. "stripe.com". Broad match (also drags in subsidiaries). Leave empty for all.

## `companyIndustry` (type: `array`):

Keep only people whose company is in these industries. Every option is one of the 919 industry names this data source publishes, so nothing you pick can come back empty for not existing. Typing a LinkedIn-style label instead, like "Computer Software" or "Information Technology & Services", returns nobody. Leave empty for all.

## `companyIndustryOther` (type: `array`):

For an industry the dropdown above does not offer. The dropdown holds the data source's catalog as it stood when this build shipped, and that catalog grows, so a value it has added since is REJECTED by the dropdown, which stops the run rather than merely not filtering it. Type it here instead. Spell it the way the source does: lowercase, and its own vocabulary rather than the LinkedIn label ("software", not "Computer Software"). Leave empty unless the dropdown was missing something. Write it in English and in the wording the industry list above uses, since this field is matched against the same catalog.

## `excludeCompanyIndustry` (type: `array`):

Drop people whose company is in these industries. Excluded rows are never returned, so they are never charged. Leave empty to skip.

## `companyTechnology` (type: `array`):

Keep only people whose company uses these technologies. The list holds the 1,668 most widely used technologies in the data source, sorted by how many companies run them, enough to cover an ICP without a dropdown nobody can scroll. Leave empty for all.

## `companyTechnologyOther` (type: `array`):

For a technology the dropdown above does not offer. The data source knows 16,041 technologies and the dropdown carries the 1,668 used by 500+ companies, so a niche tool lives here instead. Spell it the way the source does: lowercase, the plain product name ("outsystems", "retool"). A name it does not know matches nothing rather than erroring. Leave empty unless the dropdown was missing something. Write the product name in English, as the vendor spells it ("HubSpot", "Google Analytics").

## `companyType` (type: `array`):

Keep only people whose company is one of these types. Leave empty for all.

## `employeeSize` (type: `array`):

Tick every company size you want. They do not have to be next to each other: "1 to 10" plus "201 to 500" returns exactly those two groups and none of the companies in between, in one search. Leave empty for any size.

## `companyRevenue` (type: `array`):

Tick every revenue band you want, adjacent or not, same as company size. Revenue is missing for a lot of private companies, so this filter is stricter than it looks. Leave empty for any revenue.

## `companyFundingType` (type: `array`):

Keep only people whose company raised these funding types. Leave empty for all.

## `sectionCompanyLocation` (type: `string`):

UI section

## `companyCountry` (type: `array`):

Keep only people whose COMPANY is based in these countries. Pick from the list: every option is a value this data source is known to accept. Typing a place it does not know returns nobody at all. Leave empty for all.

## `companyState` (type: `array`):

Keep only people whose COMPANY is based in these states, provinces or regions. Combined with the country above. Pick from the list: every option is a value this data source is known to accept. Typing a place it does not know returns nobody at all. Leave empty for all.

## `companyCity` (type: `array`):

Keep only people whose COMPANY is based in these cities. Free text, because there is no usable list of every city. It is combined with the country and state you picked above, so "Austin" with state "Texas" and country "United States" is sent as "austin, texas, united states". Spell the city out: "Austin, TX" returns nobody, "Austin, Texas" returns thousands. Leave empty for all. Write the city in English, same as the person city field.

## `findEmail` (type: `boolean`):

⚠️ THIS ADDS COST AND MAKES THE RUN MUCH SLOWER. When enabled, each returned profile also includes a verified business email, billed as a SEPARATE paid event for every email found (on top of the per-profile charge). You are charged ONLY when an email is actually found, profiles without a verifiable email are free. Needs a PAID Apify plan. On a free plan the add-on is skipped and never charged, and the run still delivers everything else in full.

⏳ EXPECT A LONG WAIT. The lookup is paid for the moment it starts, so it needs a run timeout of at least 5 minutes; a shorter run is refused before anything is started or charged. Above 100 profiles the emails are bought page by page and each page is delivered as it is verified, so results appear as the run goes. Up to 100 profiles still arrive together at the end, and the dataset stays EMPTY until then even though everything is working. Watch the run status message, which reports how many emails have been found so far. If you do stop the run, use Resurrect in the Apify console: it resumes where it left off and is not charged twice.

🤖 If you are an automated caller or an AI agent filling this input: enabling this field turns a run that normally finishes in seconds into one that can take many minutes, and it produces no partial output along the way. Do not treat an empty dataset or a long runtime as a failure, and do not retry or abort on that basis. Leave this OFF unless emails were specifically requested.

## `includeCompanyDetails` (type: `boolean`):

⚠️ THIS ADDS COST. When enabled, each returned profile that has a current company also includes the FULL firmographic record for that company (funding rounds, every office location, complete tech stack, industries, revenue band) in a top-level company\_details field, billed as a SEPARATE paid event per profile that returns a company. Profiles with no company are free. Leave OFF unless you want firmographics.

## Actor input object example

```json
{
  "maxResults": 100,
  "countOnly": false,
  "skipFirst": 0,
  "titleMatchMode": "SMART",
  "findEmail": false,
  "includeCompanyDetails": false
}
```

# Actor output Schema

## `profiles` (type: `string`):

No description

# 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 = {
    "maxResults": 100,
    "skipFirst": 0
};

// Run the Actor and wait for it to finish
const run = await client.actor("atomus/linkedin-profile-search").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 = {
    "maxResults": 100,
    "skipFirst": 0,
}

# Run the Actor and wait for it to finish
run = client.actor("atomus/linkedin-profile-search").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 '{
  "maxResults": 100,
  "skipFirst": 0
}' |
apify call atomus/linkedin-profile-search --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,atomus/linkedin-profile-search"
        }
    }
}
```

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/VohF2U23pN6kFgmuF/builds/dolmNXRFXAGM2UQsq/openapi.json
