# LinkedIn People Search Scraper: Emails, No Cookies, 35+ Filters (`b2bsearch/people-database-search`) Actor

LinkedIn people search by title, seniority, employer, company size, industry, past employer, city: 35+ filters, no cookies, no login. Free counts and market breakdowns before you buy, then search rows, full profiles or profiles with emails & phones — below the most used people search on every tier.

- **URL**: https://apify.com/b2bsearch/people-database-search.md
- **Developed by:** [B2B Search Enriched](https://apify.com/b2bsearch) (community)
- **Categories:** Lead generation, Social media, AI
- **Features:** Limited permissions
- **Stats:** 320 total users, 71 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $0.76 / 1,000 person delivereds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 People Search Scraper** with emails and no cookies: search professional profiles by title, seniority, employer, industry and city, count the matches for free, then export them.

> **$0.95 per 1,000 people.** You pay
> per person delivered, never per search page. Counts and market
> breakdowns carry no per-row charge, and repeats and skipped people are
> never billed.

Search a database of over 800 million professional profiles with 35+
filters: title, seniority, employer, employer size, industry and HQ
country, past employer and when they left, career length, tenure, city,
languages. Before you buy a row, ask how many people match and what the
segment looks like (countries, seniority, employer size, industries, top
titles, top employers). That part has no per-row charge: a run pays only
the platform's start fee.

A run takes seconds, needs no login or cookies and has no 2,500-row cap.

### Three modes

| `mode` | What you get | Price |
|---|---|---|
| `people` (default) | the people, one row each | $0.95 per 1,000 rows · $3.20 with the full profile · $8 with emails & phones |
| `count` | how many people match, one row per segment | no per-row charge |
| `market` | the segment's shape: countries, seniority, employer size and industry, career start year, top job titles and employers, personal-email ceiling | no per-row charge |

Typical flow: run `market` to see who is there, change one filter, `count`
again, then switch to `people` and buy exactly the rows you need.

### What people use it for

Each recipe is a complete input you can paste. The numbers come from runs
on 4 October 2026.

#### 1. Size a talent or sales market before you commit

How many data engineers are there in five European countries, and who
employs them?

```json
{
  "mode": "market",
  "countries": ["gb", "de", "es", "nl", "pl"],
  "titleKeywords": ["data engineer"]
}
```

55,157 people: UK 38%, Germany 19%, Spain 17%, the Netherlands 16%,
Poland 10%. 30% work at companies with 1,001–10,000 employees and another
31% at companies above that. 29% work in IT services. At most 15,790 (29%)
have a personal email on record. Cost: the run's start fee, nothing per row.

#### 2. Compare segments side by side

Up to 10 segments in one run. Each one is the input above with a few fields
changed:

```json
{
  "mode": "count",
  "titleKeywords": ["data engineer"],
  "segments": [
    { "name": "Germany", "countries": ["de"] },
    { "name": "Poland", "countries": ["pl"] }
  ]
}
```

Germany 10,275, Poland 5,504. Use the same pattern for "seniors vs
juniors", "fintech vs banking", or "left in 2024 vs 2025". `market` takes
segments too.

#### 3. Hire from a competitor, or follow an ex-customer's champions

People who left a company, where they work now, and when they left:

```json
{
  "countries": ["us"],
  "pastEmployerDomains": ["stripe.com"],
  "leftPastEmployerAfterYear": 2022,
  "maxResults": 500
}
```

6,199 people in the US left Stripe in 2022 or later. People still at the
company are left out: an internal promotion also closes a position, and
about a third of raw matches are people who never left. Set
`stillThereCounts` to keep them. A brand domain resolves to the real
employer, so `meta.com` finds 78,337 former Meta people in the US, not the
114 at a small page that shares the domain.

#### 4. Account-based lists: a few people per company, minus your customers

```json
{
  "countries": ["de", "at", "ch"],
  "titleKeywords": ["head of marketing", "cmo"],
  "employeeCountMin": 50,
  "employeeCountMax": 1000,
  "maxPerCompany": 2,
  "excludeCompanyDomains": ["your-customer-1.com", "your-customer-2.com"]
}
```

At most two people per employer across the whole run. People over the
limit are skipped and not charged.

#### 5. Short titles without the noise

The substring "cto" also matches "director" and "doctor". Switch
`titleMatch` to `word` for short titles:

| Poland, title "cto" | People |
|---|---|
| `titleMatch: substring` | 89,024 |
| `titleMatch: word` | 3,049 |

#### 6. A weekly feed of new people only

Run the same search every week and pick the earlier datasets in
`excludeDatasets`. Everyone you already have is left out at the source,
and anyone who slips through is skipped and never charged twice. Schedule
it in Apify, and each run delivers only people who are new to the segment.

#### 7. Recruiting: tenure, career length, between jobs

```json
{
  "countries": ["pl"],
  "titleKeywords": ["engineering manager"],
  "employerHqCountries": ["us"],
  "currentRoleStartedBeforeYear": 2022,
  "careerStartYearMax": 2014
}
```

Engineering managers in Poland who work for US-headquartered companies,
have been in the role since 2022 or earlier, and started their career by
2014\. Use `onlyBetweenJobs` for people with no current position (their
job title keywords then match the jobs they held), and
`currentRoleStartedAfterDate` for recent job changers.

#### 8. A reproducible research sample

`"sampleSeed": 7` returns one page of up to 100 people spread across the
whole segment, not just the first rows. The same seed always returns the
same people.

### Input

Fill only what you need. A people run needs at least one filter that says
*who* (title, headline, employer, past employer, industry or city): a
country alone matches millions. `count` and `market` accept any filters.

**Where**

- `countries`: up to 60 two-letter codes. `countryGroups`: eu, eea, dach,
  nordics, baltics, benelux, cee, cis, post_soviet, mena, gcc, latam.
  `excludeCountries` removes countries from those lists.
  Several countries (or a group) share the order evenly, one leg per country in the order given; a country that runs short hands its share to the others, so a `dach` run is not all Austria.
- `localityKeywords`: city or region text (san francisco, greater london).

**Who**

- `titleKeywords`: job titles, read as the title tags our dictionary gives them: "head of sales" finds heads in sales in every spelling and language, "cfo" every CFO. A title the dictionary does not know is not searched, and the run names it in a `titles_not_searched` row.
- `headlineKeywords`, plus `headlineAlsoKeywords` when the headline must
  match a word from each list ("head of" or "director", AND "data").
- `seniority`: cxo, vp, director, manager, founder, other. The bucket comes
  from the title, so "CTO", "Chief Technology Officer" and "Head of
  Technology" all count as cxo. Also owner, head, partner, senior, entry and
  intern: With owner, head, partner, senior, entry or intern among them, every chosen level is matched by its title tags on any current title (C-level by the CEO, CFO, CTO… tags), and `other` cannot be added.
- `departments`: the function the person works in, read from their job
  titles (sales, marketing, engineering, hr and 26 more). Combines with
  `seniority` and the title words: a VP in sales is `seniority` vp plus
  `departments` sales.
- `excludeTitleKeywords` drops people by the title tags those titles mean (intern, assistant); `excludeHeadlineKeywords`, `pastTitleKeywords` match words, with `titleMatch` (`substring` or `word`).
- `languages`: two-letter codes. The language data is still being built;
  until it is ready, a run with this field stops with a note and charges
  nothing.

**Employer**

- `companyDomains` (currently there) and `excludeCompanyDomains` (not
  there), up to 1,000 each.
- `employerIndustries`: industry names in either wording, any letter case,
  or taxonomy ids (a sector id covers everything under it). The `valueId`
  column of a market breakdown gives the ids. An everyday word is read as
  the names it stands for ("fintech" as Financial Services): the count's
  note and a free `industries_read_as` row say what each word became. A
  word that fits no industry, a typo included, is left out of the list: the
  run reads the industries it knows and a free `filters_skipped` row names
  the word and the closest industries. Only a list with no industry we
  know stops the run, before anything is charged.
- `employeeCountMin` / `employeeCountMax`. About half the companies on
  file have no headcount; set `includeUnknownEmployerSize` to keep them.
- `employerHqCountries`: where the employer is headquartered, wherever the
  person lives.

**Career**

- `pastEmployerDomains` or `pastEmployerCountries`, with
  `leftPastEmployerAfterYear` / `leftPastEmployerBeforeYear` and
  `stillThereCounts`.
- `careerStartYearMin` / `careerStartYearMax`: years since the first
  recorded position.
- `currentRoleStartedAfterYear`, `currentRoleStartedBeforeYear` (tenure),
  `currentRoleStartedAfterDate` (YYYY-MM).
- `requireCurrentPosition` or `onlyBetweenJobs`; `connectionsMin` /
  `connectionsMax`; `activeAfter`; `updatedAfter` (record updated on or after a date, the row's `updatedAt`); `excludeLowSignal`.

**Run control**

- `mode`, `maxResults` (default 500, up to 50,000; 10,000 on the profile
  tiers), `profileDetail`, `mustHave`, `compact`.
- `segments` and `marketTopN` for count and market runs.
- `maxPerCompany`, `excludeDatasets`, `excludePersonIds`, `sampleSeed`.

### `profileDetail` and `mustHave`

- `row` ($0.95 per 1,000): name, headline, location, the current role and
  employer card, email flags.
- `profile` ($3.20 per 1,000): adds the whole career profile.
- `contacts` ($8 per 1,000 people with a working contact): adds emails,
  phones and social links. A person with no contact that reaches them today
  ships at the $3.20 profile price. In our measurement on 30 September 2026,
  the contacts price applied to 53% of people in the US, 42% in India, 40%
  in France, 33% in the UK and 32% in Germany.

`mustHave` lists what a person must have to be delivered: `email`,
`personalEmail`, `workEmail`, `currentWorkEmail`, `phone`, `github`,
`twitter`, `facebook`. People without it are skipped for free, and one
`skipped_must_have` row says how many. The three email flags work on every
tier; the rest need `contacts`. `personalEmail` also narrows the count.

### Phones, emails and social links for the people you found

Every row carries `profileUrl`, so a list from this Actor goes straight
into our lookups. Buy only the contacts you need, and only for the people
you keep:

| You need | Actor | Price (misses are free) |
|---|---|---|
| Every phone on record, plus name, title and company (US) | [LinkedIn to Phone](https://apify.com/b2bsearch/linkedin-to-phone) | $12 per 1,000 found |
| Email addresses on record | [LinkedIn Email Finder](https://apify.com/b2bsearch/linkedin-email-finder) | $8 per 1,000 at the current employer, $3 for older addresses |
| The full profile with every contact and social link | [Profile Lookup](https://apify.com/b2bsearch/profile-lookup) | $8 per 1,000 |
| X, GitHub or Facebook handles you already have | [Social Handle Lookup](https://apify.com/b2bsearch/social-handle-lookup) | $3.20 per 1,000 found, $8 with contacts |

Or stay in this Actor with `profileDetail: contacts`: $8 per 1,000 people
who have a working contact, and the profile price for everyone else.

**Only need an email per person?** [B2B Leads Finder](https://apify.com/b2bsearch/b2b-leads-finder)
takes the same filters and returns flat lead rows — name, title, company and
a work email at the current company or a personal one — from $1.50 per
1,000 leads. People without such an email are skipped free.

### What you get

| Group | Fields |
|---|---|
| Identity | full name, headline, `profileUrl`, slug, `personId` |
| Current role (flat columns) | `jobTitle`, `companyName`, `companyDomain`, `companyIndustry`, `companyEmployeeCount` — the position your filters matched (title, seniority, size and start year hold for that one job) |
| Other current role (profile tiers) | `primaryTitle`, `primaryCompany` when the profile lists another job first; `_employerUnconfirmed: true` when the profile no longer lists the matched employer |
| All current positions | title, seniority, start year, and a live employer card for each (domain, country, headcount, industry, funding, founding year) |
| Location | city, `countryCode` |
| Email flags | `hasPersonalEmail`, `hasWorkEmail` |
| Signal | `lowSignal`, connection count, first position year |
| Richer tiers | the career profile, plus `email`, `emailType`, `workEmails`, `personalEmails`, `phone`, `phones` |
| Record date | `updatedAt` |
| Market rows | `segment`, `dimension`, `value`, `count`, `share`, `countedBy`, `valueId` |

A market run writes one row per bucket. Excerpt from recipe 1:

| dimension | value | count | share |
|---|---|---|---|
| total | people matching | 55,157 | 100 |
| contact | personal email on record (at most) | 15,790 | 28.63 |
| country | gb | 21,180 | 38.4 |
| employer size | 1001-10000 | 16,837 | 30.53 |
| employer industry | IT Services and IT Consulting | 16,012 | 29.03 |

The Output tab has three views: *Overview*, *Current positions* and
*Market breakdown*.

### Pricing

| Event | Price | When |
|---|---|---|
| Person delivered | $0.00095 | one distinct person, search row |
| Person delivered (full profile) | $0.0032 | `profile`, or `contacts` without a working contact |
| Person delivered (profile + contacts) | $0.008 | `contacts`, with a contact that reaches the person today |
| Counts, market breakdowns, repeats, skipped people | **$0** per row | always; a run pays only the platform start fee |

Prices above are for Apify's Free and Starter plans. Scale plans pay 10%
less and Business plans and up 20% less, applied by Apify automatically; the
Store page quotes the lowest of these as "from".

The data keeps historical snapshots of a person under separate ids (26% of
the rows in one full segment we measured). The Actor remembers who it has
delivered, so a repeat never reaches your dataset or your bill. A snapshot
that still lists a job its person has since left is not delivered at all:
the person's current profile decides.

### Honest limits

- **Titles match as text.** Substring matching is wide and word matching is
  exact. A market breakdown can only use substring matching; with
  `titleMatch: word` it adds a whole-word total on its own row.
- **Market shares of seniority, employer size, industry, title and employer
  count current positions,** so someone with two jobs counts twice and
  those shares can add up past 100%. Top titles and top employers are close
  approximations.
- **"Personal email on record" is a ceiling,** not a promise of delivery.

### With AI agents and MCP

Add it to Claude, ChatGPT, Cursor or any MCP client through the Apify MCP
server:

```
https://mcp.apify.com?tools=b2bsearch/people-database-search
```

In **Apify AI**, the chat in Apify Console, name the Actor in your request and the chat goes
straight to it instead of searching the Store:

```
Use b2bsearch/people-database-search to count CFOs at financial services companies in the UK
```

**Use this Actor when** the task is "find people who…", "how many … are
there in …", "where do … work", "compare … across countries", or "people
who left …". **Do not use it** to look up one known person (use Profile
Lookup) or to get emails for a list of profile URLs you already have (use
LinkedIn Email Finder).

Rules that keep an agent's bill small:

1. Start with `"mode": "count"` or `"mode": "market"`. Neither charges per row.
2. Set `maxResults` to what the user asked for. You pay per row.
3. Use `"compact": true` for rows that go into a context window. Same price,
   about 2 KB per person.
4. Short titles (cto, cfo, vp) need `"titleMatch": "word"`.
5. Every row has a `_status`. A row that is not a person says why in
   `_note` or `_error`.

From request to input:

| The user says | Input |
|---|---|
| "How many fintech CFOs are there in the UK?" | `{"mode":"count","countries":["gb"],"titleKeywords":["cfo"],"titleMatch":"word","employerIndustries":["Financial Services"]}` |
| "Where do Rust engineers in Europe work?" | `{"mode":"market","countryGroups":["eu"],"headlineKeywords":["rust"]}` |
| "25 ex-Google product managers in Berlin" | `{"countries":["de"],"localityKeywords":["berlin"],"titleKeywords":["product manager"],"pastEmployerDomains":["google.com"],"maxResults":25,"compact":true}` |

Input an agent can send as is:

```json
{
  "mode": "people",
  "countries": ["nl"],
  "titleKeywords": ["founder"],
  "maxResults": 25,
  "profileDetail": "row",
  "compact": true
}
```

It also works as a tool in LangChain, CrewAI and the OpenAI Agents SDK, and
as a step in n8n, Make and Zapier through the Apify integrations.

### Ready-made examples

Each one opens with the input filled in; press Try for free and change it to your own.

- [Free Market Size: DACH CTOs at 11–200-Person Companies](https://apify.com/b2bsearch/people-database-search/examples/dach-cto-market-size-free): Free count of CTOs and VPs of Engineering at 11–200-person companies in Germany, Austria and Switzerland, by country, size and industry.
- [Early-Career Software Engineers Who Started After 2020](https://apify.com/b2bsearch/people-database-search/examples/early-career-software-engineers): US software engineers whose first recorded job started in 2021 or later, 99,391 on 31 Oct 2026. For graduate hiring and junior talent pools.
- [Fintech Founders at 1–50-Person Companies, California & Texas](https://apify.com/b2bsearch/people-database-search/examples/fintech-founders-california-texas): Founders of 1–50-person financial-services companies in California and Texas, 12,049 on record on 31 Oct 2026, with title, employer and profile URL.
- [New VPs and Heads of Sales Who Started Since October 2025](https://apify.com/b2bsearch/people-database-search/examples/new-sales-leaders-since-october-2025): US VPs and heads of sales who started their current role in October 2025 or later, 5,870 on record on 31 Oct 2026. A trigger list for outbound.
- [Find Professionals Between Jobs: Open-to-Work Talent](https://apify.com/b2bsearch/people-database-search/examples/professionals-between-jobs): Find people with no current position, filtered by the job they held: 108,941 former product managers in the US on 31 Oct 2026. For recruiters.
- [Compare Sales Team Size Across Companies for Free](https://apify.com/b2bsearch/people-database-search/examples/sales-team-size-by-company-free-count): Count account executives, SDRs and sales managers at any company for free: Salesforce 20,484, HubSpot 3,022, Zendesk 1,456 on 31 Oct 2026.
- [How Many Software Engineers per Country? Free Count](https://apify.com/b2bsearch/people-database-search/examples/software-engineers-by-country-free-count): Free count of software engineer profiles by country: over 1 million each in the US and India, 185,825 in the UK, 166,391 in Canada (31 Oct 2026).

### FAQ

#### How do I get emails for the people I find?

Set `profileDetail` to `contacts`, or add
`mustHave: ["personalEmail"]` to keep only people with a personal mailbox
on record at the row price.

#### Why was my people search run refused?

A people run with only a country (or a country
and a seniority bucket) matches millions. Add a title, headline, employer,
past employer, industry or city, or run `count` first.

#### Can I see the breakdown for more than five countries?

Yes. Facets are
counted five countries at a time and the Actor adds them up for you.

#### Who reads the reviews and issues?

The people who build it, and they are
what we fix first.

### Which actor in this family?

One database behind ten listings. Misses are free on every one of them.

| Actor | Input → output |
|---|---|
| [Profile Lookup](https://apify.com/b2bsearch/profile-lookup) | profile URL → full career profile |
| [Reverse Email Lookup](https://apify.com/b2bsearch/reverse-email-lookup) | email → person, profile URL and employer |
| [Name to Profile](https://apify.com/b2bsearch/name-to-profile) | name + company domain → profile |
| [Social Handle Lookup](https://apify.com/b2bsearch/social-handle-lookup) | GitHub, X/Twitter or Facebook handle → profile |
| [Bulk People Enrichment](https://apify.com/b2bsearch/bulk-people-enrichment) | CSV of emails, URLs, handles or names → profiles |
| [LinkedIn Email Finder](https://apify.com/b2bsearch/linkedin-email-finder) | profile URL → email addresses on record |
| [Work Email Finder](https://apify.com/b2bsearch/work-email-finder) | name + company domain → work email candidates |
| [Company Employees](https://apify.com/b2bsearch/company-employees) | company domain → current staff |
| **People Database Search** (this one) | filters → people, counts and market breakdowns |
| [B2B Leads Finder](https://apify.com/b2bsearch/b2b-leads-finder) | filters → leads with a work or personal email, from $1.50/1k |
| [Company Database Search](https://apify.com/b2bsearch/company-database-search) | filters → companies |

### Free Apify plan

Free accounts get the same rows as paid ones, with three limits. A run delivers
at most 100 results when started from Apify Console and 25 when started through
the API, a schedule or an integration; an account gets 500 dataset rows per calendar
month on this Actor, found rows and misses alike; and a row that finds nothing
carries only its status. Previews and counts, where this Actor offers them, stay
free and outside the monthly allowance. When a limit stops a run, the status
line and the last dataset row say which limit it was, what is left and when it
resets. Any paid Apify plan removes all of this: Starter is $19/month and
includes $19 of usage.

### Feedback and reviews

How did it go? A rating on this Actor's [Reviews page](https://console.apify.com/actors/WsaetcgVbECzOTGec/info/reviews)
tells the next buyer what to expect; we read every word, good or bad. Got a wrong or stale
row? Open the **Issues** tab with the run ID. Issues are public, so leave out
emails, phones and names; the run ID is enough for us to find the row. We
check every report, fix what is ours to fix and answer in the thread.

### Disclaimer

This Actor is an independent product. It is not affiliated with, endorsed by
or sponsored by LinkedIn. It does not access, crawl or scrape any of them at
run time: answers come from our own database of publicly available
professional data, and the network names only describe the kind of data it
covers. To have a person's data removed, open an issue on this Actor with only
the profile link — nothing else is needed, and it is removed from every listing.

# Actor input Schema

## `mode` (type: `string`):

people = the rows, paid per person. count = how many people match, no per-row charge. market = the segment's shape, no per-row charge: countries, seniority, employer size and industry, career start year, top job titles and top employers, plus how many have a personal email. Size and compare first, then buy rows.

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

Stop after this many people (default 500, maximum 50,000; 10,000 on the profile tiers). You pay per person delivered — $0.95 per 1,000 in the row tier — so set it to the number you need. Ignored by count and market modes. Free Apify plan: up to 100 from Console, 25 via the API, and 500 rows per month per account.

## `profileDetail` (type: `string`):

Paid per person, never per search. row = name, title, employer, location and email flags, $0.95 per 1,000; profile = the full career profile, no contacts, $3.20 per 1,000; contacts = plus emails, phones and social links, $8 per 1,000 people with a contact that reaches them today (the rest at the profile price). Profile tiers cap a run at 10,000.

## `mustHave` (type: `array`):

Deliver and charge only people who have all of these; the rest are skipped free and counted in one note row. Personal and work email work on every tier; phone, social profiles and "work email at the current employer" need emails & phones. Personal email also narrows the free count.

## `compact` (type: `boolean`):

Returns a short row instead of the full record: identity, current role, location, the 5 latest positions, education, top skills and any contacts — about 2 KB per person instead of 10+ KB. Made for AI agents and LLM pipelines with a context limit. Same price. Off by default: a run returns the complete record.

## `countries` (type: `array`):

Where the people live: two-letter codes (us, de, gb...), up to 60. Combine with country groups; leave both empty to search every country by title, headline or employer.

## `countryGroups` (type: `array`):

Whole regions at once, added to the countries above: eu, eea, dach, nordics, baltics, benelux, cee, cis, post_soviet, mena, gcc, latam.

## `titleKeywords` (type: `array`):

Job titles, read as the title tags our dictionary gives them: "head of sales" finds heads in sales in any spelling or language, "cfo" every CFO. A title the dictionary does not know is not searched, and the run names it. Each 3-64 characters, at most 10.

## `titleMatch` (type: `string`):

How headline and past-title keywords match (job titles are read as tags). Leave empty: a list with a short keyword (4 letters or fewer) matches whole words, otherwise the letters match anywhere. substring: "cto" also hits "director"; word: whole words only.

## `headlineKeywords` (type: `array`):

Match any of these words in the profile headline — what people say they do ("fractional cfo", "rust", "growth"). Each 3-64 characters, at most 10. Alone, job-title words (founder, recruiter) find that title with the word in the headline; topic words (fintech, rust) need job titles, seniority or companies too.

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

Keep only people at these levels. C-level to Other are buckets read from the job title, so 'CTO' and 'Chief Technology Officer' both land in cxo. Owner, Head of, Partner, Senior, Entry level and Intern are title tags: with one chosen, every level is matched by its tags, and Other cannot be added.

## `departments` (type: `array`):

The function the person works in, read from their job titles: sales, marketing, engineering and so on. Combines with Seniority and the job title keywords (a VP in sales = Seniority VP + Department Sales). Any of the chosen departments matches.

## `companyDomains` (type: `array`):

Keep only people currently working at these companies, by site domain (stripe.com). Brand domains resolve to the real employer. At most 1,000.

## `employerIndustries` (type: `array`):

Current employer's industry: names in either wording, any case (Software Development also finds Computer Software), or taxonomy ids. Up to 20 names and 50 ids. Examples: Financial Services, Hospitals and Health Care. Each covers its sub-industries (Software Development includes Computer Games); rows show the company's own industry.

## `employeeCountMin` (type: `integer`):

Keep only people at employers with at least this many employees.

## `employeeCountMax` (type: `integer`):

Keep only people at employers with at most this many employees.

## `pastEmployerDomains` (type: `array`):

People who USED to work at these companies, by site domain (stripe.com) — talent from a competitor, alumni of a former customer. People still there are left out unless you turn on "count people still there". At most 100.

## `segments` (type: `array`):

Compare up to 10 segments in one run: each is {"name": ..., plus the fields that differ}, laid over the input above. Example: \[{"name":"Germany","countries":\["de"]},{"name":"Poland","countries":\["pl"]}]. Count and market modes only.

## `maxPerCompany` (type: `integer`):

Account-based lists: deliver at most this many people per current employer across the whole run. The rest are skipped free and counted in one note row.

## `excludeDatasets` (type: `array`):

Pick datasets of earlier runs of this Actor: everyone in them is left out of this run and never charged again. Run the same search weekly and get only the new people. People an earlier run of the same search skipped (no email, left the role) are not read again either.

## `localityKeywords` (type: `array`):

Narrow inside the chosen countries by city or region text (example: san francisco, greater london). 3-64 characters each, at most 10.

## `excludeCountries` (type: `array`):

Two-letter codes to drop, for example a group minus one country (eu without de).

## `headlineAlsoKeywords` (type: `array`):

A second list ANDed with headline keywords: the headline needs one word from each list. Example: headline keywords head of, director + also data, analytics = data leaders only. 3-64 characters each, at most 10.

## `pastTitleKeywords` (type: `array`):

Match any of these words in a PAST job title — people who used to be something. 3-64 characters each, at most 10.

## `excludeTitleKeywords` (type: `array`):

Drop people by the title tags these titles mean (intern, assistant, student); a word the dictionary does not know (fractional, interim) drops the titles that contain it. 3-64 characters each, at most 10.

## `excludeHeadlineKeywords` (type: `array`):

Drop people whose headline contains any of these words (example: student, retired, freelance). 3-64 characters each, at most 10.

## `languages` (type: `array`):

Languages listed on the profile, two-letter codes (en, de, es). The language data is being built: until it lands, a run with this field stops with a note and nothing is charged.

## `excludeCompanyDomains` (type: `array`):

Drop people currently working at these companies, by site domain — your customers, your competitors, your own company. At most 1,000.

## `includeUnknownEmployerSize` (type: `boolean`):

About half the companies on file carry no headcount, and a size filter drops all of them. Turn on to keep them — useful when small companies matter, since unknown size is usually small.

## `employerHqCountries` (type: `array`):

Keep people whose current employer is headquartered in these countries, wherever the person lives — for example people in Poland working for US companies.

## `leftPastEmployerAfterYear` (type: `integer`):

With past employer domains or countries: keep people whose last day there falls in this year or later.

## `leftPastEmployerBeforeYear` (type: `integer`):

With past employer domains or countries: keep people who left in this year or earlier.

## `pastEmployerCountries` (type: `array`):

Instead of domains: people who used to work at a company headquartered in these countries ("worked at a US company, left after 2022"). Two-letter codes.

## `stillThereCounts` (type: `boolean`):

Off by default. A past employer match means a completed position there — and an internal promotion also closes one, so roughly a third of matches are people who never left (measured: 668 of 2,102 on one employer). By default those are dropped and you get actual leavers; turn this on to keep everyone who ever held a role there.

## `careerStartYearMin` (type: `integer`):

Year of the person's first recorded position. Use with 'career started in or before' to target experience bands (a 2015 start is roughly 10 years of experience).

## `careerStartYearMax` (type: `integer`):

Year of the person's first recorded position.

## `currentRoleStartedAfterYear` (type: `integer`):

Recent job changers: keep only people whose current position began in this year or later.

## `currentRoleStartedBeforeYear` (type: `integer`):

Tenure: people who have held their current role since this year or longer (2022 = at least about three years in the role).

## `currentRoleStartedAfterDate` (type: `string`):

Job changers to the month: YYYY-MM or YYYY-MM-DD. Start dates are dense through 2025 and thin for the last months, so use a window of a year or more.

## `requireCurrentPosition` (type: `boolean`):

Drop rows where no current employer is known.

## `onlyBetweenJobs` (type: `boolean`):

Keep only people with no current position on record — open-to-work candidates, recently laid off. Job title keywords then match the jobs they held (past titles); seniority, departments and employer filters describe a current job and cannot be combined with it.

## `connectionsMin` (type: `integer`):

Keep only people with at least this many connections — a rough proxy for an active, established profile.

## `connectionsMax` (type: `integer`):

Keep only people with at most this many connections.

## `activeAfter` (type: `string`):

Keep people whose profile shows activity on or after this date, YYYY-MM or YYYY-MM-DD.

## `updatedAfter` (type: `string`):

Keep people whose record was updated on or after this date, YYYY-MM or YYYY-MM-DD — the row's updatedAt. Works for counts and market rows too.

## `excludeLowSignal` (type: `boolean`):

Drop people with under 10 connections and no known career start — the self-declared "CEO at <famous brand>" pattern. Off by default: across the whole database many such profiles are sparse but real, so turn it on for leadership searches at well-known companies. Every row carries the lowSignal column either way.

## `excludePersonIds` (type: `array`):

personId values from earlier rows to leave out (up to 10,000). Easier: pick the earlier datasets above.

## `sampleSeed` (type: `integer`):

Return one random page of up to 100 people spread across the whole segment instead of the first rows. The same seed returns the same people — for research samples you can reproduce.

## `marketTopN` (type: `integer`):

How many job titles and employers the market breakdown lists (default 25, up to 100).

## Actor input object example

```json
{
  "mode": "people",
  "maxResults": 25,
  "profileDetail": "row",
  "compact": false,
  "countries": [
    "nl"
  ],
  "titleKeywords": [
    "founder"
  ],
  "segments": [],
  "includeUnknownEmployerSize": false,
  "stillThereCounts": false,
  "requireCurrentPosition": false,
  "onlyBetweenJobs": false,
  "excludeLowSignal": false,
  "marketTopN": 25
}
```

# Actor output Schema

## `results` (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": 25,
    "profileDetail": "row",
    "countries": [
        "nl"
    ],
    "titleKeywords": [
        "founder"
    ],
    "segments": [],
    "excludeLowSignal": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("b2bsearch/people-database-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": 25,
    "profileDetail": "row",
    "countries": ["nl"],
    "titleKeywords": ["founder"],
    "segments": [],
    "excludeLowSignal": False,
}

# Run the Actor and wait for it to finish
run = client.actor("b2bsearch/people-database-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": 25,
  "profileDetail": "row",
  "countries": [
    "nl"
  ],
  "titleKeywords": [
    "founder"
  ],
  "segments": [],
  "excludeLowSignal": false
}' |
apify call b2bsearch/people-database-search --silent --output-dataset

```

## MCP server setup

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