# Google Serp Scraper Lead Finder

> Find public LinkedIn profiles that match a plain-language description via Google search. Get profile URL, name, headline and snippet per lead, plus public location when shown. No login. Pay per lead.

Actor id `quaking_pail/google-serp-scraper-lead-finder`. Index of all Epsimo actors: https://epsimo.org/llms.txt

## What it does

### Google Serp Scraper Lead Finder

A LinkedIn lead discovery Actor that queries search engines for public LinkedIn profile pages matching a plain-language profile description and optional location, scraping Google search result pages over HTTP (no browser) and optionally visiting public profiles to augment results. It turns natural-language role/industry/city queries into site-specific web searches, decodes search redirect links to canonical LinkedIn profile URLs, normalizes and de-duplicates profiles across pages, retries blocked or unreadable pages on new IPs, and falls back to an alternative search engine only when the primary search engine fails. The Actor extracts per-lead data such as the profile URL, name and headline derived from the search result title, the search snippet, public location when available from a visited profile, an indicator whether the profile page was visited, source/search-engine metadata, processing notes, and timestamps — producing one consolidated lead row per matched profile. It can also process a supplied list of LinkedIn profile URLs directly.

### Use cases

- Build prospect lists from a short natural-language profile description (role, industry, city).
- Generate targeted outreach lists for sales and SDR teams (e.g., "Head of Growth, SaaS, Berlin").
- Find decision makers for an account list to enrich in a CRM.
- Source candidate leads for recruitment from public LinkedIn profiles.
- Research who holds specific roles at target companies for founders and marketers.

## Use cases and Limits

From the actor README on the Apify Store.

### Use cases for LinkedIn lead search

- Build a list of "Head of Growth, SaaS, Berlin" profiles for outreach.
- Find decision makers for an account list, then enrich them in your CRM.
- Source candidates for a role from public profiles.

### How much will it cost to find LinkedIn leads?

You **pay per lead, with no subscription** and no rental. One lead is one row saved to the dataset. Failed requests, retries and diagnostics go to the key-value store record `FAILED_REQUESTS` and are never billed. A run that finds no leads ends as failed and charges no leads. A small standard Actor start event applies to every run. See the **Pricing** tab for current prices, including discounts on higher Apify plans.

The run stops at **Maximum Results** or at your **maximum cost per run**, whichever comes first.

### Tips for better LinkedIn lead results

- Use specific job titles plus an industry or city.
- Turn off **Scrape LinkedIn Profiles** for faster runs. You still get URL, title, snippet, and the name and headline from the search title. You lose only the location.
- Keep **Google Proxy Groups** empty so Google goes through `GOOGLE_SERP`.
- Keep the default Google strategy. **Bing Only** no longer searches Bing alone: Bing is currently unreliable, so that option also starts with Google.

### FAQ, disclaimers and support

#### Is it legal to scrape LinkedIn profiles from search results?

Our Actors are ethical and do not extract any private user data. This Actor does not extract email addresses, phone numbers or gender. It only reads what Google shows in public search results and what a LinkedIn member has chosen to show on their public profile. However, you should be aware that your results could contain personal data. Personal data is protected by the GDPR in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers.

Every lead is personal data. **You are responsible for making sure that your scraping and your use of the results are legal**, including LinkedIn's terms, GDPR and anti-spam rules for outreach.

#### Why is the headline masked with asterisks on some leads?

When the Actor visits a public profile, LinkedIn often hides the headline from anonymous visitors behind asterisks, and the profile value replaces the one from the search title. The headline is still readable in the `title` field. If you need clean headlines in the `headline` column, turn off **Scrape LinkedIn Profiles**.

#### Why do some leads have no location?

The location comes only from a visited public profile. Leads behind a LinkedIn login wall, and all leads when **Scrape LinkedIn Profiles** is off, have `location: null`.

#### Why did I get fewer leads than Maximum Results?

Google returned fewer matching profiles, or your exclude keywords removed some. Check the log and the `FAILED_REQUESTS` record in the key-value store.

#### Why did my run fail?

A run that finds no leads fails on purpose, so you can tell an empty search from a successful one, and no leads are charged. Try a broader profile description, keep the default Google strategy, or try again later.

#### How do I report a problem?

Open an issue in the **Issues** tab with the run ID. If the Actor saved you time, a rating on the **Reviews** tab helps other users find it.

## Input

