LinkedIn People Search - Find Profiles by Title & Location
Pricing
Pay per event
LinkedIn People Search - Find Profiles by Title & Location
Find LinkedIn people by job title and location without cookies or a login. Pay per profile you actually receive — never per search page. Built-in cross-run deduplication (no database required) and freshness windows that surface profiles updated in the last week or month.
Pricing
Pay per event
Rating
5.0
(1)
Developer
Omar Eldeeb
Maintained by CommunityActor stats
1
Bookmarked
7
Total users
5
Monthly active users
5 days ago
Last modified
Categories
Share
LinkedIn People Search — Find Profiles by Job Title & Location
You need a list of people who hold a job title, in a place. Not a company list, not a job-post list — people, with their LinkedIn URL, so you can start a search or a campaign today.
Getting that list normally costs you one of two things: a LinkedIn account you are willing to risk (session cookies, Sales Navigator seats, ban exposure), or a per-search-page bill that charges you the same whether a page returns ten new people or ten you already had.
This actor gives you the list without either. Type a job title and a location, get back rows of real people with names, headlines, current titles, current employers and profile URLs. No login, no cookies, no LinkedIn account, no session to keep alive. And you are billed for the rows you receive, not for the pages we looked at.
It is not a substitute for Recruiter. Read Limitations before you commit to it — that section is deliberately blunt.
What it does
- You give it job titles and locations (or your own raw search queries).
- It builds a matrix of public-index searches from them — optionally expanding job-title synonyms and nearby cities.
- Each search page yields roughly 10 public LinkedIn profiles: name, headline, current title, current company, profile URL.
- In Full mode it then opens each profile through a cookie-free path and adds the about section, work history, education and follower counts.
- Rows land in your dataset. You are charged per row.
Everything comes from publicly indexed LinkedIn profile pages. There is no authenticated session anywhere in the chain.
Three things it does differently
1. You pay per profile delivered, never per search page
Per-search-page pricing is common in this category: you are charged a fixed amount for each page of results fetched, regardless of what is on it — including pages where every single result is someone you already have, and pages that come back thin.
This actor charges on delivery. A row hits your dataset, you are charged for that row. Nothing else bills:
- Search pages are free. Fetching 50 of them costs you nothing.
- Profiles removed by deduplication are free — they are filtered before anything is opened.
- Profiles that fail to open in Full mode are charged the Short price, not the Full price.
- A run that finds nobody costs you the $0.005 actor-start fee and nothing more.
maxSerpCalls exists to bound run time, not your bill. Raising it does not cost you money.
2. Cross-run deduplication with no database
The usual way to stop a scheduled sourcing run from handing you the same 200 people every week is to stand up your own database — connect a MongoDB, write the seen-set yourself, filter on your side after you have already paid for the duplicates.
Set dedupeMode and this actor does it for you, storing the seen-set in a named key-value store in your own Apify account. No external database, no connection string, nothing to maintain.
dedupeMode | What happens | Use it when |
|---|---|---|
off (default) | Every match is returned. | You already deduplicate inside your own ATS or CRM. |
auto | The actor remembers every profile it has given you and returns only people you have not seen. State lives in a key-value store named by dedupeStoreName, in your account. | You want a recurring run that only ever surfaces new people. |
exclude_list | You pass excludeProfileUrls — URLs or bare slugs — and they are dropped before any profile is opened. | You hold the state yourself and want the actor stateless. |
Under auto, runs that share a dedupeStoreName share a memory. Use one store name per sourcing project so a nurse search in Dubai does not suppress results in your engineering search in Berlin.
3. Freshness windows are also a job-change signal
freshness restricts results to profiles that have been re-indexed recently — past_month or past_week.
That matters more than it sounds. A public profile gets re-crawled when it changes: a new job title, an "Open to work" banner, a rewritten headline, a new employer. So a recency window is a proxy for "this person's profile moved lately" — which is the population most likely to be reachable, mid-move, or newly in a role you care about.
The combination that makes this a product rather than a filter:
freshness: "past_week" + dedupeMode: "auto" + an Apify schedule
Run that weekly and you have a standing feed of people in your market whose profiles just changed and whom you have never been shown before. Every run returns a small, new, actionable list instead of the same haystack.
Pricing
Pay-per-event, with no separate trial tier — new Apify accounts come with free platform credit you can spend here like anywhere else.
| Event | Price | Per 1,000 | When it fires |
|---|---|---|---|
| Actor start | $0.01 | — | Once per run. Covers all search-page fetches, however many the run needs. |
| Profile | $0.002 | $2 / 1k | One person delivered — name, headline, current title, company, LinkedIn URL. Also charged when a Full profile could not be opened. |
| Full profile | $0.004 | $4 / 1k | One person delivered with their profile opened — adds about, work history, education, followers. Only when the open actually succeeded. |
What is never charged: search pages, deduplicated profiles, empty results, or a run that finds nothing beyond the start fee.
A 1,000-profile Full-mode run costs roughly $4.01 — less in practice, because the share of profiles that do not open is billed at the Short price.
Quick start — find candidates by job title and location
A recruiting search
ICU nurses in Dubai, full detail, 250 people:
{"jobTitles": ["Registered Nurse", "ICU Nurse"],"locations": ["Dubai", "Abu Dhabi"],"mode": "full","maxProfiles": 250,"maxSerpCalls": 60,"expandSynonyms": true}
expandSynonyms also searches close title variants and nearby cities. It finds substantially more people and uses more search pages — which, again, cost you nothing.
A standing "who just moved" feed on a schedule
Attach this to an Apify schedule (weekly). Every run returns only people you have never been given before, whose profiles changed in the last week:
{"jobTitles": ["Head of Talent", "Talent Acquisition Manager"],"locations": ["London", "Manchester"],"mode": "short","freshness": "past_week","dedupeMode": "auto","dedupeStoreName": "uk-talent-leaders","maxProfiles": 200}
Short mode is the right choice here — you are monitoring for who appeared, and can run a Full pass on the handful worth pursuing.
An exclude-list run against your own CRM
You already have people in your ATS. Skip them before they cost anything:
{"searchQueries": ["\"Backend Engineer\" \"Berlin\" -recruiter -hiring"],"mode": "full","dedupeMode": "exclude_list","excludeProfileUrls": ["https://www.linkedin.com/in/jane-doe-1234","https://de.linkedin.com/in/max-mustermann","another-slug-you-already-have"],"maxProfiles": 300}
Raw queries run before any title × location combinations. site:linkedin.com/in is added automatically if you leave it out. Full URLs, country-subdomain URLs and bare slugs are all accepted in the exclude list.
What you get per person
One dataset row per person. mode: "short" returns everything above enriched; mode: "full" adds the rest when the profile opens.
{"profileUrl": "https://www.linkedin.com/in/renju-rajappan-a36231125","slug": "renju-rajappan-a36231125","name": "Renju Rajappan","headline": "Registered Nurse - ICU at Dubai Health Authority","currentTitle": "Registered Nurse - ICU","currentCompany": "Dubai Health Authority","location": {"raw": "دبي، الإمارات العربية المتحدة","normalized": "Dubai, United Arab Emirates","countryCode": "AE"},"locationConfidence": "exact","snippet": "Registered Nurse - ICU at Dubai Health Authority · Experience: Dubai Health Authority · Location: Dubai · 262 connections...","enriched": true,"about": "ICU nurse with nine years of critical-care experience across...","workHistory": [{"company": "Dubai Health Authority","companyLinkedInUrl": "https://www.linkedin.com/company/dubai-health-authority","title": "Registered Nurse - ICU","startDate": "2019","endDate": null,"isCurrent": true},{"company": "Aster Hospital","companyLinkedInUrl": null,"title": "Staff Nurse","startDate": "2016","endDate": "2019","isCurrent": false}],"education": [{"school": "Rajiv Gandhi University of Health Sciences","degree": "B.Sc. Nursing","startYear": 2011,"endYear": 2015}],"followers": 266,"connections": 262,"_meta": {"query": "site:linkedin.com/in \"Registered Nurse\" \"Dubai\"","queryOrigin": "seed","rank": 3,"freshnessWindow": "past_month","fetchedAt": "2026-08-18T09:14:22.311Z","enrichAttempts": 1,"enrichFailureReason": null}}
When a profile cannot be opened you still get the row — enriched: false, _meta.enrichFailureReason set, the enrichment-only fields absent, and the Short price charged.
Every run also logs a stats block: search pages fetched, profiles discovered, duplicates skipped, enrichment attempted vs. succeeded, rows delivered, and how many were charged at each price. You can always reconcile what you paid for.
Input reference
| Field | Type | Default | Notes |
|---|---|---|---|
jobTitles | string[] | ["Registered Nurse"] | Job titles to search for. Combined with every location. Leave empty if you are using searchQueries instead. |
locations | string[] | ["Dubai"] | Cities, regions or countries. Combined with every job title. |
searchQueries | string[] | — | Raw queries for full control, e.g. "Head of Talent" "Berlin" -recruiter. Run before the title × location combinations. site:linkedin.com/in is added automatically if you omit it. |
mode | full | short | full | Short returns search-index fields only, $2/1k. Full additionally opens each profile for about, work history, education and follower counts, $4/1k. A profile that will not open is charged the Short price. |
freshness | any | past_month | past_week | any | Restrict to profiles re-indexed in that window. See freshness windows. |
maxProfiles | integer | 100 | Hard cap on rows returned this run. This is your cost cap. 1–20000. |
maxSerpCalls | integer | 50 | Safety cap on search pages fetched, roughly 10 profiles each. Raise it if a broad search stops before hitting maxProfiles. Not billed — it bounds run time only. 1–2000. |
dedupeMode | off | auto | exclude_list | off | See deduplication. |
dedupeStoreName | string | linkedin-people-finder-seen | Only used when dedupeMode is auto. Runs sharing a name share their memory of who has already been returned — one name per sourcing project. The store lives in your own Apify account. |
excludeProfileUrls | string[] | — | Only used when dedupeMode is exclude_list. Profile URLs or slugs you already have. Skipped before any profile is opened, so they cost nothing. |
expandSynonyms | boolean | false | Also search title variants (Software Engineer → Software Developer, Backend Engineer) and nearby locations (Dubai → Sharjah, Abu Dhabi). More people, more search pages. |
useResidentialFallback | boolean | false | Full mode only. After 3 failed attempts on a profile, retry through a residential proxy. Raises the share of profiles successfully opened, at higher cost on those retries only. |
maxRetriesPerProfile | integer | 5 | Full mode only. Attempts before falling back to the short profile. 1–10; 5 is the validated sweet spot. |
proxyConfiguration | object | Apify datacenter | Proxy used for opening profiles in Full mode. Datacenter is the default and the cheapest option that works. |
Limitations — read this before you run it
This actor reaches LinkedIn through a public search index, with no login. That buys you the price, the absence of ban risk and the zero setup. It costs you the following, and none of it is fixable within a cookie-free design. Please size your expectations against this list rather than against a session-based scraper.
Roughly 300–400 results per query, not thousands. A public-index site search has a hard ceiling. Session-based scrapers that drive LinkedIn's own search with authenticated accounts return thousands of results per query and segment their way well beyond that. This one does not. You widen coverage by adding more queries — more titles, more cities, expandSynonyms, different freshness windows — not by paging deeper into one.
Give the run enough time. The actor reserves the tail of your run timeout to finish writing rows and save its deduplication state, and it caps the search phase so that discovery can never eat the whole window and leave nothing delivered. Full mode opens roughly one profile every 2-3 seconds, so budget accordingly: ~100 profiles needs about 5 minutes, ~1,000 needs closer to an hour. If a run stops early it says so in the log and in stoppedReason, and everything already found is still in your dataset and still deduplicated — re-running continues from where it left off.
Work history carries employers, rarely role titles or dates. LinkedIn serves most public profiles with the experience section's role titles and date ranges blanked out — they are absent from both the structured data and the rendered HTML, so no cookie-free tool can recover them. What survives is the employer name and its LinkedIn company URL, which is what workHistory gives you. On the profiles that do expose titles we extract them; across live recruiting searches that is a small minority. Do not build a workflow that needs tenure dates.
currentTitle is often empty; use headline instead. LinkedIn's public profile markup has no reliable dedicated job-title field, so we fill currentTitle only when a role can be read unambiguously — measured across live searches it lands between about 4% and 53% of rows depending on the profession. What is always there is headline, the line the person wrote about themselves ("Registered Nurse -ICU at Dubai Health Authority"), which is populated on effectively every row and is what most recruiters filter on anyway. Treat currentTitle as a bonus and headline as the real field.
In Short mode, currentCompany is best-effort and often empty. The search index gives us a person's headline, and we can only split out an employer when that headline uses the "Role at Company" form. Across our own test searches the fill rate ranged from none at all to about half, depending entirely on how people in that profession write their headlines. Where the headline is truncated we recover the employer from the result snippet when it is there, and leave the field null when it is not — we would rather give you an empty field than a half-a-name that looks real. Full mode reads the employer off the profile itself and fills it far more reliably. If employer matters to your workflow, use Full mode.
No seniority, years-of-experience, company-headcount, function or industry-ID filters. Those facets live inside LinkedIn's authenticated search. Reaching them requires a logged-in session, which this actor deliberately does not use. You get job title and location, plus whatever you can express in a raw query string. If your workflow depends on "VP and above, at companies of 200–1000 people, in SaaS", this is the wrong tool and a session-based product will serve you better.
Location is a text match, not a true geo filter. LinkedIn's own search resolves a location to a geographic ID; this actor matches text. Someone whose headline merely mentions your city will match — in validation, a large minority of results for a Dubai query were profiles indexed in India whose headline referenced Dubai.
We do not hide that and we do not silently drop those rows. Every row carries locationConfidence:
exact— the location evidence came from the profile's own location field.mentioned— the person references the location in their headline or snippet, but their profile location is elsewhere.unknown— no usable signal.
Filter on it in your own pipeline. For relocation-focused recruiting — Gulf healthcare hiring from South Asia is the obvious case — the mentioned set is frequently the exact pool you are looking for, which is why we return it rather than discard it. But be clear-eyed: this is not geo-precise targeting. If you need "people verified to live inside this metro", that is not what you are getting here.
Full mode opens profiles successfully roughly 80% of the time. The remainder are profiles whose owners have restricted public visibility, or which resist the cookie-free path. When that happens you still get the row — search-index fields, enriched: false, and a stated failure reason — and you are charged the Short price, never the Full price. You do not pay for what you did not get, but do not plan on a fully enriched dataset.
Also worth knowing:
- Only vanity profile URLs (
/in/their-name) exist in the public index. ID-style URLs (/in/ACoAAA…) are login-gated and cannot be resolved by any cookie-free tool. - No email addresses. This actor does not guess, infer or buy them.
- The public index decides what has been indexed. Very new profiles, and profiles with public visibility switched off, are not reachable at all — no setting in this actor changes that.
FAQ
Do I need a LinkedIn account or cookies? No. There is nothing to configure, no session to keep alive, no account to put at risk. That is the whole design.
Am I charged for duplicates? No. Deduplication runs before enrichment and before delivery, so filtered profiles never reach a charge.
Am I charged for search pages?
No. Only delivered rows bill. Raising maxSerpCalls costs you time, not money.
What happens if a profile cannot be opened in Full mode?
You get the row with enriched: false and a failure reason, charged at the Short price of $0.002.
Which mode should I use? Short for discovery, monitoring and anything feeding a schedule — half the price and faster. Full when you are actually going to read the profile: shortlisting, personalising outreach, screening.
How do I get more than 300–400 people?
Add queries, not pages. More job titles, more locations, expandSynonyms: true, and different freshness windows each surface a different slice of the index. Then dedupeMode: "auto" collapses the overlap for you.
Does dedupeMode: "auto" share data with other users?
No. The seen-set lives in a named key-value store in your own Apify account.
How do I reset the deduplication memory?
Change dedupeStoreName, or delete that named key-value store from your Apify account storage.
Can I filter by seniority or company size? No — see Limitations. Those facets require an authenticated session.
Why did my run return fewer people than maxProfiles?
Either the query hit the public-index ceiling, or maxSerpCalls was reached first, or deduplication removed the rest. The run stats tell you which.
Can I feed the output into Clay, n8n or Make? Yes. It is a standard Apify dataset — pull it over the API or wire up the Apify integration in any of those tools.
What this data is, and using it lawfully
Everything this actor returns is public data: LinkedIn profile pages their owners have chosen to make publicly visible, reached through a public search index. No login, no cookies, no session, no authentication bypass, no private or connection-gated surface. If a profile is not public, this actor cannot see it — which is correct behaviour, not a gap.
That said, the rows are personal data about real people, and the tool being lawful does not make every use of its output lawful. If you process these rows — for recruiting outreach, sourcing, list-building, CRM enrichment — under GDPR, UK GDPR, PECR or an equivalent regime, you are the controller: your lawful basis, your transparency obligations to those individuals, your retention policy, and your handling of objection and erasure requests. Rules on direct marketing and electronic communications may also govern how you contact them.
We cannot do that part for you and do not claim to. Please have your basis worked out before running this at scale.
License
MIT. Use the data within LinkedIn's Terms of Service and applicable scraping law. This actor never touches an authenticated LinkedIn surface.