Linkedin Profile Phone Number Scraper avatar

Linkedin Profile Phone Number Scraper

Pricing

Pay per usage

Go to Apify Store
Linkedin Profile Phone Number Scraper

Linkedin Profile Phone Number Scraper

Automate phone number extraction from LinkedIn profiles with LinkedIn Profile 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

4.5

(5)

Developer

API Empire

API Empire

Maintained by Community

Actor stats

1

Bookmarked

365

Total users

62

Monthly active users

1.4 days

Issues response

6 hours ago

Last modified

Share

LinkedIn Phone Number Scraper — Extract Numbers, Titles and URLs

LinkedIn Phone Number Scraper searches Google's public index for linkedin.com pages and pulls out any phone number written in the result's title or snippet, normalising each one to E.164 and filtering it against the dial code of the country you pick. Every row returns eight typed JSON keys — the search result's title, description and url, the extracted phone_number, and the country/dial_code/keyword/platform context around it. No HTML, no selectors, nothing to parse. This Actor does one job: find and normalise phone numbers. It does not score, grade or rank the leads it finds — for that, a separate scoring Actor exists elsewhere in this catalogue. Give it a list of keywords and a country, press Start, and rows land in the dataset as each Google results page is parsed.

What is LinkedIn Phone Number Scraper?

LinkedIn Phone Number Scraper is an Apify Actor that turns a keyword and a country into a list of publicly indexed linkedin.com search results that contain a phone number in visible text. For each keyword it runs a site:linkedin.com Google query, pages through the organic results, scans each result block for a phone-shaped string, and keeps only the ones that normalise to a valid number matching your chosen country's dial code.

No LinkedIn account, login, session cookie or API token is required — LinkedIn is never contacted directly. The only credential involved is your Apify token. There is no li_at cookie field, no session field, and nothing marked as secret in the input schema, because nothing LinkedIn-specific is ever collected as a credential — the Actor authenticates to nothing.

Unlike a lead-scoring variant of this search that also computes a 0–100 outreach score, a letter grade and a guessed seniority tier, this Actor stays deliberately narrow: it returns the raw search result and the normalised phone number, and nothing else. If you need a ranked call list, that's a different Actor's job. If you need clean, verifiable phone-number rows with the source URL attached, this is the one.

  • Search LinkedIn-indexed pages by keyword, role, company name, or a partial username
  • Normalise every matched number to E.164 (+ followed by digits)
  • Filter numbers to the dial code of the country you select
  • Export as JSON, CSV, Excel or XML, or read the dataset over the Apify API
  • No proxy setup, no Google-blocking logic to write yourself

What data does LinkedIn Phone Number Scraper collect?

Every row is one Google result block matched to one phone number, but the eight fields split cleanly into three groups: where the number came from, the number itself, and the country context used to find and validate it.

Data TypeKey FieldsJSON Field Names
Search result identitywhich keyword matched, the result's title and snippet, the LinkedIn URLplatform, keyword, title, description, url
Phone numberthe number itself, normalised to E.164phone_number
Country / dial-code contextthe country you selected and the dial code used to filtercountry, dial_code

🤖 Need more LinkedIn contact data?

If a url in your results needs a name, job title or employer attached, LinkedIn Phone Number Scraper & Email Finder — also published under this account — runs a similar search but adds email discovery and a contact-completeness filter on top of the phone number. Reach for it when a number alone isn't enough to qualify a contact.

How does LinkedIn Phone Number Scraper work?

The pipeline is four steps, run once per keyword and repeated per results page until the keyword's limit or empty-page cutoff is hit.

1. Query construction. Each keyword becomes a Google query of the form site:linkedin.com "<dial code>" "<keyword>" — a site-restricted search with the dial code and the keyword both quoted as exact phrases. If a country's dial code can't be parsed, the dial-code term is simply omitted from the query and a warning is logged; the search still runs on the keyword alone, but phone matching becomes less strict since there's no dial code to filter on.

2. Fetching. The query is sent to google.com/search through Apify's GOOGLE_SERP proxy group, paginated ten results at a time (start=0, start=10, start=20, …). Each request carries a randomised desktop user-agent and accept-language header. A response is retried up to three times with proxy rotation between attempts if it looks blocked.

