LinkedIn Phone Number Scraper By Region & City Targeting avatar

LinkedIn Phone Number Scraper By Region & City Targeting

Pricing

from $2.99 / 1,000 results

Go to Apify Store
LinkedIn Phone Number Scraper By Region & City Targeting

LinkedIn Phone Number Scraper By Region & City Targeting

LinkedIn Phone Number Scraper collects phone contact data to support workforce research and outreach. Analyze roles, sectors, or regions while identifying direct contact points efficiently.

Pricing

from $2.99 / 1,000 results

Rating

0.0

(0)

Developer

SimpleAPI

SimpleAPI

Maintained by Community

Actor stats

0

Bookmarked

17

Total users

3

Monthly active users

3 days ago

Last modified

Share

LinkedIn Phone Scraper — City and Region Targeting

LinkedIn Phone Region Targeter finds publicly indexed phone numbers tied to LinkedIn content for a keyword, country, and — uniquely — a specific list of cities or regions within that country, tagging every result with exactly where it was geo-targeted from. It's built for local sales teams who need leads scoped to a specific metro area rather than an entire country, franchise and multi-location businesses researching phone contacts city by city, and lead-generation teams who want a per-city breakdown of how many leads and distinct numbers a search actually surfaced. No LinkedIn login is required — every number comes from Google's own indexed search snippets. Every section below documents an input, an output field, or exactly how the city targeting and deduplication work.

What is LinkedIn Phone Region Targeter?

This Actor is a superset of a country-wide LinkedIn phone-number scraper: it still runs the same keyword-plus-country Google dork search, and adds a cities list that repeats each keyword's search once per named city, tagging every resulting row with the city it was found under and emitting a real aggregated summary row per city once the run finishes.

Key capabilities, read from the source:

  • Per-city search + tagging. process_keyword() in src/main.py builds a separate Google query per city in your cities list (via build_queries()), and every phone row it finds is tagged with that city — leaving cities empty preserves the original country-wide, city-less behavior exactly.
  • Verified locations, not echoed input. Every candidate page is fetched and its own PostalAddress / location line is read. A record whose page does not place it in the region you asked for is dropped, so location, locality and region are always the page's values.
  • Traceable phone provenance. Every row records phoneSource, phoneSourceUrl and phoneSourceHost, so you can see exactly which document published each number and confirm it belongs to the entity in the url field.
  • GOOGLE_SERP-only proxying. create_proxy_configuration() always routes through the GOOGLE_SERP Apify proxy group specifically, because the module's own comment notes the RESIDENTIAL group serves Google's JS-gated shell with no real results over plain HTTP — GOOGLE_SERP is the only group that reliably returns a real results page.
  • Genuine block detection, not a status-code guess. fetch_html() classifies a response via is_block_page(), which inspects the actual response body rather than trusting the HTTP status alone, and retries with jitter before giving up on a query.

What data can I extract with LinkedIn Phone Region Targeter?

Every field in every row is read out of a page the Actor actually fetched. Nothing is inferred from the search query and nothing is lifted from a Google snippet. A field that cannot be sourced is omitted from the row — there are no "N/A" placeholders — and a record that cannot be fully verified is dropped rather than emitted half-empty.

FieldExample ValueWhere it comes from
phone_number+442039954222Normalised to E.164 and validated against the target country's dial code
phoneSourceabout_sectionWhich part of which page published the number (see below)
phoneSourceHostuk.linkedin.comThe host the number was actually read from
phoneSourceUrlhttps://uk.linkedin.com/company/...The exact document the number came from
name / titleGrowth Partners<h1> of the fetched LinkedIn page
entityTypecompany / personDerived from the entity URL path
headlineBusiness Consulting and ServicesIndustry / headline on the fetched page
description"...Call: +44 (0) 203 995 4222..."The entity's own About text
locationLondon, Greater LondonThe fetched page's own location line
locality / region / streetAddressLondon / Greater London / 160 Fleet StreetPostalAddress in the page's JSON-LD
cityLondonThe region you requested — only present when the page's own location matched it
urlLinkedIn entity URLThe verified profile / company page
websitehttp://www.growthpartners.orgThe entity's own external site, taken from the page
keyword, platform, country, dial_codeRun scope

Where a phone number can come from

phoneSource makes provenance explicit on every single row:

ValueMeaning
about_sectionThe organisation's own About us text on its LinkedIn page
profile_taglineThe entity's own meta/tagline description
own_postA post whose JSON-LD author.url resolves to this same entity — its own content, never a third party's
own_websiteThe entity's own external site, reached from the website link on its LinkedIn page

