LinkedIn Profile Phone Number Scraper (Number Validation) avatar

LinkedIn Profile Phone Number Scraper (Number Validation)

Under maintenance

Pricing

Pay per usage

Go to Apify Store
LinkedIn Profile Phone Number Scraper (Number Validation)

LinkedIn Profile Phone Number Scraper (Number Validation)

Under maintenance

LinkedIn Profile Phone Number Scraper gathers public phone contacts for agencies and B2B teams. Filter profiles by job title, industry, or location to streamline prospecting and outbound calling at scale.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

Scrapier

Scrapier

Maintained by Community

Actor stats

0

Bookmarked

36

Total users

5

Monthly active users

2 days ago

Last modified

Share

LinkedIn Phone Number Scraper — Validated & Classified Numbers

LinkedIn Phone Number Scraper searches Google SERP for public LinkedIn results that mention a phone number, then runs every extracted number through libphonenumber to confirm its format and classify its line type. Instead of a bare digit string, each row returned includes isValid, phoneType, e164, nationalFormat, and carrierRegion — computed from the real number found in the result, not fabricated. Every response is structured JSON, ready to pass directly to an LLM, load into a CRM, or feed a lead-qualification pipeline. Run it once for a quick pull, or on a schedule to catch newly indexed numbers as Google's index changes.

What is LinkedIn Phone Number Scraper?

LinkedIn Phone Number Scraper queries Google (site:linkedin.com) for a list of keywords, LinkedIn usernames, or profile URLs, pulls phone numbers out of the matching result snippets, and validates and classifies every one with libphonenumber — Google's own phone-numbering-plan library. This is what separates it from a plain LinkedIn phone scraper: it doesn't just find numbers, it tells you whether each one is structurally valid for its region and what kind of line it is (mobile, fixed line, VoIP, toll-free, and more) before it ever reaches your dataset. No LinkedIn account or login is required — the Actor never authenticates to LinkedIn; it reads only what Google's public search index already returns.

Key capabilities:

  • Builds a Google dork per keyword (site:linkedin.com "<dial code>" "<keyword>") and pages through the SERP
  • Extracts phone numbers from matching result blocks and normalizes them toward E.164
  • Validates every extracted number's format with libphonenumber and reports why a number fails when it does
  • Classifies each parseable number's line type (mobile, fixed line, VoIP, toll-free, premium rate, and more)
  • Filters pushed rows by validationMode — keep everything, valid numbers only, or mobile numbers only
  • De-duplicates by E.164 across separate runs, so a number already returned before is not pushed (or charged) again

What data can you get with LinkedIn Phone Number Scraper?

The Actor writes two kinds of dataset rows: one phone-number result per matched search result, and a single run-summary row at the end of each run.

Result TypeExtracted FieldsPrimary Use Case
Phone-number resultplatform, keyword, title, description, url, phone_number, country, dial_code, isValid, phoneType, e164, nationalFormat, carrierRegion, validationReasonLead enrichment, contact discovery, outreach-list building
Run summaryrecord_type, validationMode, rows_examined, valid_count, invalid_count, mobile_count, filtered_out_count, deduped_count, pushed_countRun auditing — one row per run, not billed

Validation and classification fields

This is the part a raw LinkedIn scraper doesn't do. Every extracted number is parsed with phonenumbers (the Python port of libphonenumber) using the selected country as the default region, then:

  • isValidtrue only if libphonenumber's numbering-plan metadata confirms the number is a real, valid number for its region
  • phoneType — the classified line type: mobile, fixed_line, fixed_line_or_mobile, voip, toll_free, premium_rate, shared_cost, personal_number, pager, uan, voicemail, or unknown. This is set whenever the string parses as a number, even if isValid is false
  • e164 and nationalFormat — canonical formats computed from the parsed number
  • carrierRegion — the ISO region libphonenumber assigns to the number
  • validationReasonnull when the number is valid; otherwise "empty_number", "invalid_for_region", or a "parse_error: ..." message explaining why parsing failed
{
"isValid": true,
"phoneType": "fixed_line",
"e164": "+442079460000",
"nationalFormat": "020 7946 0000",
"carrierRegion": "GB",
"validationReason": null
}

This is format validation, not a live lookup. libphonenumber checks a number against published numbering-plan rules — length, prefix, structure for its region — the same way Android and other communication apps validate numbers offline. It does not dial the number, send an SMS/OTP, query a telecom carrier or HLR database, or confirm the number is currently in service, assigned, or reachable. A structurally valid number can still be disconnected or unassigned; a real, working number can still be marked invalid if the extracted text was truncated or malformed in the source snippet.