3. Parsing. The HTML is parsed with BeautifulSoup. Each organic result container (div.MjjYud) is required to have an <h3> title inside a link element with an href, and that href must contain linkedin.com — anything else is skipped. The title and the snippet (.VwiC3b) are flattened to plain text with Unicode NFKC normalisation and zero-width-character stripping.

4. Phone extraction and validation. Every phone-shaped substring in the combined block text is tested with a regex that requires at least eight characters between an optional leading + and a trailing digit. Each candidate is normalised toward E.164, then kept only if its digit count falls between 8 and 15 (the E.164 significant-digit bounds) and the normalised number starts with the selected country's dial code. The first candidate in a block that passes both checks becomes that row's phone_number; a block that yields no valid candidate produces no row at all.

Only the first ten results on the first attempted page order come from Google's own ranking — the Actor does not re-sort, re-rank or otherwise interpret relevance. It reports what Google returned, filtered down to what parses as a real, dial-code-matching phone number.

Why not build this yourself?

LinkedIn's own APIs are partner-gated and expose no public search or contact-lookup endpoint, so there is no official API to compare this Actor against — the realistic alternative is writing the Google-SERP plumbing yourself, and that plumbing is where the effort goes.

Block detection is not a substring match. A naive implementation greps the response body for captcha or /sorry/. That fails immediately here: Google embeds a reference to /sorry/index in the anti-automation JavaScript of every normal results page, so a bare substring match flags close to every healthy page as blocked. This Actor instead checks the HTTP status, whether the final resolved URL actually navigated to /sorry/, and whether a block phrase appears without any genuine result-container marker (<h3, or one of Google's own result-wrapper CSS classes) corroborating it. A block phrase alone is not enough; it has to be uncorroborated by a real result.

Phone-number normalisation has real edge cases. A snippet number already written in international form without a leading + — for example 44 7911 123456, or + 44 (0)20 7946 0958 with a space after the + — gets captured by the extraction regex with the dial-code digits already at the front of the string. A normaliser that unconditionally re-prepends the dial code turns that into +44447911123456 instead of +447911123456. This Actor checks whether the candidate already starts with the target dial-code digits before deciding whether to prepend anything, and drops a leftover trunk 0 left by a (0) marker in the same pass.

Then there's the long tail: rotating user-agent and accept-language pools, jittered delays between requests, a retry budget with proxy rotation on each retry, whitespace and zero-width-character normalisation on scraped text, and an E.164 digit-length check (8–15 significant digits) to reject phone-shaped junk like truncated IDs. All of it runs inside the Actor so you don't have to build or maintain it.

Why do developers and teams search LinkedIn for phone numbers?

For sales and business development teams

A rep building an outbound list for a niche — say, operations managers at logistics companies — runs a handful of role and industry keywords against their target country and gets back only the linkedin.com results Google has indexed with a visible number, skipping the manual work of opening dozens of profiles to see if a number is even published.

For recruiters and talent sourcers

Recruiters filling a role in one country search by job title and location term, then open url on each match to confirm the candidate before ever placing a call — the phone number is a shortcut to a warm first contact, not a replacement for reading the profile.

For small business owners doing direct outreach

A local agency or consultancy targeting prospects in one country searches by industry keyword and dial-codes on their own market, so every number returned is already pre-filtered to a country they can actually call without an international rate.

For researchers studying public contact-info exposure

Analysts studying how often professionals in a given field or country publish a direct number on a public, indexable page can compare row counts across keyword and country combinations — this Actor reports what Google has indexed, which is a measurable, if partial, proxy for public exposure.

For developers building contact-enrichment pipelines

A developer wiring phone discovery into an internal CRM or outreach tool calls this Actor over the Apify API with a rotating keyword list, writes phone_number, url and dial_code straight into a record, and uses title/description as the human-readable evidence a rep sees before dialling. Because the schema is fixed and typed, no parsing layer sits between the Actor and the downstream table.

How to search LinkedIn for phone numbers (step by step)

  1. Open LinkedIn Phone Number Scraper on its Apify Store listing and click Try for free
  2. Add one or more entries to Keywords / Usernames / URLs (keywords) — a role, industry term, or company name works best
  3. Pick a Country (country) from the dropdown — this sets the quoted dial code in the Google query and the filter applied to every number found
  4. Optionally raise or lower Max Phone Numbers (maxPhoneNumbers) — this caps rows collected per keyword, not per run
  5. Click Start, then export the dataset as JSON, CSV or Excel, or read it through the Apify API

keywords and country are the two required inputs. An empty or missing keywords array logs ❌ No keywords provided. Please fill the 'keywords' array with at least one value. and the run ends immediately with nothing collected and nothing charged.

What happens if Google changes its search results layout?

The Actor is maintained, and its output schema — the eight field names and types on every row — does not change on your end even when the underlying scrape logic is updated. The parser depends on specific Google result markup (div.MjjYud containers, an <h3> title, a .VwiC3b snippet class), which is Google's markup, not LinkedIn's — a LinkedIn redesign has no effect on this Actor at all, since LinkedIn pages are never fetched. A Google SERP markup change is the actual dependency, and when Google changes it, this parser is updated. No specific turnaround time is promised.

⚠️ Limits you should know before your first run

Most LinkedIn profiles do not publish a phone number in indexed text, so expect low yield. LinkedIn discourages putting a personal number in a public headline or summary, and even when one is present on the page, Google has to have indexed that exact text for it to show up in a snippet. Do not plan a campaign around a high hit rate — many keyword and country combinations will return few rows, or none, and that is normal, correct behaviour, not a bug.

maxPhoneNumbers is a per-keyword limit, not a per-run total. Ten keywords at maxPhoneNumbers: 50 is a target of up to 500 rows, not 50. Each keyword pages through Google independently until its own limit is met or it hits three consecutive result pages that return nothing.

Deduplication only happens within a single Google results page, not across the run. The set of "already-seen" URLs is created fresh every time a page of results is parsed, so it is not shared across pages of the same keyword, and never shared across different keywords. If the same LinkedIn URL surfaces under two different keywords in your list — a realistic outcome, since one profile can plausibly match both "founder" and "marketing" — it is pushed, and charged, as two separate rows. If you run multiple keywords, deduplicate on url or phone_number after export if you need one row per contact.

engine currently has one selectable value, and it does not change proxy behaviour. The dropdown only offers legacy, and internally the Actor always requests the Apify GOOGLE_SERP proxy group regardless of what value reaches it — the field's own description mentions a cost-effective mode using RESIDENTIAL proxies, but that value is not present in the input's enum and the proxy-setup code has no branch that would act on it even if it were supplied directly through the API. There is nothing to configure here today; leave it on the default.

proxyConfiguration.apifyProxyGroups is not read. Only useApifyProxy (on/off) is read from the object you provide. Whatever proxy group you set is discarded — the Actor always forces GOOGLE_SERP, per its own description of enforcing that group.

A keyword gives up after three consecutive empty or failed pages. If Google returns nothing usable, or the same request fails, three times in a row for a keyword, the Actor stops that keyword and moves to the next one, keeping whatever rows it already collected. It will not keep paging indefinitely looking for the last few numbers toward your maxPhoneNumbers target.

⬇️ Input

Two inputs are required: keywords and country. Everything else has a default.

ParameterRequiredTypeDescriptionExample Value
keywordsYesarray of stringsA list of keywords, LinkedIn usernames, or profile URLs to search for. Prefilled with ["marketing"].["cto", "founder"]
countryYesstringSelect a country to scrape related phone numbers. The dial code is used to normalize and filter phone numbers. 194 values in the dropdown, e.g. Afghanistan (+93) through Zimbabwe (+263). Default "United Kingdom (+44)"."United Kingdom (+44)"
maxPhoneNumbersNointegerMaximum number of phone numbers to collect per keyword. The scraper stops once this limit is reached. Minimum 1, maximum 10000. Default 20.50
platformNostringSelect platform. For now this Actor targets LinkedIn via google.com SERP. Enum has one value: "Linkedin". Default "Linkedin"."Linkedin"
engineNostringChoose scraping engine. Enum has one value: "legacy". Default "legacy". Its own description references a 'cost-effective' RESIDENTIAL-proxy mode, but that value is not selectable and the code does not implement it — see the limits section above."legacy"
proxyConfigurationNoobjectConfigure proxies for this Actor (Apify Proxy editor). Only the on/off useApifyProxy flag is actually read; the Actor always enforces the GOOGLE_SERP proxy group regardless of any group you set here.{"useApifyProxy": true}

Honest notes on how these behave:

  • keywords has no URL or username parsing. Despite the field's title ("Keywords / Usernames / URLs") and description, every entry is wrapped in quotes and sent to Google as a literal exact-phrase term — the code does not detect a LinkedIn URL and extract a name or slug from it. Pasting https://www.linkedin.com/in/jane-doe/ into keywords produces a query that searches for that literal URL string, which usually returns few or no results. Use a name, job title, industry term or company name instead.
  • country drives three things at once: the quoted dial code inserted into the Google query, the filter every extracted number must pass, and the country/dial_code values stamped on every row. It is parsed by splitting the trailing (+…) off the display string — "United Kingdom (+44)" becomes the name United Kingdom and the dial code +44.
  • maxPhoneNumbers is per keyword, not a total across the run — see the limits section above for the arithmetic.

Example input

{
"keywords": ["cto", "founder"],
"platform": "Linkedin",
"country": "United Kingdom (+44)",
"maxPhoneNumbers": 50,
"engine": "legacy",
"proxyConfiguration": {
"useApifyProxy": true
}
}

Common pitfall: pasting a full LinkedIn profile URL into keywords expecting a profile-specific search. The Actor doesn't parse URLs — it uses whatever string you provide as a literal quoted Google search phrase, so a URL almost never matches. Use a role, name or company term.

⬆️ Output

Typed, normalised JSON — the same eight keys on every row, in the same order, run after run. There is no field that can come back missing: a row is only ever written once a phone number has been successfully extracted and validated, so every key is always populated (an empty snippet still produces description: "" rather than a missing key). Rows are pushed to the dataset live as each Google results page is parsed, not batched at the end of the run. Export as JSON, CSV, Excel or XML, or read the dataset through the Apify API. The default dataset view shows all eight fields — nothing is hidden behind the view.

Every row is charged once, as one row_result event. The Actor never writes a placeholder, header, error or diagnostic row — a keyword that finds nothing contributes zero rows to the dataset and costs nothing. There is no status or isError field to filter on because there is nothing to filter: a row existing means a valid phone number was found. The one caveat is that deduplication is per-page only (see the limits section) — the same URL and number pair can legitimately appear, and be charged, more than once if it surfaces under more than one keyword.

Scraped phone number result

{
"platform": "Linkedin.com",
"keyword": "cto",
"title": "Jane Doe - CTO | LinkedIn",
"description": "Jane Doe. CTO at BrightLabs Ltd. Call or WhatsApp +44 7911 123456 for partnership enquiries.",
"url": "https://uk.linkedin.com/in/jane-doe",
"phone_number": "+447911123456",
"country": "United Kingdom",
"dial_code": "+44"
}
FieldDescription
platformSource label built from your platform input, e.g. Linkedin.com.
keywordThe exact entry from your keywords list that produced this row.
titleText of the Google result's <h3> heading, whitespace-normalised.
descriptionThe Google snippet for that result, or "" when no snippet element matched.
urlThe linkedin.com URL from the result's link element, as returned by Google — not unwrapped from any tracking redirect.
phone_numberThe number normalised to + followed by digits only, filtered to match dial_code.
countryCountry name with the dial code stripped off, e.g. United Kingdom.
dial_codeDial code parsed from your country selection and used to build the query and filter results, e.g. +44.

A second row, from a different keyword and country in the same run, showing how the fields shift with the input:

{
"platform": "Linkedin.com",
"keyword": "founder",
"title": "Priya Raman - Founder - Northwind Media | LinkedIn",
"description": "Founder of Northwind Media, an independent retail marketing agency. Direct line +1 415 555 0148.",
"url": "https://www.linkedin.com/in/priya-raman/",
"phone_number": "+14155550148",
"country": "United States",
"dial_code": "+1"
}

Both rows share the same eight keys in the same order — only the values change with the keyword, the country you selected, and what Google actually returned.

How does LinkedIn Phone Number Scraper compare to other LinkedIn phone scrapers?

FeatureLinkedIn Phone Number ScraperGeneric alternative
Output field documentationAll 8 fields documented with exact JSON keys and how each is derivedStore listings checked on the Apify Store, 25 July 2026, for similarly named LinkedIn phone-number Actors list the same 8 field names but illustrate them with placeholder values such as "country": "Global" and "dial_code": "Auto-detected" that don't correspond to how the input actually works
Extraction rule transparencyE.164 normalisation rule, dial-code filter, and the 8–15 digit E.164 length bound documented from sourceNot documented in the listings checked
Engine / proxy behaviourDocuments that engine currently has one working mode and that GOOGLE_SERP is enforced regardless of the value passedNot documented
Duplicate-row handlingDocuments that deduplication is per-page only, not per-runNot documented
Billing transparencyStates exactly which event is charged (row_result) and that unmatched pages are never pushed or chargedNot documented

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.

How many phone numbers can you scrape with LinkedIn Phone Number Scraper?

maxPhoneNumbers caps rows per keyword, from 1 to 10000, default 20 — a run with five keywords at the default setting can collect up to 100 rows total, not 20. There is no separate run-level cap in the Actor itself; the practical ceiling for a keyword is whichever comes first: hitting maxPhoneNumbers, or three consecutive Google results pages that return no usable rows for that keyword (page size is Google's standard ten results per page). Because deduplication only happens within a single results page, a keyword that keeps surfacing the same handful of profiles across pages will not silently shrink toward a unique-contact count — plan for some repeats when you search overlapping keywords. No benchmark run time is published for this Actor.

Integrate LinkedIn Phone Number Scraper and automate your workflow

LinkedIn Phone Number Scraper works with any language or tool that can send an HTTP request, because it runs as a standard Apify Actor.

REST API integration

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("<YOUR_USERNAME>/linkedin-profile-phone-number-scraper").call(run_input={
"keywords": ["cto", "founder"],
"country": "United Kingdom (+44)",
"maxPhoneNumbers": 50,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
print(row["keyword"], row["phone_number"], row["url"])

Works in Python, Node.js, Go, Ruby, cURL — any language that can make an HTTP request.

Automation platforms (n8n, Make)

In n8n, use the Apify node — or an HTTP Request node pointed at the Apify run-sync endpoint with your token — and pass the same JSON input shown above; a Set or Filter node downstream can split rows by dial_code before they reach a CRM node. In Make, the Apify module runs the Actor and feeds its dataset output directly into a Google Sheets or Airtable module, so a recurring keyword sweep needs no code.

Yes — collecting phone numbers and names that individuals or Google have already made publicly visible in an indexed search snippet, without logging in or bypassing any access control, is broadly treated as permissible. LinkedIn Phone Number Scraper returns only what appears in Google's own public search results; it never logs in to LinkedIn or accesses anything behind a wall.

Because the output includes personal data — names, phone numbers and profile URLs tied to identifiable individuals — GDPR (if you or the data subjects are in the EU/UK) and CCPA (for California residents) can apply to how you store, use and retain it, separately from whether the initial collection was lawful. You are responsible for having a lawful basis for your own use of any personal data you collect, and for honouring deletion or opt-out requests.

Consult legal counsel for commercial use cases involving bulk personal data, particularly outbound contact campaigns.

❓ Frequently asked questions

Does LinkedIn Phone Number Scraper work without a LinkedIn account?

Yes. No LinkedIn login, session cookie or API token is used or requested anywhere in the input schema. The Actor never contacts LinkedIn directly — it reads Google's public index of linkedin.com pages. The only credential you need is your Apify token.

How often is the scraped data updated?

Every run performs a live Google search at the moment it executes — there is no caching layer in the Actor. Results reflect whatever Google's index shows for your query at run time, which can change between runs as Google re-crawls and re-indexes pages.

What happens when a keyword returns no phone numbers?

This is common and expected — see the limits section above. The Actor pages through up to three consecutive results pages for that keyword; if none produce a valid phone number matching your country's dial code, it logs that no more numbers were found and moves to the next keyword. No row is written and nothing is charged for that keyword.

Can I scrape private or login-gated LinkedIn content with this Actor?

No. The Actor only reads what Google has publicly indexed from linkedin.com — it never authenticates to LinkedIn and never fetches a LinkedIn page directly, so anything behind LinkedIn's login wall (contact-info panels, private profile fields, InMail) is out of reach by design.

Do I get charged for a run where no phone numbers are found?

No. Only rows that contain a successfully extracted and validated phone number are pushed to the dataset, and only pushed rows are charged under the row_result event. A run that finds nothing for every keyword finishes with an empty dataset and no row_result charges.

Does LinkedIn Phone Number Scraper work for AI agent workflows and LLM pipelines?

Yes. It's callable as a standard HTTP endpoint through the Apify API, so any agent framework that can make a request — LangChain, CrewAI, a custom tool definition, n8n — can invoke it and receive typed JSON rows directly, with no HTML or parsing step in between.

How does LinkedIn Phone Number Scraper handle Google's anti-bot system?

Requests go through Apify's GOOGLE_SERP proxy group. Each page gets up to three fetch attempts, each preceded by a randomised 1–2 second delay and a freshly rotated user-agent and accept-language header drawn from small pools of current desktop-browser strings; a failed or blocked attempt waits a further randomised 3–6 seconds and rotates to a new proxy URL before retrying. A response is treated as blocked on a 429/503/4xx/5xx status, on the final URL resolving to /sorry/, or on a genuine interstitial phrase that is not corroborated by any real result marker in the same page — a design specifically meant to avoid false-positiving on Google's own anti-automation boilerplate, which appears on every normal page. There is no CAPTCHA solving; a keyword that exhausts its retries on three consecutive pages is stopped and the run continues with the next keyword.

How does LinkedIn Phone Number Scraper compare to other LinkedIn phone scrapers?

Checked on the Apify Store, 25 July 2026, similarly named listings from other accounts describe the same eight output fields but with generic, non-representative example values and no documentation of the extraction rule, the dedup behaviour, or the proxy/engine caveats covered in this README. A differently named competitor's listing title advertises "80% coverage" for LinkedIn profile URL phone enrichment (observed on the Apify Store, 25 July 2026) — that is the competitor's own unverified claim about their own product, not a measurement of this Actor or of how many LinkedIn profiles actually publish a phone number in Google's index; treat any such coverage figure with the same scepticism this README applies to its own numbers.

Does LinkedIn Phone Number Scraper return data in a format LLMs can use directly?

Yes. Every row is typed, normalised JSON with the same eight field names on every run. No HTML, no selectors. Pass a row straight into an LLM context window, index it into a vector store, or hand it to an agent tool with no transformation step required.

Can I use LinkedIn Phone Number Scraper without managing proxies?

Yes. The Actor always routes search requests through Apify's GOOGLE_SERP proxy group — you never create a proxy account, choose an exit country, or rotate an IP yourself. The only proxy setting you control is whether Apify Proxy is used at all (useApifyProxy).

What happens when Google changes its search results layout or blocks the scraper?

The scraper is maintained, and the output schema — field names and types — stays stable on your end even when the parsing logic underneath is updated to match a Google markup change. No specific turnaround time is promised for any given update.

Can I search multiple keywords in one run?

Yes. keywords is a list — add as many role, industry or company terms as you need. Each keyword is processed in turn within the same run, its own maxPhoneNumbers limit applies independently, and rows for every keyword land in the same dataset, tagged by the keyword field so you can split them back out afterward.

Which fields should I index for AI training data or RAG?

description carries the most context per row — it's the raw Google snippet, so it usually contains the number in its original written form along with the surrounding sentence. title, keyword and url are useful metadata filters alongside it. phone_number, country and dial_code are the normalised, already-structured fields — index those separately from the free text if you want clean lookups rather than semantic search.

💬 Your feedback

Found a bug, or a phone number your keyword should have matched but didn't? We want to know. Open an issue on the Actor's Issues tab on Apify, and include the keyword and country you ran — that's the fastest way to reproduce and fix a parsing gap.