| Name | Type | Required | Default | Allowed values / range | Description |
|---|---|---|---|---|---|
| `profile_description` | string | yes | - | - | Description of the profile you're looking for (e.g., 'marketing manager startup') |
| `location` | string | no | - | - | Optional location to target (e.g., 'Paris, France') |
| `exclude_keywords` | array | no | - | - | Optional keywords to exclude from search. Page 1 uses Google's -keyword operator. Google returns no later pages for such queries, so pages 2+ are fetched without the operators and results whose title, snippet or profile URL contains an excluded word or phrase (case-insensitive, whole words) are dropped and not charged. The operator-free list starts at the page that came back empty, so its own first page is skipped and runs with exclusions may return fewer leads. |
| `max_results` | integer | no | `10` | min 1; max 10000 | Maximum number of leads to extract (one dataset row per lead). Values above 1000 are capped to 1000. |
| `scrape_profiles` | boolean | no | `true` | - | Visit each public LinkedIn profile to add name, headline and location. Each lead is still one row; if LinkedIn shows a login wall, the row keeps the search snippet only. |
| `search_engine_strategy` | string | no | `"google_with_fallback"` | `"google_only"` (Google Only), `"bing_only"` (Bing Only (unreliable, now uses Google first)), `"rotation"` (Rotate Between Google and Bing (Bing currently unreliable)), `"google_with_fallback"` (Start with Google, Fallback to Bing if Blocked) | Which search engine to use. Google (GOOGLE_SERP proxy) first, Bing as fallback: Bing is used automatically when Google blocks the run or finds no LinkedIn profiles. Bing is currently unreliable: it answers automated requests with results unrelated to the query. Bing Only is kept for compatibility but now runs like the default (Google first, Bing as fallback) and logs a warning. Since 0.20, Rotate also starts with Google and uses Bing only as a fallback. |
| `use_direct_linkedin` | boolean | no | `false` | - | Whether to use direct LinkedIn URLs instead of search |
| `linkedin_urls` | array | no | - | - | Direct LinkedIn profile URLs to scrape (if use_direct_linkedin is true) |
| `proxy_country` | string | no | `"US"` | `"US"` (United States), `"UK"` (United Kingdom), `"FR"` (France), `"DE"` (Germany), `"CA"` (Canada), `"AU"` (Australia), `"JP"` (Japan), `"SG"` (Singapore), `"NL"` (Netherlands), `"BR"` (Brazil), `"IN"` (India) | Country code for proxy location |
| `proxy_groups` | array | no | - | - | Apify Proxy groups for Bing search pages and LinkedIn profile pages |
| `google_proxy_groups` | array | no | - | - | Optional Apify Proxy groups for Google search pages. Leave empty to use GOOGLE_SERP, the Apify Google SERP proxy built for Google result pages and billed per request (recommended). Other groups, such as datacenter proxies, are often rate-limited by Google (HTTP 429). |
| `timezone` | string | no | `"America/New_York"` | `"America/New_York"`, `"America/Los_Angeles"`, `"America/Chicago"`, `"Europe/London"`, `"Europe/Paris"`, `"Europe/Berlin"`, `"Asia/Tokyo"`, `"Asia/Singapore"`, `"Australia/Sydney"` | Ignored since 0.20 (no browser). Kept so existing API calls keep working. |
| `max_captcha_retries` | integer | no | `3` | min 1; max 10 | Retries per search page (with a new proxy IP each time) before it counts as blocked and the run switches search engines. Google pages through GOOGLE_SERP get at least 5 retries. |

## Example input

Built from the input schema prefill/default values (the actor publishes no example input).

```json
{
  "profile_description": "marketing manager startup",
  "exclude_keywords": [
    "post",
    "jobs"
  ],
  "max_results": 10,
  "scrape_profiles": true,
  "search_engine_strategy": "google_with_fallback",
  "use_direct_linkedin": false,
  "linkedin_urls": [],
  "proxy_country": "US",
  "proxy_groups": [
    "BUYPROXIES94952",
    "StaticUS3"
  ],
  "timezone": "America/New_York",
  "max_captcha_retries": 3
}
```

## Output

| Field | Type | Description |
|---|---|---|
| `title` | string or null | Search result title (or profile name for direct LinkedIn URLs) |
| `profileUrl` | string or null | Normalized LinkedIn profile URL |
| `description` | string or null | Search result snippet (or profile headline for direct LinkedIn URLs) |
| `displayedUrl` | string or null | Host name of the profile URL |
| `name` | string or null | Name from the public LinkedIn profile when it was scraped, otherwise parsed from the search result title (null if not parsable) |
| `headline` | string or null | Headline from the public LinkedIn profile when it was scraped, otherwise the search result title after the name (null if not parsable) |
| `location` | string or null | Location from the public LinkedIn profile, when the profile was scraped |
| `profileScraped` | boolean or null | True when public profile data (name, headline, location) was extracted |
| `source` | string or null | Where the lead came from: google_search, bing_search, linkedin_profile or direct_url |
| `sourceSearchEngine` | string or null | Search engine that returned the lead (null for direct LinkedIn URLs) |
| `note` | string or null | Processing note, e.g. whether the profile visit was skipped or hit a login wall |
| `scrapedAt` | string or null | ISO timestamp when the lead was saved |