Run summary row

The last row pushed in every run has "record_type": "run_summary" and none of the phone-result fields above. It reports rows_examined, valid_count, invalid_count, mobile_count, filtered_out_count, deduped_count, and pushed_count for that run — useful for auditing a run without opening the log. It is pushed with a plain Actor.push_data() call and is not a row_result event, so it is not charged. Filter it out of downstream processing with item.get("record_type") != "run_summary", or simply check for the presence of phone_number.

⚠️ Why not build this yourself?

LinkedIn does not expose a public API for free-text, keyword-driven search across profiles that returns phone numbers — its official developer APIs are partner-gated and scoped to consented data, not open search. Reaching phone numbers embedded in public search results means scraping Google's SERP directly, which brings its own moving parts: rotating desktop user agents and Accept-Language headers, a dedicated GOOGLE_SERP proxy group, retry logic when Google returns a block page or a CAPTCHA interstitial, and jittered delays between requests. The Actor implements all of this — three retry attempts per page with 1–2 second pre-request jitter and 3–6 second backoff between attempts, and it stops paging a keyword after three consecutive pages come back empty, blocked, or with no new numbers. Google's response shape and blocking behavior change without notice, so maintaining this yourself means continuously re-tuning selectors and block detection. Running it as a hosted Actor means that maintenance, plus the proxy infrastructure, is already handled.

What's the difference between a phone number scraper and a phone number validator?

A phone number scraper extracts digit strings from a page — it tells you a sequence of characters that looks like a phone number was found. A phone number validator takes an existing number and checks it against numbering-plan rules to confirm it is structurally real and tells you what kind of line it is. Most LinkedIn contact scrapers only do the first: they return a phone_number string with no indication of whether it's actually a valid number for its country, or whether it's a mobile line worth an SMS campaign versus a landline that isn't.

LinkedIn Phone Number Scraper does both in one run: it finds the number, then immediately validates and classifies it before writing the row. The isValid, phoneType, e164, nationalFormat, and carrierRegion fields arrive in the same JSON object as the phone_number, title, url, and description fields the search produced — there's no separate validation pass or second Actor to run. Anyone who only needs the validation step against numbers they already have (not LinkedIn-sourced) should look at a standalone bulk phone-validation tool instead; this Actor is built for the discovery-plus-validation workflow specifically.

How to scrape LinkedIn with LinkedIn Phone Number Scraper?

  1. Open the Actor on its Apify Store listing and click Try for free (or Run, if you already have it saved)
  2. Fill the required keywords array with the terms, LinkedIn usernames, or profile URLs to search for, e.g. ["marketing", "founder"]
  3. Set the required country (e.g. "United Kingdom (+44)") — this drives both the Google dork's dial-code filter and the validation region — plus maxPhoneNumbers and validationMode if you want something other than the defaults
  4. Start the run
  5. Download results as JSON or CSV from the Dataset tab, or read them via the Apify API/apify_client

A run with keywords: ["marketing", "founder"] and country: "United Kingdom (+44)" internally builds one Google dork per keyword — site:linkedin.com "+44" "marketing", then site:linkedin.com "+44" "founder" — and pages through each until maxPhoneNumbers is reached or the empty-page stop condition triggers.

How to run multiple keywords in one job

keywords is an array, so a single run works through every keyword sequentially, applying the same country, maxPhoneNumbers, and validationMode to each. There's no separate batch-upload input — add every keyword, username, or profile URL to the same list and the Actor searches each one in turn, tagging each result row with the keyword that produced it.

⬇️ Input

Configure the run with the following fields. keywords and country are required; everything else has a default.

ParameterRequiredTypeDescriptionExample Value
keywordsYesarray of stringsA list of keywords, LinkedIn usernames, or profile URLs to search for.["marketing", "founder"]
platformNostring (enum: Linkedin)Select platform. For now this actor targets Linkedin via google.com SERP. Default: "Linkedin"."Linkedin"
countryYesstring (enum — full dial-code list)Select a country to scrape related phone numbers. The dial code is used to normalize and filter phone numbers. Default: "United Kingdom (+44)"."United Kingdom (+44)"
maxPhoneNumbersNointeger (min 1, max 10000)Maximum number of phone numbers to collect per keyword. The scraper will stop once this limit is reached. Default: 20.20
engineNostring (enum: legacy)Choose scraping engine. Default: "legacy"."legacy"
proxyConfigurationNoobject (proxy editor)Configure proxies for this Actor (Apify Proxy). The actor enforces the GOOGLE_SERP proxy group required for Google SERP scraping.{"useApifyProxy": true}
validationModeNostring (enum: all, valid_only, mobile_only)Filter which validated rows are pushed to the dataset. all keeps every extracted number (valid or not); valid_only keeps only numbers libphonenumber confirms are valid; mobile_only keeps only valid numbers classified as mobile or fixed-line-or-mobile. Default: "all"."valid_only"

