LinkedIn Profile Search & Email to Name - No Cookies
Pricing
Pay per usage
LinkedIn Profile Search & Email to Name - No Cookies
Reverse-look up a work email to the right person: full name, job title, current company - or search LinkedIn people by keyword, company, location, school. Verified two-way match, blank instead of wrong. No login, no cookies. JSON, CSV, Excel.
Pricing
Pay per usage
Rating
0.0
(0)
Developer
Andrew Babo
Maintained by CommunityActor stats
0
Bookmarked
2.2K
Total users
1.1K
Monthly active users
11 days ago
Last modified
Categories
Share
LinkedIn Profile Search & Email to Name Lookup (No Cookies, No Login)
Turn a work email into a verified person — full name, job title and current company — or search LinkedIn people by keyword, company, location or school. No LinkedIn account, no cookies, no session sharing, no ban risk on your own profile.
Built for cold outreach, CRM enrichment and lead qualification teams who cannot afford to greet a stranger by the wrong name.
Table of contents
- What this LinkedIn scraper does
- Benchmark: 25 real work emails
- Why "blank" beats "wrong"
- Quick start
- Input reference
- Output reference
- Common recipes
- Use cases
- Speed and cost
- How the matching works
- Limits and honest caveats
- FAQ
What this LinkedIn scraper does
| Mode | You give | You get |
|---|---|---|
| Reverse email lookup | dylan.church@mintselection.com | Full name, job title, current company, profile URL, location, photo |
| People search | head of growth fintech, London, Revolut | Matching public profiles with the full public profile data |
Both modes read public LinkedIn pages only. Nothing here depends on a logged-in session, so there is nothing to get restricted, banned or rate-limited on your account — because there is no account.
The email mode is the reason this actor exists: most LinkedIn search actors take a name and a company and return a list of plausible people. This actor takes the one identifier you actually have after an email-verification pass — the address itself — and resolves it to a single verified identity, or tells you honestly that it cannot.
Benchmark: 25 real work emails (measured, not estimated)
Side-by-side against a leading LinkedIn profile search actor on the same 25 real work emails:
| This actor | A leading LinkedIn profile search actor | |
|---|---|---|
| Correct person from email only | 19 / 25 | 0 / 25 (email input is not supported) |
| Correct person given name + company | n/a (not needed) | 14 / 25 top result |
| Wrong person returned | 0 | 7 / 25 (top result was a different human) |
| Total time for 25 emails | 47 seconds | ~16 seconds per single lookup |
| Cost per email | ~$0.003 | ~$0.10 per search |
The 6 remaining emails came back blank with a reason code — by design, not by failure.
Why "blank" beats "wrong"
Most email-to-name tools take the first search result with a similar name and attach it to your campaign. That is how "Hi Ruth" ends up in an email to John. This actor scores every candidate on two independent axes:
- Name axis — does the name inside the email match the profile name? (
first.last,flast,firstl,firstlast, initials…) - Company axis — does the email domain match the company the person actually works for? Confirmed on LinkedIn, and when LinkedIn hides the employer, on an external source such as the company team page or a press release.
Both must agree. If only one agrees, or two candidates tie, the row comes back empty with a machine-readable reason instead of a guess. Every blank row also carries rejectedCandidates, so you can audit the decision instead of trusting it.
Quick start
- Open the actor and paste one or more work emails into Emails.
- Leave Mode on
fulland set the proxy group to RESIDENTIAL (already the default). - Press Start. Each email takes a few seconds; 25 emails at
maxConcurrency: 25finish in under a minute. - Download the results as JSON, CSV or Excel from the Dataset tab, or pull them through the API.
Email mode, minimal:
{"emails": ["dylan.church@mintselection.com"]}
Keyword mode, minimal:
{"search": "head of growth fintech","locations": ["London"],"maxItems": 50}
Input reference
| Field | Type | Default | Description |
|---|---|---|---|
emails | array | — | Work emails to reverse-look up. Provide this or search, not both. Each entry is either a plain address ("jane@acme.com") or an object carrying its own company context: { "email": "jane@acme.com", "companyName": "Acme Group", "companyDomain": "acme.com" }. Per-entry hints win over the run-wide companyName / companyDomain, so a single run can cover thousands of addresses from different employers. |
search | string | — | Free-text people search query (e.g. "product manager fintech"). |
locations | string[] | — | Narrow keyword search by location (e.g. ["London"]). |
currentCompanies | string[] | — | Narrow keyword search by current employer (e.g. ["Revolut"]). |
schools | string[] | — | Narrow keyword search by school. |
companyName | string | — | Run-wide employer brand-name hint for email mode (e.g. "Emerald Carrying Company"). Used twice: to find extra candidates (an additional public search for "Name" "Company" linkedin when nothing found so far mentions that company) and to confirm a profile whose employer LinkedIn hides from guests. Useful when the email domain is an abbreviation of the company name. Overridden by a per-email hint. |
companyDomain | string | — | Run-wide employer domain hint for email mode. When set, it replaces the domain derived from the email for company matching. Overridden by a per-email hint. |
includeRawCandidates | boolean | false | When on, every row also includes rawCandidates[] — the full pre-filter candidate list with scores, matched signals and rejection reasons, so you can apply your own acceptance rules. |
maxItems | integer | 100 | Maximum profiles returned in keyword mode. |
mode | fast / full | full | fast returns identity fields only; full adds experience, education, summary, languages. |
maxConcurrency | integer | 8 | Parallel lookups. 25 is safe and the fastest tested setting. |
maxRunTimeSecs | integer | 3600 | Hard stop for the whole run. |
cacheTtlDays | integer | 14 | Profiles are cached by slug; repeat lookups within the TTL are near-free. Set 0 to always fetch fresh. |
proxyConfiguration | object | RESIDENTIAL | Residential proxies are strongly recommended (see FAQ). |
sessionCookies | string | — | Optional li_at cookie if you want to use your own session. Nothing depends on it. |
Output reference
One dataset row per email (email mode) or per profile (keyword mode), exportable to JSON, CSV, Excel, XML or HTML and available through the Apify API.
| Field | Meaning |
|---|---|
email | The input email (email mode) |
matched | true only when both name and company axes confirm the same profile |
confidence | 0–1 match score. On a blank row (matched: false) this is the score of the best candidate that was rejected, so you can see how close the row came |
confidenceLabel | high (≥ 0.8), medium (≥ 0.6) or low — always present, including on blank rows — pick your own acceptance threshold |
matchedSignals | Which verification signals fired, e.g. ["name-in-email", "domain-abbreviation"] |
bestCandidateUrl | Blank rows only: the profile that scored highest but was not published |
reasonCode | Machine-readable decision (table below) |
fullName, firstName, lastName | Parsed name |
headline, currentTitle, currentCompany, currentCompanyUrl | Current role |
titleSource | Where the job title came from: profile (experience section), headline (profile top card), search-snippet (public search result line) or null when no title could be verified. Titles are never guessed. A headline that reads like a pitch ("Interested in mobile technology and e-Commerce.") is kept in headline and not promoted to currentTitle. |
companySource | Where the employer came from: profile, search-snippet, input-hint (the companyName you sent with the email, used only on a verified match) or null |
companies | All companies seen on the profile (current + past) |
profileUrl | Canonical LinkedIn profile URL |
location, country | Public location |
photoUrl, followers, connections | Public profile metadata |
summary, languages, experience[], education[] | full mode only |
dataQuality | full or partial (partial = LinkedIn served an obfuscated guest page) |
rejectedCandidates[] | Candidates that failed verification, each with confidence, confidenceLabel, nameScore, domainScore, matchedSignals and rejectedReason — for auditing blank rows and tuning your own threshold |
rawCandidates[] | Only when includeRawCandidates is on: the full pre-filter candidate list with per-candidate scores, matchedSignals, accepted flag and rejection reason |
scrapedAt | ISO timestamp |
Matched signals
matchedSignals tells you exactly which evidence confirmed the match:
| Signal | Meaning |
|---|---|
name-in-email | The email local part encodes the person's name (first.last, flast, …) |
domain-website | The email domain matches the company website on the profile (strongest) |
domain-company-name | The domain matches the company name on the profile |
domain-abbreviation | The domain is an abbreviation of the company name (emcarry ↔ Emerald Carrying Company, ms ↔ Mint Selection) |
domain-past-company | The domain matches a past employer (weaker) |
domain-in-page-text | The company is masked, but the domain root appears in the visible profile text |
company-name-hint | Your companyName input matched the company on the profile |
outside-source | A page outside LinkedIn (company team page, press release) ties this person to the domain |
Reason codes
| reasonCode | Meaning |
|---|---|
MATCHED | Name and company both confirm the same profile |
AMBIGUOUS | Two or more candidates are equally plausible |
DOMAIN_MISMATCH | Name matches, but the person does not work at that domain |
NAME_MISMATCH | Nothing with a matching name was found |
NOT_FOUND | No public profile surfaced at all |
GENERIC_EMAIL | Gmail/Outlook address — no company signal exists |
ROLE_EMAIL | info@, sales@ — not a person |
TIME_LIMIT | The caller's run-time limit was reached; this row was saved before shutdown and can be retried |
Example row
{"email": "satya.nadella@microsoft.com","matched": true,"confidence": 0.96,"reasonCode": "MATCHED","fullName": "Satya Nadella","headline": "Chairman and CEO at Microsoft","currentCompany": "Microsoft","profileUrl": "https://www.linkedin.com/in/satyanadella"}
Common recipes
Enrich a CRM export. Export your leads as a CSV with an email column, upload it in the input editor (the actor accepts pasted lists), run, then download the dataset as Excel and join it back on the email column.
Skip non-people cheaply. Role mailboxes (info@, sales@) and free-mail addresses are rejected before any network traffic, so a dirty list costs almost nothing to clean.
Verify a cached row is still current. Set cacheTtlDays: 0 to bypass the cache and re-read the profile — useful before a big send.
Audit a blank row. Open the row's rejectedCandidates: you will see every candidate that was considered, its name/company scores, and why it was rejected.
Call it from your own app. Use the Apify API or the JavaScript/Python client with call(); the dataset items map one-to-one to your input emails.
Use cases
- Cold email personalisation — you have a verified email, you need the real name and title before you write the first line.
- CRM enrichment — fill missing
name,title,companyfields on inbound leads. - Lead qualification — confirm the contact still works at the company on the email domain.
- Recruiting — search candidates by keyword, company, location or school.
- Data hygiene — flag role mailboxes and free-mail addresses before they enter a sequence.
Speed and cost
- 25 emails in 47 seconds at
maxConcurrency: 25. - ~$0.003 per email including proxy usage, measured on a real run.
- Repeat lookups are close to free: profiles are cached by slug for
cacheTtlDays(default 14).
How the matching works
- Parse the email. Role mailboxes and free-mail providers are rejected instantly. Personal emails yield candidate name patterns and a company domain.
- Discover candidates. Search engines surface public
/in/profile URLs for the name; a direct slug guess from the email pattern is tried in parallel. - Read the public page. Structured data on the public profile gives name, headline, employer, location, experience and education.
- Score two axes. The name pattern must match the profile name, and the email domain must match the employer. If LinkedIn hides the employer on the guest page, the actor looks for an independent confirmation (company team page, press release) before deciding.
- Decide. Both axes agree →
MATCHED. Anything else → blank row with a reason code and the rejected candidates attached.
Limits and honest caveats
- Coverage depends on public visibility. Profiles with no public page, or pages LinkedIn heavily obfuscates for guest traffic, resolve to blank rather than to a guess. In the benchmark that was 6 of 25.
- Very short API timeouts reduce coverage. The actor respects the run timeout imposed by the caller and saves unfinished emails with
TIME_LIMITbefore shutdown instead of letting the run end asTIMED-OUT. For reliable enrichment, allow at least 60 seconds; large batches should use the default. - Very common names (think
john.smith@apple.com) may resolve to a real person with that exact name at that exact company who is still the wrong person. The two-axis check keeps this rare, but no public-data tool can eliminate it entirely. - No email extraction. Public profiles do not carry reliable email addresses, so this actor never invents them. It goes the other way: email in, identity out.
FAQ
Do I need a LinkedIn account or cookies?
No. The actor reads public pages. An optional li_at field exists only if you want to use your own session — nothing depends on it.
Will it return email addresses? No. It goes the other way: email in, identity out.
Why did some rows come back empty?
Because the two-way check did not pass. Read reasonCode and rejectedCandidates to see exactly why. An empty row is a deliberate answer, not a failure.
Which proxies should I use?
Residential. LinkedIn serves partially hidden ("*****") guest pages to datacenter addresses; dataQuality reports partial when that happens, and the actor never publishes an obfuscated field as if it were text.
Is scraping public LinkedIn data legal? Publicly accessible pages are generally scrapable, but you are responsible for how you use the data, including GDPR/CCPA duties for personal data. This actor collects no private, logged-in-only data.
Can I run it on a schedule or from my own app? Yes — Apify Schedules, the API, or any of the JavaScript/Python clients.
For AI agents (MCP-ready)
This actor is designed to be called by AI agents, not just humans. It works out of the box with the Apify MCP Server — add it to Claude Desktop, Cursor or any MCP client and the agent can resolve emails and search people on its own:
{"mcpServers": {"linkedin-profile-search": {"url": "https://mcp.apify.com/?actors=andrew_babo/linkedin-profile-search","headers": { "Authorization": "Bearer <YOUR_APIFY_TOKEN>" }}}}
Agent skill (paste into your agent's instructions)
You can resolve work emails to verified people using the"linkedin-profile-search" tool.WHEN TO USE- You have a work email and need the person's full name, job title,current company and LinkedIn URL.- You need to find people by job title / company / location / school.HOW TO CALL- Email lookup: { "emails": ["jane@acme.com"] }Better accuracy with context:{ "emails": [{ "email": "jane@acme.com", "companyName": "Acme Group" }] }- People search: { "search": "head of growth fintech","currentCompanies": ["Revolut"], "locations": ["London"] }OUTPUT CONTRACT- matched: true → fullName, jobTitle, currentCompany, profileUrl areverified on TWO independent axes (name pattern + company). Safe to usein a cold email greeting.- matched: false → do NOT guess or fill a name. Read reasonCode:NO_CANDIDATE (no public profile found), NO_COMPANY_EVIDENCE (personexists but employer could not be confirmed), ROLE_OR_FUNCTIONAL_EMAIL,FREE_EMAIL_PROVIDER, BELOW_MIN_CONFIDENCE. Report the reason, move on.- NEVER treat an empty row as an error. A blank row is a correct answer.- dataQuality: "partial" means LinkedIn hid some fields from guesttraffic; hidden fields are never fabricated.COST- ~$0.003 per email, 25 emails in under a minute. Cache makes repeatlookups nearly free for cacheTtlDays (default 14).