LinkedIn Candidate Finder: Matched Skills, No Recruiter Seat
Pricing
from $1.80 / 1,000 candidate founds
LinkedIn Candidate Finder: Matched Skills, No Recruiter Seat
Find LinkedIn profiles matching recruiter requirements: role, skills, location, experience, target companies. Returns name, headline, current title and company, profile URL, matched skills, and a match confidence note. No login, no cookies. Use as an MCP server in Claude, ChatGPT and AI agents.
Pricing
from $1.80 / 1,000 candidate founds
Rating
0.0
(0)
Developer
The Mine Works
Maintained by CommunityActor stats
0
Bookmarked
10
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
From The Mine Works, makers of Threads Scraper and B2B Leads Finder, with over 140,000 runs across 170+ public actors. This actor ranks #2 for "candidate finder" in Apify Store search.
Describe the hire the way a recruiter would: a role, the skills you need, a city, an experience band and, if you like, the companies you want to poach from. The actor searches the public LinkedIn profiles Google has indexed and returns a shortlist: name, headline, current title and company, location, profile URL, which of your skills each person's public text mentions, and a plain-English note on how well they match. No LinkedIn login, no Recruiter seat, no cookies, no browser.
Why choose this actor?
- A role-checked shortlist in about half a minute. In a recorded run on 30 September 2026,
Data ScientistinLondonreturned 5 candidates in 32 seconds, every one with the role in their headline and London in their public text, ratedhigh (role matched, location matched). No LinkedIn account and no Recruiter licence. - You only pay for people who are actually in the role. Google pads thin searches with unrelated profiles. Every result must show at least half the words of your role title in its headline, snippet or Google's summary line, or it is skipped before it is opened and never charged. A made-up role in our tests returned nothing and cost only the start fee.
- Honest matching, not invented data.
matched_skillslists only the skills that literally appear in a person's public profile text,locationis reported only when it appears there, andmatch_confidencespells out what matched (for examplemedium (role matched, 1/2 skills matched, location not confirmed)).
Part of The Mine Works LinkedIn family: LinkedIn Company Scraper, LinkedIn Post Scraper, LinkedIn Employees Scraper, LinkedIn Profile Scraper, LinkedIn Email Finder, LinkedIn Newsletter Scraper.
Try it in one minute
Paste this into the JSON tab of the input page and press Start. It returns up to 10 candidates, usually in under a minute.
{"roleTitle": "Data Scientist","skills": ["Python"],"location": "London","maxResults": 10}
The only input you must give is roleTitle, the job title as people write it on their profiles (Senior Software Engineer, Product Manager, Data Scientist). Everything else narrows or steers the search: skills (a list of must-have skills), location (a city, region or country), experienceYears (a soft seniority hint), and targetCompanies (up to 20 companies to search first).
Apify's free plan includes $5 of credit every month, which covers about 1,500 candidates at this actor's Free plan price ($0.003 a candidate plus the $0.005 start fee, in runs of 30).
Copy to your AI assistant
Paste this block into ChatGPT, Claude, Cursor or any assistant that can write code, and it can run the actor for you.
themineworks/linkedin-candidate-finder on Apify. Finds public LinkedIn profiles indexed by Google for a role, skills and location, and returns one row per candidate with name, headline, current_title, current_company, location, profile_url, matched_skills and match_confidence. Call ApifyClient("TOKEN").actor("themineworks/linkedin-candidate-finder").call(run_input={...}), then client.dataset(run["defaultDatasetId"]).list_items().items. Required: roleTitle (string). Optional: skills (string[]), location (string), experienceYears ({"min": n, "max": n}, adds "senior" when min >= 8 or "junior" when max <= 3), targetCompanies (string[], up to 20), maxResults (1 to 200, default 30). Rows with _type "summary" are run reports and are never billed. Full spec: GET https://api.apify.com/v2/acts/themineworks~linkedin-candidate-finder/builds/default (Bearer TOKEN), which returns inputSchema and readme. Token: https://console.apify.com/account/integrations?fpr=ymnoit&utm_source=apify-readme&utm_medium=referral
Key features
- 8 candidate fields plus a timestamp:
name,headline,current_title,current_company,location,profile_url,matched_skills,match_confidenceandscraped_at. Fields that cannot be read from the public text are left out rather than guessed. - Recruiter-shaped search plan. Up to six searches per run, from narrow to broad: role with your top 3 skills and the location, one search per target company, role with one skill, role and location, role and skills anywhere, and finally the role alone. The actor moves to the next search only when it still needs candidates.
- Target-company sourcing. Each of up to 20
targetCompaniesgets its own search (role, top skill, location and company), run right after the most specific search. - Role check on every row. At least half of your role title's words must appear in the person's headline, snippet or Google's summary line. The summary row counts the profiles turned away (
filtered_role_not_confirmed). - Duplicates removed. A person found by two searches appears once and is charged once.
- Never touches LinkedIn. Searches go to Google (with Brave as a backup), and each Google result link is resolved without following it to LinkedIn. You get public search data only.
How to use it
Basic: one role in one city
{"roleTitle": "Data Scientist","location": "London","maxResults": 30}
This is the shape of our 30 September test (with maxResults: 5): one Google results page, 10 profiles checked, 5 delivered, 32 seconds.
Role plus must-have skills
{"roleTitle": "Senior Software Engineer","skills": ["Python", "AWS", "Kubernetes"],"location": "San Francisco","experienceYears": { "min": 8 },"maxResults": 50}
The first search uses all three skills and the location, plus the word senior because min is 8 or more. If that runs dry, the actor broadens step by step. Sort the results on match_confidence: high means the role matched and at least 70% of your skills appear in the person's public text.
Poaching from named companies
{"roleTitle": "Product Manager","skills": ["B2B SaaS"],"location": "London","targetCompanies": ["Stripe", "Notion", "Revolut"],"maxResults": 60}
Each company gets its own search right after the most specific one. Check current_company on each row: the company name in the search makes a match likely but does not guarantee the person still works there, and some headlines do not name a company at all.
Junior pipeline for a graduate program
{"roleTitle": "Data Analyst","skills": ["SQL", "Tableau"],"location": "Bengaluru","experienceYears": { "max": 2 },"maxResults": 100}
A max of 3 or less adds the word junior to the searches. It is a hint to the search engine, not a filter: people who never write "junior" in their headline can still appear, and many junior people are left out.
Weekly refresh for a hard-to-fill role
{"roleTitle": "Site Reliability Engineer","skills": ["Terraform"],"location": "Berlin","maxResults": 100}
Save this as a task and schedule it weekly (for example 0 8 * * 1). Turn on monitorMode and each run returns only people it has not delivered before, so every run can go into your ATS as it is.
Input parameters
| Parameter | Type | Default | What it does |
|---|---|---|---|
roleTitle | string | required (form prefill: Senior Software Engineer) | The role you are hiring for, as people write it in their headlines. Every delivered candidate shows at least half of its words (of 3 letters or more). |
skills | array of strings | none (form prefill: Python, AWS) | Must-have skills. The first three go into the searches; all of them are checked for matched_skills. |
location | string | none (form prefill: San Francisco) | City, region or country. Used in the searches and checked against each person's public text. |
experienceYears | object | none (form prefill: {"min": 3, "max": 8}) | {"min": n, "max": n}. A soft hint only: max of 3 or less adds junior, min of 8 or more adds senior, anything else adds nothing. |
targetCompanies | array of strings | none | Up to 20 companies. Each adds its own search, and a search for a company with no matching people still costs a results page on our side, so keep the list to real targets. |
maxResults | integer (1 to 200) | 30 (form prefill: 5) | Most candidates to return across all searches. |
proxy | object | Apify Proxy, group GOOGLE_SERP | Only used for the Brave backup search. Google searches always run through Apify's Google search proxy. With the default setting, the Brave backup uses Apify's US residential proxy; any other group you choose is used as is. |
"Form prefill" values fill the Console form for you; an API call that leaves a field out gets the default shown, or nothing.
A run stops when it has maxResults candidates, when every search has run dry, after 150 results pages in total, or when its own spend guard decides further pages cost more than they return. Whatever it found by then is delivered. The default timeout is 300 seconds; give large runs (100 or more candidates, many target companies) 900 seconds or more in Run options. If a run reaches its timeout, it stops 15 seconds early and keeps every candidate already delivered.
What data do you get?
One row per candidate, built only from what Google shows for a public profile (its title, snippet and summary line).
Who: name and headline (split from the result title, which LinkedIn writes as the name, a dash, then the headline), profile_url (the public linkedin.com/in/ address, lower case, no tracking parameters).
Current role: current_title and current_company, split from the headline at " at ", "@" or " | ". A headline such as "Data Scientist" with no company gives a title and no current_company.
Fit: location (your requested location when it appears in the person's public text, otherwise a "City, Region" phrase when one is present, otherwise left out), matched_skills (each of your skills that appears in that text, case-insensitive) and match_confidence.
match_confidence reads like high (role matched, 2/3 skills matched, location matched):
- with skills requested:
highwhen the role matched and at least 70% of the skills appear,mediumwhen at least 30% appear or the role matched, otherwiselow; - without skills:
highwhen the role matched and the location (if any) matched,mediumwhen one of them matched.
scraped_at is the ISO timestamp of the row.
Public search text is short, so matched_skills under-reports: a person who lists Python deep in their profile but not in their headline or snippet will show no match for it. Treat an empty list as "not shown publicly", not as "does not have the skill".
Each run ends with one _type: "summary" row: total_candidates, charged_for, filtered_role_not_confirmed, total_page_fetches, the Google and Brave request counts (google_search, brave_search, engine_pages) and the run's own cost estimate (guard). It is never billed.
Stable fields for automations
These 7 fields were present in every candidate row we sampled on the current version (all rows of the 30 September run, and they are written for every candidate by the code):
| Field | What it holds |
|---|---|
name | Name as shown in the public search result |
headline | Headline as shown in the public search result |
current_title | Title split from the headline (the whole headline when it cannot be split) |
profile_url | Public profile URL, https://www.linkedin.com/in/<slug> |
matched_skills | Array of your skills found in the public text; empty when none, or when you gave no skills |
match_confidence | high, medium or low with the reasons in brackets |
scraped_at | ISO timestamp when the row was captured |
current_company and location are present only when they could be read (4 of 5 and 5 of 5 rows in the 30 September run). We will not rename these fields. New fields may be added over time; existing ones keep their names.
Output examples
These rows are about real people, so we do not reprint new ones here. The first example below is the record the previous version of this page already showed, from a run on 15 July 2026 with roleTitle: "Senior Software Engineer", skills: ["Python", "AWS"] and location: "San Francisco":
{"name": "Adam Jenkins","headline": "Senior Software Engineer | ex-Amazon","current_title": "Senior Software Engineer","current_company": "ex-Amazon","profile_url": "https://www.linkedin.com/in/adamjenkins1","matched_skills": [],"match_confidence": "medium (role matched, 0/2 skills matched, location not confirmed)","scraped_at": "2026-07-15T01:15:42.690Z"}
It shows two limits worth knowing: the headline split took "ex-Amazon" as the company, and neither skill appeared in the public text, so matched_skills is empty rather than guessed.
A row from the 30 September Data Scientist / London run, with the name and profile address withheld:
{"name": "[withheld]","headline": "Data Scientist at TfL","current_title": "Data Scientist","current_company": "TfL","location": "London","profile_url": "https://www.linkedin.com/in/[withheld]","matched_skills": [],"match_confidence": "high (role matched, location matched)","scraped_at": "2026-09-30T14:35:37.121Z"}
The summary row from that run (never charged), trimmed:
{"_type": "summary","total_candidates": 5,"charged_for": 5,"charge_failures": 0,"engine_refused": false,"search_requests": 1,"search_refused": 0,"engine_pages": { "google_pages": 1, "brave_pages": 0, "brave_after_google_failed": 0 },"total_page_fetches": 1,"filtered_role_not_confirmed": 0,"scraped_at": "2026-09-30T14:35:38.865Z"}
In a run with a made-up role on the same day, Google returned nothing, Brave returned 12 profiles, all 12 failed the role check, and the run delivered 0 candidates and charged only the start fee.
Pricing
Pay per event: you pay for each candidate delivered to your dataset, plus a small start fee per run.
| Event | Free | Bronze | Silver | Gold and above |
|---|---|---|---|---|
candidate-found, per candidate | $0.003 | $0.00253 | $0.00213 | $0.0018 |
candidate-found, per 1,000 candidates | $3.00 | $2.53 | $2.13 | $1.80 |
apify-actor-start, per run | $0.005 per GB of run memory, minimum one event | same | same | same |
The start fee, exactly. Apify's apify-actor-start event is charged once when a run starts, at $0.005 for each GB of memory the run uses, with a minimum of one event. This actor runs on 256 MB by default, so a default run pays one event: $0.005.
Worked examples on the Gold tier: 30 candidates cost $0.054 plus $0.005. 100 candidates cost $0.18 plus $0.005. The maximum, 200, costs $0.36 plus $0.005. On the Free tier, 30 candidates cost $0.09 plus $0.005.
Never charged: profiles that fail the role check, a person found twice (charged once), the Google and Brave search pages themselves (our cost, not yours), failed or refused searches, and the summary row. A run that finds nobody pays only the start fee.
There is no scheduled price change for this actor; these prices have applied since 14 September 2026. The Pricing tab on this page always shows the rate for your own plan; if it and this table ever differ, the Pricing tab is right.
Run it on a schedule
Turn on monitorMode and each run delivers only the candidates you have not received before, so a daily run costs you only for what is new.
- Enter your input, switch on Monitor mode and click Save as a task.
- In Apify Console open Schedules, click Add schedule and pick Daily (or any time and timezone you like).
- Under Actors or tasks to run, add the task you saved and save the schedule.
{"roleTitle": "Data Engineer","skills": ["Python","Spark"],"location": "Bengaluru","maxResults": 30,"monitorMode": true}
The first run delivers everything it finds. After that, each run delivers only candidates that were not in an earlier run with the same input, and candidates it skips are never charged. The summary row at the end shows new_this_run and skipped_duplicates. Changing the input starts a fresh history; changing only the result limit does not. A search stops after three pages in a row of people you already have, and the run's spend guard still stops it when further pages bring too few new people to pay for themselves.
FAQ
How does it find people without a LinkedIn Recruiter seat?
It searches Google for public LinkedIn profiles (site:linkedin.com/in plus your role, skills and location in quotes) through Apify's Google search proxy. When Google does not answer the first page of a search, the same search goes to Brave instead. It reads only what the search engines show: the title, the snippet and Google's summary line. It never logs in to LinkedIn and never opens a LinkedIn page.
How many candidates can I get? Up to 200 per run. In practice the number depends on how many matching profiles the search engines have indexed: a common role in a big city fills quickly, while a niche role with several required skills may return fewer than you asked for even after broadening. Each search reads up to 10 results pages, and a run reads at most 150.
How fresh is the data?
Searches run live, but the text comes from the search engine's index, which can lag a person's latest job change by weeks. Open profile_url before outreach to confirm the current role.
How reliable are matched_skills and location? Both are strict: a skill or a place counts only when it appears in the public search text for that person. That text is short, so both under-report; they never invent a match.
What does experienceYears actually do?
Public search results have no years-of-experience field. A max of 3 or less adds the word junior to the searches, a min of 8 or more adds senior, and any other range changes nothing. Use it as a nudge, then read the headlines.
Do I need a LinkedIn account, cookies or a proxy of my own? No. You need only an Apify account. The search proxies are included in the price; you do not need to change the proxy setting.
Why did I get fewer candidates than maxResults?
Either the searches ran out of people who pass the role check, or the run's spend guard stopped it because further pages were returning too few new people to pay for themselves. The summary row shows total_page_fetches and filtered_role_not_confirmed, so you can see which. Broaden the role title, drop a skill or remove the location and run again.
Can I get emails or phone numbers? Not from this actor. It returns public profile search data only. For business contact details, see the related actors below.
How do I export the data?
From the run's Storage tab as JSON, CSV, Excel, XML or HTML, or through the Apify API. Remove the row with _type: "summary" if you want candidates only.
Can I run it on a schedule?
Yes. Save your input as a task, then in Apify Console open Schedules, create a schedule (for example weekly, 0 8 * * 1) and pick the task. Turn on monitorMode to get only people not delivered in an earlier run; without it, each run returns everyone it finds, so filter out profile_url values you already have.
Can I use it from Claude, ChatGPT or another AI assistant?
- Connector URL:
https://mcp.apify.com/?tools=themineworks/linkedin-candidate-finder. - Claude: Settings > Connectors > Add custom connector, paste the URL, sign in with Apify.
- ChatGPT: developer mode, add an MCP connector with the URL, sign in with Apify.
- Cursor or VS Code: add it as an HTTP MCP server with that URL.
- Claude Code:
claude mcp add -t http linkedin-candidate-finder "https://mcp.apify.com/?tools=themineworks/linkedin-candidate-finder".
Is it legal to use? The actor collects only what public search engines show about public LinkedIn profiles, and it never logs in or visits LinkedIn. The results are still personal data about real people. You are responsible for having a lawful basis to process them and for how you contact anyone, including LinkedIn's terms and data protection laws such as GDPR and CCPA (for example, telling people where you got their details and honoring opt-outs). This is general information, not legal advice.
Integrations
- Google Sheets: export a run straight to a sourcing sheet, or use Apify's Google Sheets integration to append each run.
- Make, Zapier and n8n: use the Apify app or node to start a search from a new job opening and push the shortlist into your ATS or a Slack channel.
- Webhooks: have Apify call your URL when a run succeeds, then fetch the dataset.
- API and client libraries: start runs and read datasets from Python, JavaScript or any HTTP client. See the "Copy to your AI assistant" block above for the exact call.
- MCP clients: Claude, ChatGPT, Cursor, VS Code and other MCP clients can call the actor through
https://mcp.apify.com.
More from The Mine Works
- LinkedIn Company Scraper
- LinkedIn Post Scraper
- LinkedIn Employees Scraper
- LinkedIn Profile Scraper
- LinkedIn Email Finder
- LinkedIn Newsletter Scraper
Social media and video
Leads and business directories
Marketing, SEO and reviews
Real estate
Science, health and government data
Jobs and hiring
E-commerce and marketplaces
Company and business data
Food and local services
Developer and AI tools
More tools
- Tennis Match & Player Data Scraper
- Google Hotels Prices Scraper
- LandWatch Scraper
- Taobao Products Scraper 淘宝 天猫
Support
Found a bug or need a field we do not return yet? Open an issue on the Issues tab of this page and we will reply there. To ask for a new source, email dmineworks@gmail.com. A guide and FAQ for this actor also live at themineworks.com.
LinkedIn Candidate Finder turns a role, skills and a location into a role-checked shortlist of public LinkedIn profiles, billed only for the candidates it delivers.