No credentials, API key, or LinkedIn login is required for any of these fields — proxyConfiguration only toggles Apify Proxy on or off.

Example JSON input

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

Common pitfalls:

  • maxPhoneNumbers is a per-keyword ceiling, not a total across the whole keywords array — five keywords at the default of 20 can push up to 100 phone-number rows.
  • country isn't just a label — its dial code is matched against the digits in each result snippet, and it sets the default region libphonenumber validates against. Picking the wrong country for the numbers you're targeting will cause otherwise-real numbers to come back isValid: false or to be filtered out entirely.
  • engine currently accepts only "legacy" in the schema. Regardless of that value, proxyConfiguration's own apifyProxyGroups selection is not read — the Actor always forces the GOOGLE_SERP proxy group in code; only the useApifyProxy toggle from your proxy configuration is honored.
  • platform currently accepts only "Linkedin". Result parsing is hard-filtered to URLs containing linkedin.com regardless of this field, so there is no way to target another site with this Actor today.
  • The default validationMode is "all", which pushes invalid numbers too (with isValid: false and a validationReason). If you only want confirmed-valid numbers in the dataset, set validationMode to "valid_only" or "mobile_only" explicitly rather than filtering after the fact.
  • maxPhoneNumbers accepts up to 10000, but the three-consecutive-empty-page stop condition means the Actor will usually exhaust the available SERP results for a keyword well before a high ceiling like that is ever reached.

⬆️ Output

Results are written to the Actor's default dataset as typed JSON, one object per row, with a consistent schema across a given run. Download or stream them as JSON or CSV from the dataset, or pull them programmatically via the Apify API or apify_client.

Scraped results

[
{
"platform": "Linkedin.com",
"keyword": "marketing",
"title": "Jane Doe - Marketing Consultant | LinkedIn",
"description": "Freelance marketing consultant based in London. Call +44 20 7946 0000 to discuss your next campaign.",
"url": "https://uk.linkedin.com/in/jane-doe-example",
"phone_number": "+442079460000",
"country": "United Kingdom",
"dial_code": "+44",
"isValid": true,
"phoneType": "fixed_line",
"e164": "+442079460000",
"nationalFormat": "020 7946 0000",
"carrierRegion": "GB",
"validationReason": null
},
{
"platform": "Linkedin.com",
"keyword": "marketing",
"title": "Marketing Solutions Ltd | LinkedIn",
"description": "Reach our team on +44 7911 123456 for enquiries.",
"url": "https://uk.linkedin.com/company/marketing-solutions-example",
"phone_number": "+447911123456",
"country": "United Kingdom",
"dial_code": "+44",
"isValid": true,
"phoneType": "mobile",
"e164": "+447911123456",
"nationalFormat": "07911 123456",
"carrierRegion": "GB",
"validationReason": null
},
{
"platform": "Linkedin.com",
"keyword": "founder",
"title": "Alex Founder - Startup Founder | LinkedIn",
"description": "Founder profile mentioning a partial number +44 20 79...",
"url": "https://uk.linkedin.com/in/alex-founder-example",
"phone_number": "+442079",
"country": "United Kingdom",
"dial_code": "+44",
"isValid": false,
"phoneType": "unknown",
"e164": null,
"nationalFormat": null,
"carrierRegion": null,
"validationReason": "invalid_for_region"
},
{
"record_type": "run_summary",
"validationMode": "all",
"rows_examined": 14,
"valid_count": 9,
"invalid_count": 5,
"mobile_count": 4,
"filtered_out_count": 0,
"deduped_count": 2,
"pushed_count": 3
}
]

Output fields