LinkedIn exposes no structured telephone field to logged-out visitors, so a number is only emitted when it appears in text the entity itself authored, or on the entity's own website.

Why not build this yourself?

Why not build this yourself?

LinkedIn does not expose phone numbers through any public API, and the only path to a public phone number tied to LinkedIn content is whatever Google has indexed in a page's visible snippet text — which means building and tuning a Google-dork query strategy, handling Google's own anti-automation detection (a "blocked" response often still returns HTTP 200 with a CAPTCHA-shaped body, not a clean error status), and routing through the specific proxy pool that actually returns real results rather than a JS-gated shell. This Actor already handles the correct proxy group selection, genuine body-based block detection with retry, and a query pattern that reliably surfaces LinkedIn-hosted content specifically — building that query and block-detection logic from scratch is most of the actual work.

How to use data extracted from LinkedIn Phone Region Targeter?

Local and regional sales teams

Set cities to your specific target metros within a country rather than running one broad country-wide search, and use the per-city summary rows to immediately see which cities produced the most leads before doing any manual review.

Franchise and multi-location businesses

Search a role or industry keyword across each of your franchise territories in one run. Because each row's locality and streetAddress come from the entity's own page, you can assign a lead to a territory on verified address data rather than on which search surfaced it.

Lead-generation and enrichment pipelines

Because every lead row already carries city and every summary row carries real aggregated counts, a pipeline can route leads to city-specific campaigns without any additional geocoding step.

Market coverage research

Compare how many verified leads each requested region yields for a given keyword to see where public, contactable coverage is densest. Because non-matching records are dropped rather than tagged, the per-region counts reflect real presence in that region.

🔼 Input sample

ParameterRequiredTypeDescriptionExample Value
keywordsYesarrayKeywords, LinkedIn usernames, or profile URLs to search for.["plumber", "electrician"]
countryYesstring enumCountry to scope the search and dial-code matching to (full list of ~150 countries with dial codes)."United Kingdom (+44)"
citiesNoarrayCity/region names to geo-target within the selected country. Each keyword is searched once per city. Leave empty for a country-wide search.["London", "Manchester"]
platformNostring enumCurrently only "Linkedin". Default "Linkedin"."Linkedin"
maxPhoneNumbersNointeger (1–10000)Max phone numbers to collect per keyword. Default 20.50
useApifyProxyNobooleanRoute through Apify Proxy (GOOGLE_SERP group). Default true.true
{
"keywords": ["marketing"],
"country": "United Kingdom (+44)",
"cities": ["London", "Manchester"],
"maxPhoneNumbers": 30
}

Common pitfall: maxPhoneNumbers caps new phone numbers per keyword, not per city — with multiple cities set, the cap is checked as leads accumulate across all cities for that keyword, so a keyword may reach its cap on an earlier city and collect nothing further from the remaining cities in that pass. Split a broad multi-city sweep into multiple keyword variants if you want a guaranteed minimum per city.

🔽 Output sample

One JSON row per verified phone lead, pushed to the run's default dataset and charged as one row_result event per row. This is a real row from a live run:

{
"recordType": "lead",
"platform": "Linkedin.com",
"keyword": "marketing consultant",
"city": "London",
"entityType": "company",
"name": "Growth Partners",
"title": "Growth Partners",
"headline": "Business Consulting and Services",
"description": "Growth Partners is a flexible consultancy platform with global capabilities... Call: +44 (0) 203 995 4222 Email: info@growthpartners.org",
"url": "https://uk.linkedin.com/company/growth-partners-consultancy",
"phone_number": "+442039954222",
"phoneSource": "about_section",
"phoneSourceUrl": "https://uk.linkedin.com/company/growth-partners-consultancy",
"phoneSourceHost": "uk.linkedin.com",
"location": "London",
"locality": "London",
"streetAddress": "160 Fleet Street",
"website": "http://www.growthpartners.org",
"country": "United Kingdom",
"dial_code": "+44"
}

Note that region is absent from this row: LinkedIn published no addressRegion for this company, so the key is omitted rather than filled with a guess.

How do you target specific cities and regions?

The city is verified against the fetched page, not just appended to a query. Appending a city name to a Google dork only biases which results come back — it proves nothing about where a record is. This Actor treats the city as a filter on real data:

  1. Each city becomes its own Google query, so "marketing" in London and
    "marketing" in Manchester
    are two genuinely separate searches.
  2. Every candidate LinkedIn page is then fetched, and its own location is read from the PostalAddress in its JSON-LD (addressLocality, addressRegion, streetAddress) or its top-card location line.
  3. A record whose own page does not place it in the requested region is dropped, not emitted with the requested city copied onto it. The location, locality and region you get back are the page's values, not your input echoed back.

