LinkedIn Phone Number Scraper & Email Finder
Under maintenancePricing
Pay per usage
LinkedIn Phone Number Scraper & Email Finder
Under maintenanceAutomate phone number extraction from LinkedIn with LinkedIn Phone Number Scraper. The actor scans profiles and external links to pull available contact numbers into structured datasets for CRM enrichment.
Pricing
Pay per usage
Rating
0.0
(0)
Developer
API Empire
Maintained by CommunityActor stats
0
Bookmarked
19
Total users
0
Monthly active users
a day ago
Last modified
Categories
Share
LinkedIn Phone Number Scraper — Extract Phones, Emails & Profiles
Find publicly available phone numbers and email addresses tied to LinkedIn profiles and company pages — without logging in to LinkedIn. You supply keywords, job titles, or LinkedIn profile/company URLs plus a target country, and the Actor searches Google's indexed results for matching LinkedIn pages and pulls out any contact details that already appear in the public snippet text. Every response is typed, normalized JSON — no HTML, no CSS selectors, no manual parsing. After a run you have a deduplicated table of LinkedIn matches, each flagged for whether it carries a real phone number, a real email, or both.
What is LinkedIn Phone Number Scraper & Email Finder?
LinkedIn Phone Number Scraper & Email Finder is an Apify Actor that runs targeted site:linkedin.com Google searches for the keywords you provide, then extracts and normalizes any phone numbers and email addresses visible in the returned search-result titles and snippets. It never logs in to LinkedIn, never requests a LinkedIn cookie or session token, and never loads a LinkedIn profile page directly — it only reads what Google has already indexed publicly. No LinkedIn account is required to run it.
- 📞 Extract phone numbers and normalize them to E.164 using the country dial code you select
- 📧 Extract, validate, lowercase and deduplicate email addresses from the same result snippet
- 🔍 Search by keyword, job title, industry term, or a LinkedIn profile/company URL
- 🎯 Filter output rows to only the contact type you need — phone only, email only, both, or either
- 📤 Export results as JSON or CSV straight from the Apify dataset
📊 What data does LinkedIn Phone Number Scraper & Email Finder collect?
Every dataset row is a single LinkedIn search-result match, carrying three kinds of data at once: the contact numbers found, the contact emails found, and the search-result metadata that tells you where they came from.
| Data Type | Key Fields | JSON Field Names |
|---|---|---|
| Phone Numbers | E.164-normalized number, whether one was found, the dial code used to validate it | phone_number, hasPhone, dial_code |
| Email Addresses | Validated inbox addresses found in the snippet, the first one picked as primary, whether any were found | emails, primaryEmail, hasEmail |
| LinkedIn Profile & Company Matches | Result title, snippet text, the LinkedIn URL, the keyword that produced it | title, description, url, keyword, platform, country |
Need more LinkedIn data?
If you need full profile history (experience, education, skills) rather than just contact details, or company firmographics, pair this Actor with the other LinkedIn scrapers published under the API Empire account — including a dedicated LinkedIn jobs scraper and a LinkedIn company/profile finder. Each covers a different slice of LinkedIn's public data so you are not paying for fields you don't need.
Why not build this yourself?
LinkedIn does not offer a public API that lets a third-party developer search its membership by keyword and retrieve contact details — its official developer platform is scoped to partner-approved products (advertising, sign-in, talent products) and does not expose a "find phone number or email by keyword" endpoint at all. The realistic alternative to an Actor like this one is not "call LinkedIn's API," it's "scrape Google's search results yourself," and that carries real, ongoing engineering cost:
- Block detection. Google returns a JS-gated interstitial shell to unrecognized traffic. This Actor keys detection specifically on phrases like "our systems have detected unusual traffic" and the
/sorry/index?continueredirect path — get this wrong and you either treat good pages as blocked (silently return nothing) or blocked pages as good (silently return garbage). This Actor's earlier detection logic did exactly the former; a broad "sorry"/"captcha" keyword match flagged even legitimate results pages, and it had to be narrowed to the phrases above before it worked reliably. - Markup fragility. Result blocks are matched against specific Google SERP container classes (
div.MjjYud, falling back to the olderdiv.tF2Cxc). Google changes these periodically without notice; maintaining a scraper means watching for that breakage and shipping a selector update. - Proxy routing. Residential proxy IPs get served the JS-gated shell with no results — only Apify's
GOOGLE_SERPproxy group reliably returns a real results page over plain HTTP. Getting proxy group selection wrong looks like "the scraper works but returns nothing," which is a hard failure mode to debug from the outside. - Retry and timeout tuning. Each SERP fetch runs under a 60-second total timeout (30 seconds to connect, 30 seconds to read), retries up to three times on a failed or blocked page with a randomized delay between attempts, and a keyword gives up after three consecutive empty or failed pages rather than hanging indefinitely. Tuning these by hand takes iteration; get the retry count too low and a transient block looks like "no results," too high and a genuinely blocked run burns your whole timeout budget on one keyword.
If you only need a handful of lookups occasionally, doing this by hand in a browser is viable. For repeated, keyword-driven runs at volume, an Actor that already handles block detection, retries and proxy routing is the lower-maintenance path.
Why do developers and teams scrape LinkedIn for phone numbers and emails?
🤖 For AI engineers and agent builders
Contact-enrichment is a common tool call inside a sales or recruiting agent: given a company or role, find a reachable person. Because every row returns typed fields (phone_number, emails, hasPhone, hasEmail) instead of HTML, an agent can call this Actor as a tool, check hasEmail before attempting outreach, and pass primaryEmail straight into the next tool call — a mail-merge step or a CRM write — without a parsing layer in between.
📈 For sales and growth teams
Outbound teams use keyword or job-title searches ("head of growth", "founder") combined with requireContact: "email" to build a list of reachable prospects for a given role, filtered to rows that actually carry a usable address rather than a profile URL alone. Running the same keyword against multiple countries (by changing the country input) builds region-specific outreach lists without separate tooling.
🧑💼 For recruiters and talent teams
Recruiters search a role or skill keyword ("devops engineer", "clinical research associate") and use requireContact: "phone" to shortlist candidates whose public LinkedIn footprint already surfaces a callable number, skipping the InMail queue entirely for the subset of candidates that publish direct contact details.
🔬 For researchers and analysts
Labour-market and industry researchers use broad keyword sweeps (an industry term, a job title, a company name) across a country to gauge how many professionals in a segment publish public contact details on LinkedIn, using hasPhone/hasEmail as a simple public-visibility signal rather than to build a communications list.
How to scrape LinkedIn phone numbers and emails (step by step)
- Open LinkedIn Phone Number Scraper & Email Finder on the Apify Store and click Try for free (or Start, if you already have it saved) to open the run console — no separate signup or API key is needed beyond your Apify account.
- Fill in
keywords— an array of search terms, job titles, or LinkedIn profile/company URLs. At least one keyword is required. - Select the required
country— its dial code is used both to localize the Google search and to validate/normalize any phone numbers found. Optionally setrequireContactto keep only rows with a phone, only rows with an email, rows with both, or leave it onany. - Click Start and let the run finish — it works through your keyword list one at a time, paginating Google results until it hits
maxPhoneNumbersor runs out of indexed matches. - Open the Dataset tab and export results as JSON, CSV, Excel, or another supported format, or pull them programmatically via the Apify API.
What happens if LinkedIn or Google changes its structure
The Actor is maintained, and its output schema — the field names and types documented below — stays stable on your end even when the underlying Google SERP markup or LinkedIn's public snippet format changes internally. No specific update turnaround is promised here; check the Actor's build history on its Apify Store page for the latest maintenance activity.
⬇️ Input
All input fields, exactly as defined in the Actor's input schema:
| Parameter | Required | Type | Default | Constraints |
|---|---|---|---|---|
keywords | Yes | array of strings | — | editor: stringList. A list of keywords, LinkedIn usernames, or profile URLs to search for. |
platform | No | string | "Linkedin" | enum: "Linkedin" (only option currently offered). |
country | Yes | string | "United Kingdom (+44)" | enum of 172 country + dial-code strings (full list below). |
maxPhoneNumbers | No | integer | 20 | minimum 1, maximum 10000. Applies per keyword, not to the whole run. |
requireContact | No | string | "any" | enum: "any" (phone or email), "phone" (phone only), "email" (email only), "both" (phone and email). |
useApifyProxy | No | boolean | true | editor: checkbox. Routes Google search requests through the Apify GOOGLE_SERP proxy group. |
Field descriptions, verbatim from the schema:
keywords— A list of keywords, LinkedIn usernames, or profile URLs to search for. Example:["marketing", "founder"].platform— Select platform. For now this actor targets Linkedin via google.com SERP.country— Select a country to scrape related phone numbers. The dial code is used to normalize and filter phone numbers.maxPhoneNumbers— Maximum number of contact rows (phone and/or email) to collect per keyword. The scraper will stop once this limit is reached.requireContact— Filter which rows are kept:anykeeps every result with a phone OR an email;phonekeeps only rows with a real phone;emailkeeps only rows with a real email;bothkeeps only rows that have a real phone AND a real email.useApifyProxy— Route Google search requests through Apify Proxy (recommended). The Actor fetches reliable, unblocked search results automatically. Turn this off only if you intend to run without a proxy.
Example JSON input
{"keywords": ["marketing", "founder"],"platform": "Linkedin","country": "United Kingdom (+44)","maxPhoneNumbers": 20,"requireContact": "any","useApifyProxy": true}
Common pitfall: setting requireContact to "both" on a broad, generic keyword can return very few or zero rows — Google's public snippet text rarely surfaces a phone number and an email for the same person in the same result. Start with "any" or "email" and tighten the filter once you see how much your keyword actually surfaces.
How keyword and URL entries are handled differently
A plain keyword (a job title, industry term, or name) becomes one Google query: site:linkedin.com "<dial code>" "<keyword>", narrowed to your selected country's dial code when one was resolved.
A LinkedIn profile or company URL (linkedin.com/in/…, /pub/…, or /company/…) is handled differently. The Actor extracts the URL's slug, strips LinkedIn's trailing vanity-ID hash (so louis-rose-9057562b becomes louis rose), and tries up to three fallback queries in order until one returns results: the decoded name plus the dial code, the decoded name alone, and finally the raw slug itself. This exists because an exact-URL match on Google frequently returns nothing even when the profile is indexed under a slightly different canonical URL — the fallbacks trade query precision for a better chance of finding the same person. Only the first query that returns any result rows is used; the Actor does not merge results from multiple fallback queries for the same keyword.
⬆️ Output
Results are pushed to the Actor's default dataset as one JSON object per LinkedIn match, and can be exported as JSON, CSV, Excel, XML, RSS or HTML directly from the Apify Console or via the API. The dataset's default view already shows every field the row-building code writes — there are no hidden columns beyond what's listed here.
Scraped contact record
A row with both a phone number and an email found in the same result snippet:
{"platform": "Linkedin.com","keyword": "marketing","title": "Jane Doe - Marketing Director at Acme Ltd","description": "Get in touch: jane.doe@acme-example.co.uk | +44 7412 345678 | 10+ years in B2B marketing...","url": "https://uk.linkedin.com/in/jane-doe-example","phone_number": "+447412345678","country": "United Kingdom","dial_code": "+44","emails": ["jane.doe@acme-example.co.uk"],"primaryEmail": "jane.doe@acme-example.co.uk","hasPhone": true,"hasEmail": true}
A row where the snippet carried only an email — phone_number stays null, it is never guessed or fabricated:
{"platform": "Linkedin.com","keyword": "founder","title": "John Smith - Founder & CEO","description": "Reach out via founder@startup-example.com for partnership inquiries.","url": "https://www.linkedin.com/in/john-smith-example","phone_number": null,"country": "United Kingdom","dial_code": "+44","emails": ["founder@startup-example.com"],"primaryEmail": "founder@startup-example.com","hasPhone": false,"hasEmail": true}
| Field | Type | Description |
|---|---|---|
platform | string | The normalized platform label, e.g. "Linkedin.com". |
keyword | string | The exact keyword from your input list that produced this row. |
title | string | The Google search-result title for the matched LinkedIn page. |
description | string | The Google search-result snippet text the contact details were extracted from. |
url | string | The LinkedIn URL of the match (Google redirect/safety wrappers are resolved to the real link). |
phone_number | string or null | The phone number normalized to E.164 (e.g. "+447412345678"), or null when no valid phone was found. |
country | string | The country name resolved from your country input. |
dial_code | string | The dial code used to validate and normalize phone numbers, e.g. "+44". |
emails | array of strings | All validated, lowercased, deduplicated email addresses found in the result's title + snippet text. Can be empty. |
primaryEmail | string or null | The first entry in emails, or null if the array is empty. |
hasPhone | boolean | true when phone_number is a real, validated number. |
hasEmail | boolean | true when emails contains at least one address. |
Deduplication across a run
The Actor tracks every (url, contact) pair it has already pushed for the whole run, not just per keyword or per page. If the same LinkedIn result surfaces again — for a different query fallback, or because two of your keywords happen to match the same page — it is not pushed and not charged a second time. A page that carries more than one distinct phone number produces one row per distinct number (each with its own key), while a page with several emails but no phone still produces a single row, since emails is a list on one row rather than one row per address.
How contact extraction actually works
Phone numbers are matched with a regex that looks for an international run (+44 7585 467400), a 00-prefixed international run (0044 7585 467400), or a national run starting with a trunk 0 (07585 467400) of at least 8 digits. Each match is then normalized: national numbers get the trunk 0 swapped for your selected country's dial code, duplicated country-code prefixes are collapsed, and the result is rejected unless it is between 10 and 14 digits and starts with your selected country's dial code. A number for the wrong country, or a stray ID that happens to look like a phone number, is dropped rather than pushed as a false positive.
Email addresses are matched with a standard local-part@domain regex, then filtered: addresses ending in an asset-file extension (.png, .jpg, .css, .js, and similar) or matching known placeholder domains (example.com, sentry.io, yourdomain.com, and similar) are discarded, along with any address with a leading or trailing dot in the local part.
Honest hit-rate expectation: this Actor only surfaces a phone number or email when the person or company has already published it somewhere Google indexes on their public LinkedIn presence. Most professional profiles do not publish a phone number or a personal email in the parts of the page Google indexes — whether a given keyword returns contacts at all depends entirely on whether that information is public. Broader keywords (a job title, an industry term) generally surface more matches than a single narrow name search, simply because more result pages exist to search.
How does LinkedIn Phone Number Scraper & Email Finder compare to other LinkedIn scrapers?
| Feature | This Actor | Generic alternative |
|---|---|---|
| Output format | Typed JSON, stable field names | Varies — several competitors return unstructured or loosely typed fields |
| LinkedIn login required | No — reads Google's public index only | Some website/social scrapers crawl target pages directly, which risks blocks |
| Contact-type filtering | Built-in requireContact input (any/phone/email/both) | Not offered as a first-class filter by themineworks/b2b-leads-finder (checked on the Apify Store, 2026-07-25) |
| Source provenance per row | url, title, and description returned with every contact, so you can see exactly which snippet it came from | themineworks/b2b-leads-finder labels email confidence (found/pattern_matched/guessed) but generates addresses from patterns rather than only reading what's published (Apify Store listing, checked 2026-07-25) |
| Proxy handling | Apify GOOGLE_SERP proxy group wired in by default (useApifyProxy) | Varies by Actor; some require you to configure proxy groups manually |
If you're building an AI agent or RAG pipeline, the output format row is the decision-maker — parsing HTML inside an agent loop is a reliability failure mode, not a feature. A typed field like hasEmail lets an agent branch on a boolean instead of regex-matching a raw page.
How many results can you scrape with LinkedIn Phone Number Scraper & Email Finder?
maxPhoneNumbers sets a per-keyword cap (default 20, minimum 1, maximum 10000) — the Actor stops collecting for a given keyword once that many contact rows have passed your requireContact filter. There is no separate cap on the total run: with multiple keywords, the effective ceiling is maxPhoneNumbers × number of keywords. Setting a high maxPhoneNumbers on a large keyword list can produce a very large, slow, and expensive run, since every kept row is billed individually — size it to what you actually need.
Under the hood, each keyword paginates Google's search results 10 results at a time, retrying a blocked or failed page up to 3 times before moving on, and gives up on that keyword after 3 consecutive empty or failed pages rather than looping indefinitely. In practice this means the real ceiling for a narrow keyword is however many matching, contact-carrying LinkedIn pages Google has actually indexed — not the number you set in maxPhoneNumbers. No benchmark run time is published here; none has been measured for this documentation.
Integrate LinkedIn Phone Number Scraper & Email Finder and automate your workflow
LinkedIn Phone Number Scraper & Email Finder works with any language or tool that can send an HTTP request, through the Apify API.
REST API integration
from apify_client import ApifyClientclient = ApifyClient("<YOUR_API_TOKEN>")run = client.actor("<YOUR_USERNAME>/linkedin-phone-email-finder").call(run_input={"keywords": ["marketing", "founder"],"country": "United Kingdom (+44)","maxPhoneNumbers": 20,"requireContact": "any",})for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item["title"], item.get("primaryEmail"), item.get("phone_number"))
Works in Python, Node.js, Go, Ruby, cURL — any client that can call the Apify API.
MCP for AI agents
The Actor is reachable as an MCP tool through Apify's MCP server without any extra setup on your side:
https://mcp.apify.com/?tools=<YOUR_USERNAME>/linkedin-phone-email-finder
Compatible with Claude, ChatGPT, and any MCP-capable agent client.
Automation platforms (n8n, Make)
Apify publishes an official Apify node for n8n and an official Apify app/module for Make that can run any public Actor by ID, including this one — add the node or module, set the Actor ID to <YOUR_USERNAME>/linkedin-phone-email-finder, supply the same input fields documented above, and the run's dataset becomes available as the next step's input without custom API code.
Is it legal to scrape LinkedIn for phone numbers and emails?
Yes — this Actor only returns data that is already publicly visible in Google's search index; it does not log in to LinkedIn, bypass any access wall, or read non-public profile fields. Because the output is personal data (names, phone numbers, and email addresses tied to identifiable individuals), regimes like the GDPR and CCPA govern how you may store, process, and use it — public availability does not remove your obligations around lawful basis, retention, and giving people a way to object. Consult legal counsel for commercial use cases involving bulk personal data, particularly before using extracted contacts for unsolicited outreach at scale.
❓ Frequently asked questions
Does LinkedIn Phone Number Scraper & Email Finder work without a LinkedIn account?
Yes. The Actor never authenticates with LinkedIn — no login, no cookies, no session token. It only fetches Google search results and reads the LinkedIn pages that already appear in them.
How often is the scraped data updated?
Every run performs a live Google search at the moment you start it — there is no cached or pre-scraped dataset behind this Actor. Results reflect whatever Google has indexed for your keywords right now.
What happens when a keyword returns zero contacts?
The row-building step only produces a row when a result block on the LinkedIn domain actually contains a phone number, an email, or both — if nothing on a page has a public contact detail, no row is created for it, and the run log records "No contacts were collected" for that keyword rather than failing. Try a broader keyword, or set requireContact back to "any" if you had it narrowed to "phone", "email", or "both".
Can I scrape private or restricted LinkedIn content?
No. Only what is visible in Google's public search snippet is ever extracted — the Actor never loads a LinkedIn profile page directly, so login-gated or connections-only content is never touched.
How much does a run cost?
The Actor bills per contact row actually written to the dataset (the row_result charged event) — rows dropped by your requireContact filter are never pushed and never charged. The exact price per row is shown on the Actor's Apify Store page before you run it.
Does LinkedIn Phone Number Scraper & Email Finder work for AI agent workflows and LLM pipelines?
Yes. It's callable as an HTTP endpoint through the Apify API from any agent framework, and it's also exposed as an MCP tool via Apify's MCP server (see the integration section above). Every response is typed JSON with stable field names, so no parsing step is needed before passing results to an LLM.
How does it handle Google's anti-bot defenses?
The Actor doesn't scrape LinkedIn directly, so LinkedIn's own anti-bot system is never in play — the countermeasures here are for Google's SERP. It rotates between four browser-like user agents and several accept-language values per request, adds a randomized delay before each fetch, routes traffic through Apify's GOOGLE_SERP proxy group by default, retries a blocked or failed page up to three times, and checks each response against known block-page phrases (like Google's "unusual traffic" interstitial) before treating it as usable.
How does it compare to other LinkedIn or contact-finding scrapers?
The closest comparable Actor on the Apify Store, themineworks/b2b-leads-finder, also searches public LinkedIn profiles via Google rather than a pre-built database, and pairs that with pattern-generated business emails and company-website scraping — its listing describes email-confidence labels (found/pattern_matched/guessed) for addresses it infers (checked 2026-07-25). This Actor takes a narrower, more literal approach: it only returns a phone number or email that is already written out in the LinkedIn result snippet itself, never a pattern-guessed address.
Does it return data in a format LLMs can use directly?
Yes. Every row is typed, normalized JSON with stable field names — no HTML, no CSS selectors, no parsing step. Pass it directly into an LLM context window, index it into a vector store, or route it through an agent tool call.
Can I use it without managing proxies?
Yes. With useApifyProxy left at its default true, the Actor provisions an Apify GOOGLE_SERP proxy connection for you automatically — there's no separate proxy account or configuration to manage.
What happens if LinkedIn or Google changes its structure or blocks the scraper?
The Actor is maintained, and the output schema documented above stays stable on your end regardless of internal changes to Google's SERP markup or LinkedIn's snippet format. No specific turnaround time is promised here — check the Actor's Apify Store page for its current build and maintenance history.
💬 Your feedback
Found a bug, an edge case the extraction misses, or a field you need that isn't here? We want to know — reach out through the Actor's Apify Store page or the API Empire developer's Apify profile. Reports like these are what keep the block-detection logic and extraction rules current.