Dataset views: `overview` (Overview).

## Example output item

Built from the `example` values of the dataset schema.

```json
{
  "title": "Jane Doe - Marketing Manager - Example Startup | LinkedIn",
  "profileUrl": "https://www.linkedin.com/in/jane-doe-0a1b2c3d/",
  "description": "Marketing Manager at Example Startup. Growth, SEO and content strategy.",
  "displayedUrl": "www.linkedin.com",
  "name": "Jane Doe",
  "headline": "Marketing Manager at Example Startup",
  "location": "Paris, Île-de-France, France",
  "profileScraped": false,
  "source": "bing_search",
  "sourceSearchEngine": "bing",
  "note": "LinkedIn login wall; search snippet only",
  "scrapedAt": "2025-01-15T12:00:00.000Z"
}
```

## Pricing

Pay per event, in effect since 2026-10-16 (as of 2026-10-18). Each event below is charged.

| Event | Title | Description | Price USD (FREE tier) |
|---|---|---|---|
| `apify-actor-start` | Actor Start (once per run) | Charged when the Actor starts running. Number of events charged depends on Actor memory (one event per GB, minimum one event). | $0.00005 |
| `apify-default-dataset-item` | Lead (primary) | One LinkedIn profile lead saved to the default dataset. Failed searches are never charged. | $0.0033 |

Plan-tier prices for `apify-default-dataset-item`: FREE $0.0033, BRONZE $0.003, SILVER $0.0027, GOLD $0.0024, PLATINUM $0.0024, DIAMOND $0.0024.

Prices are in USD at the Apify FREE plan tier; tiered events can cost less on paid Apify plans (plan-tier prices above). The [Apify Store page](https://apify.com/quaking_pail/google-serp-scraper-lead-finder) is authoritative: read the current price there instead of hardcoding these values.

## How to run

Run the actor and get its dataset items in one HTTP call (needs an Apify API token in `$APIFY_TOKEN`, sent in the `Authorization` header as Apify recommends ([Apify API authentication](https://docs.apify.com/api/v2))):

```bash
curl -X POST "https://api.apify.com/v2/acts/quaking_pail~google-serp-scraper-lead-finder/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
  "profile_description": "marketing manager startup",
  "exclude_keywords": [
    "post",
    "jobs"
  ],
  "max_results": 10,
  "scrape_profiles": true,
  "search_engine_strategy": "google_with_fallback",
  "use_direct_linkedin": false,
  "linkedin_urls": [],
  "proxy_country": "US",
  "proxy_groups": [
    "BUYPROXIES94952",
    "StaticUS3"
  ],
  "timezone": "America/New_York",
  "max_captcha_retries": 3
}'
```

Apify also accepts `?token=$APIFY_TOKEN` in the URL, but avoid it: URLs end up in logs and shell history.

If the run takes longer than 300 seconds, this endpoint returns HTTP 408 (Request Timeout). For longer runs start the actor with the asynchronous [Run Actor endpoint](https://docs.apify.com/api/v2/act-runs-post) and read the dataset when the run finishes. The `maxTotalChargeUsd` query parameter caps the total cost of a run ([run-sync-get-dataset-items reference](https://docs.apify.com/api/v2/act-run-sync-get-dataset-items-post)).

## Apify MCP

Apify hosts an MCP server at https://mcp.apify.com. The actor id is `quaking_pail/google-serp-scraper-lead-finder`; the `tools` query parameter loads only that actor as a tool ([Apify MCP server](https://docs.apify.com/platform/integrations/mcp)).

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=quaking_pail/google-serp-scraper-lead-finder",
      "headers": {
        "Authorization": "Bearer $APIFY_TOKEN"
      }
    }
  }
}
```

Replace `$APIFY_TOKEN` with your Apify API token. Without the `headers` entry the client signs in to Apify with OAuth in the browser instead.

## Links

- Apify Store: [quaking_pail/google-serp-scraper-lead-finder](https://apify.com/quaking_pail/google-serp-scraper-lead-finder)
- Sources: [actor API](https://api.apify.com/v2/acts/quaking_pail~google-serp-scraper-lead-finder), [build API](https://api.apify.com/v2/acts/quaking_pail~google-serp-scraper-lead-finder/builds/default)
- Data fetched from the Apify API on 2026-10-18
- Build: 0.20.6

## Do not

- Do not hardcode prices: read them on the Apify Store page before a large run.
- Do not put the Apify token in shared URLs, prompts or logs; prefer the `Authorization` header.
- Do not treat the output as verified: it is scraped from public pages and can be incomplete, outdated or wrong.