Because of step 3, a run can legitimately return fewer rows than candidates found — that is the filter working. The run log prints each drop and why.

Country subdomains are not location evidence. Google returns uk.linkedin.com, ca.linkedin.com and similar host variants as a routing artefact. The Actor never treats the subdomain as a location signal; only the fetched page's address fields count.

The per-keyword limit applies per region. maxPhoneNumbers is enforced for each keyword and each requested region, so an early city cannot consume the whole budget and starve the rest of your list.

Leaving cities empty runs a single country-wide pass per keyword with no region filter; rows then carry no city key.

▶️ Want to try other LinkedIn scrapers?

ScraperWhat it extracts
LinkedIn Profile Contact ExtractorContact details parsed from a profile
LinkedIn Company URL Mass Profile FinderBulk company URL discovery with executive contacts
LinkedIn Jobs Scraper — Employer & Company DetailsJob postings with employer profile data
LinkedIn Comments and Reactions ScraperPost comments, replies and reaction breakdown

How to extract phone-number leads programmatically

This Actor runs as a standard Apify Actor call — one API call in, structured JSON dataset out, using your Apify API token.

Python example

from apify_client import ApifyClient
client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("<YOUR_USERNAME>/linkedin-phone-region-targeter").call(run_input={
"keywords": ["marketing"],
"country": "United Kingdom (+44)",
"cities": ["London", "Manchester"],
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
if item.get("recordType") == "lead":
print(item["phone_number"], item["city"], item["url"])

Export to spreadsheets or CRM

Every dataset supports one-click CSV/Excel export from the Apify Console. Filter on recordType to separate lead rows from per-city summary rows before loading into a CRM.

This Actor only surfaces phone numbers already published in Google's own publicly indexed search results — it does not access LinkedIn directly or bypass any LinkedIn login. Phone numbers tied to an identifiable individual are personal data under GDPR/CCPA, so treat storage and outreach accordingly, and be aware that unsolicited phone or SMS outreach is separately regulated in most jurisdictions (TCPA in the US, PECR in the UK, and equivalents elsewhere). Consult legal counsel before using this data for outbound calling or messaging campaigns.

❓ FAQ

Does maxPhoneNumbers apply per city or per keyword overall?

Per keyword and per region. Each requested city gets its own budget, so a city early in your list cannot exhaust the quota and leave later cities empty.

How do I know a phone number really belongs to the profile in the url field?

Every row carries phoneSource, phoneSourceUrl and phoneSourceHost. A number is only accepted from the entity's own About text, its own tagline, a post whose JSON-LD author resolves to that same entity, or the entity's own website — never from a comment, a caption, or another company's content that happens to share the page.

Why are some fields missing from a row rather than empty?

Because the Actor never pads a record. If LinkedIn published no street address or region for a company, those keys are simply absent. Every key that is present holds a real, fetched value.

Do I need a LinkedIn account to use this?

No. Everything is read from publicly accessible pages. Note that LinkedIn returns HTTP 999 to un-proxied traffic and rate-limits per egress address, so the Actor rotates through a pool of proxy addresses and backs off automatically — leave the proxy enabled.

Why did a search return no phone numbers at all?

Either no candidate page in that region published a phone number in text the entity itself authored, or every candidate failed the region check. The run log lists each dropped candidate with the reason. Try a broader keyword or a larger region.

How does this compare to other LinkedIn phone-number scrapers?

As observed on the Apify Store on 2026-07-26, scraper-mind/linkedin-phone-number-scraper and api-empire/linkedin-profile-phone-number-scraper both extract phone numbers by keyword and country, but neither documents city/region-level targeting or a per-city aggregated summary row — that geo-targeting layer is unique to this Actor.

Does this work with AI agent frameworks?

Yes — call it as a standard HTTP endpoint via the Apify API from any agent framework capable of making an API call; there's no MCP-specific integration for this Actor.

Conclusion

LinkedIn Phone Region Targeter turns a keyword-and-country phone-number search into a city-scoped one — every lead tagged with where it was found, cross-city repeats tracked rather than duplicated or dropped, and a real aggregated summary per city. It fits local sales, franchise, and territory-based lead-generation work that needs geography built into the search itself. Start a run from the Apify Console or the Apify API with your target keywords, country, and cities to get your first geo-tagged lead export.