FieldDescription
platformSource label built from the platform input, e.g. "Linkedin.com".
keywordThe keyword, username, or URL from the keywords array that produced this result.
titleThe search result's title.
descriptionThe search result's snippet text.
urlThe LinkedIn URL of the matching result.
phone_numberThe extracted phone number, normalized toward E.164 before validation.
countryThe country name portion of the selected country input (dial code excluded).
dial_codeThe dial code portion of the selected country input, e.g. "+44".
isValidtrue if libphonenumber confirms the number is valid for its region, else false.
phoneTypeClassified line type, or null if the number never parsed. See the validation fields section above for the full value list.
e164Canonical E.164-formatted number, or null if parsing failed.
nationalFormatNational (local) formatted number, or null if parsing failed.
carrierRegionISO region code libphonenumber assigns to the number, or null if parsing failed.
validationReasonnull when valid; otherwise "empty_number", "invalid_for_region", or a "parse_error: ..." message.
record_typePresent only on the run-summary row, with value "run_summary".
validationMode, rows_examined, valid_count, invalid_count, mobile_count, filtered_out_count, deduped_count, pushed_countPresent only on the run-summary row; per-run counts for auditing.

The 14 phone-result fields listed here are exactly what the default dataset view displays — there is no hidden field on a phone-result row beyond these. The run-summary row's fields are separate and are not part of that default view's column set, which is why it's worth filtering out before you process results downstream. Only phone-number result rows are charged (see below); the run-summary row is free.

How can I use the data extracted with LinkedIn Phone Number Scraper?

  • 📞 Sales and outreach teams: build a call list filtered to phoneType: "mobile" and isValid: true so SMS or call campaigns don't waste budget on landlines or malformed numbers.
  • 🤖 AI engineers and LLM developers: have an agent issue a keyword query, receive the structured JSON rows, and pass title, description, and the validation fields directly to the model as grounded context for lead scoring or enrichment.
  • 🔎 Recruiters and talent researchers: search by role or company keyword and use title/url/phone_number to reach candidates or contacts surfaced in public search results.
  • Data-hygiene and compliance teams: run with validationMode: "valid_only" to keep only structurally valid numbers out of a raw scrape before they ever enter a CRM or dialer list, using validationReason to see exactly why a rejected number failed.

How do you monitor new LinkedIn phone numbers over time?

Tracking new phone numbers surfaced for a keyword set is a repeated-query problem: run the same keywords and country on a schedule, and let the Actor's own cross-run de-duplication do the filtering for you. Every E.164 number the Actor ever pushes is recorded in a named key-value store (phone-validator-dedupe) that persists across runs of the Actor — not just within a single run — so a scheduled rerun only pushes (and charges for) numbers it has not returned before. In practice, this means the dataset from any run after the first is already the "what's new" delta, without you needing to diff two exports yourself.

To set this up, create an Apify Schedule against this Actor with the same input (keywords, country, validationMode) and a recurrence that matches how often you expect LinkedIn's Google-indexed content to change. Compare pushed_count on each run's summary row to gauge how much new data a given run surfaced, and watch phoneType and isValid on the newly pushed rows to see whether the fresh numbers are mobile leads worth acting on or invalid strings worth ignoring. There is no built-in webhook or alerting inside the Actor itself — pair the schedule with an Apify webhook on the ACTOR.RUN.SUCCEEDED event, or poll the dataset from your own pipeline, to turn new rows into an alert.

Integrate LinkedIn Phone Number Scraper and automate your workflow

LinkedIn Phone Number Scraper works with any language or tool that can call the Apify API — there is no LinkedIn credential or separate signup to manage.

REST API with Python

from apify_client import ApifyClient
client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("<YOUR_USERNAME>/linkedin-profile-phone-validator").call(
run_input={
"keywords": ["marketing", "founder"],
"country": "United Kingdom (+44)",
"maxPhoneNumbers": 20,
"validationMode": "valid_only",
}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
if item.get("record_type") == "run_summary":
continue
print(item["phone_number"], item["isValid"], item["phoneType"])

Scheduled monitoring and delivery

Use the Apify Console's Schedules to trigger runs at a fixed interval with saved input, and an Apify webhook on run success to push new results onward, or pull the latest dataset items via apify_client on your own polling interval.

Yes — scraping publicly accessible LinkedIn search results is generally lawful in the United States; LinkedIn Phone Number Scraper only returns what Google's public search index already surfaces from public profiles and posts, the same content any visitor without an account can see. In hiQ Labs, Inc. v. LinkedIn Corp., 938 F.3d 985 (9th Cir. 2019), the Ninth Circuit held that scraping publicly available LinkedIn profile data likely does not violate the Computer Fraud and Abuse Act. Because the output includes phone numbers tied to identifiable individuals, it is personal data under GDPR and CCPA, so storing, processing, or contacting people from it — not the act of collection itself — is where those regimes attach; scraping for internal research or monitoring carries a different risk profile than using the data to train AI models or for bulk unsolicited outreach. Consult your legal team for commercial use cases involving bulk data storage or direct contact of the individuals found.

❓ Frequently asked questions

Which countries does LinkedIn Phone Number Scraper support?

Any country in the country dropdown, each listed with its dial code (e.g. "Germany (+49)", "United States (+1)"). The dial code you select is used both to filter matching digits out of search snippets and as the default region libphonenumber validates against.

Can I limit results to only valid or only mobile numbers?

Yes, with validationMode. "all" (default) pushes every extracted number regardless of validity; "valid_only" pushes only numbers libphonenumber confirms are valid; "mobile_only" pushes only valid numbers classified as mobile or fixed_line_or_mobile. Rows that don't pass the selected mode are dropped before being pushed — they are never written to the dataset and never charged.

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

It rotates desktop user agents and Accept-Language headers per request, adds a 1–2 second jitter before each request and a 3–6 second backoff between retry attempts, and retries a page up to three times before giving up on it. A page is only treated as blocked when it shows a block marker (a /sorry redirect or strings like "unusual traffic" or "captcha") and contains no organic result containers — this avoids false positives from legitimate result pages that happen to reference Google's own "sorry" link in their page chrome. A keyword stops early after three consecutive pages come back empty, blocked, or with no new (non-duplicate, mode-passing) numbers.

Does LinkedIn Phone Number Scraper validate phone numbers, or just extract them?

Both, in the same row. Every extracted number is run through libphonenumber immediately after extraction, and the result — isValid, phoneType, e164, nationalFormat, carrierRegion, validationReason — is written into the same JSON object as the search-result fields. This is format and structure validation against libphonenumber's numbering-plan metadata; it is not a live carrier lookup, OTP send, or reachability check.

How many phone numbers does LinkedIn Phone Number Scraper return per keyword?

Up to maxPhoneNumbers per keyword (default 20, minimum 1, maximum 10000). The Actor stops a keyword early, before reaching that limit, if three consecutive search-result pages produce no usable new numbers.

Does filtering with validationMode affect what I'm charged for?

Yes. Only rows that pass the selected validationMode and aren't cross-run duplicates are pushed with the charged row_result event. Numbers filtered out by mode, or already seen in a prior run, are never pushed and never billed. The run-summary row is also never billed.

How do I use LinkedIn Phone Number Scraper to monitor new numbers over time?

Schedule the same keywords, country, and validationMode to run repeatedly via an Apify Schedule. Because cross-run de-duplication is keyed on E.164 and persists across runs, each subsequent run's dataset already contains only numbers not previously returned — check the pushed_count field on that run's summary row to see how many new numbers it found.

Does LinkedIn Phone Number Scraper work with Claude, ChatGPT, and AI agent frameworks?

It's callable as a standard Apify Actor via the Apify API and apify_client, so any agent framework that can make an HTTP call or run a Python/JS SDK client can trigger a run and read back the structured JSON — enabling a grounded agent that retrieves live, validated numbers before answering.

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

Checked on the Apify Store on 2026-07-25, api-empire's Linkedin Profile Phone Number Scraper documents the same base fields (platform, keyword, title, description, url, phone_number, country, dial_code) but no validation or line-type classification fields in its output table. pink_comic's Phone Number Validator & Lookup API does libphonenumber-based validation, formatting, and line-type classification with comparable depth, but takes a list of phone numbers as direct input rather than discovering them from LinkedIn search — it has no keywords, url, or title fields at all. LinkedIn Phone Number Scraper combines both steps: LinkedIn discovery via Google SERP and libphonenumber validation/classification, in one run.

Can I use LinkedIn Phone Number Scraper without managing proxies or LinkedIn credentials?

Yes. No LinkedIn login is required — the Actor never authenticates to LinkedIn, it only reads Google's public search results. Proxying is handled internally through Apify Proxy with the GOOGLE_SERP group; the only proxy-related input you can set is whether to use Apify Proxy at all.

What happens if a keyword returns no phone numbers?

The run simply produces no rows for that keyword — it does not fail the run. A keyword stops early once three consecutive search-result pages come back empty, blocked, or with no new number that passes validationMode and cross-run de-duplication. If a run pushes nothing at all, the log records: "No phone numbers were pushed. Try different keywords, a broader validationMode, or another country." Widening validationMode to "all", trying a broader or different keyword, or double-checking that country matches the numbers you expect are the first things to try.

💬 Your feedback

Found a bug or a field that doesn't match this documentation? Let us know through the Actor's Issues tab on Apify, or email scrapier.io@gmail.com. Reports help keep the extraction and validation logic accurate as Google's SERP layout changes.