# LinkedIn API No Login: Search, Profiles, Companies & Emails (`pnda/linkedin-scraper`) Actor

LinkedIn API with no cookies and no login: search LinkedIn people and companies by keyword, job title and location (Sales Navigator alternative), scrape profiles, company data, jobs and posts, find verified work emails. Pay per result.

- **URL**: https://apify.com/pnda/linkedin-scraper.md
- **Developed by:** [PNDA](https://apify.com/pnda) (community)
- **Categories:** Lead generation, Social media, Jobs
- **Stats:** 3 total users, 2 monthly users, 90.9% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.50 / 1,000 profiles

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## LinkedIn API, No Login: Search Profiles & Companies, Scrape Data, Find Emails

**A LinkedIn API with no cookies and no login.** Search LinkedIn people and companies by keyword, job title and location, scrape full **profiles**, **company data**, **jobs** and **posts** from URLs, and get **verified work emails**. One actor, pay per result.

- 🔒 **No cookies, no login, no LinkedIn account.** Nothing touches your account, so it can never be restricted or banned.
- 🔎 **LinkedIn search without Sales Navigator** (`mode: "search"`): find LinkedIn profiles like *"CEO, marketing agency, Paris"* or companies like *"SaaS, London"*. A **Sales Navigator alternative** for lead generation, built on Google x-ray search of public LinkedIn pages.
- 🏢➡️👤 **Company → decision makers**: find companies, then the CEO / head of sales / recruiter at each one, in the same run.
- 📧 **Verified work email** (`findEmail`): name + company → professional email, checked live over SMTP. **$9 / 1,000 emails found**, charged only when verified.
- 🧩 **A LinkedIn API alternative**: call it over HTTP from the Apify API, n8n, Make, Zapier, Clay or your own code. No LinkedIn developer app, no partner approval.
- 💸 **Pay only for rows you receive.** Invalid URLs, dead pages and empty searches are **never charged**.
- 💳 **Paid Apify plans only.** Runs from a free plan stop immediately with an upgrade message, at no cost.
- 📦 Export to **JSON, CSV, Excel, HTML, XML** or stream the dataset straight into your pipeline.

***

### 💡 Who is it for?

- **Sales & SDR teams** building lead lists from a LinkedIn search (title + industry + city) without Sales Navigator, then enriching them (job title, company, seniority) before outreach.
- **Recruiters** pulling full candidate profiles (experience, education) in bulk.
- **RevOps / CRM owners** refreshing job titles and employers every month.
- **Market researchers & investors** collecting LinkedIn company data (size, industry, HQ, followers, headcount on LinkedIn).
- **Job-market analysts** tracking open roles of target companies as hiring signals.
- **Social & content teams** measuring reactions and comments on posts.
- **Data & AI teams** feeding LinkedIn data into scoring models, RAG pipelines or agents.

***

### ⚙️ How it works

Two modes:

- **Scrape URLs** (`mode: "urls"`, default): pick a content type (`Profile`, `Company`, `Job` or `Post`), paste LinkedIn URLs, get one full row per URL.
- **Search LinkedIn** (`mode: "search"`): give keywords, a job title and a location, get LinkedIn profile or company URLs with name, position, company and location. Optionally scrape each result and find its verified email.

#### Scrape URLs

URLs that don't match the selected mode are skipped (and listed in the log) before anything happens. URLs that LinkedIn can't serve are saved in the key-value store record `FAILED_URLS` and are **not charged**.

| Mode | Accepted URLs | What you get |
|---|---|---|
| **Profile** | `linkedin.com/in/<handle>` | Name, headline, location, followers, connections, about, current company, full experience, education, awards, recent activity & posts, similar profiles |
| **Company** | `linkedin.com/company/<slug>` | Name, industry, company size, headquarters, website, followers, employees on LinkedIn, description, specialties, locations |
| **Job** | `linkedin.com/jobs/view/<id>` | Title, company, location, seniority, employment type, job function, industries, number of applicants, posted date, full description |
| **Post** | `linkedin.com/posts/...` or `linkedin.com/feed/update/...` | Author, post text (plain + HTML), date, likes, comments, top comments, hashtags, tagged people & companies, images, videos, documents |

Country subdomains (`fr.linkedin.com`, `uk.linkedin.com`...) and query strings are accepted.

***

### 📥 Input

| Field | Type | Required | Description |
|---|---|---|---|
| `type` | string | ✅ | `Profile` (default), `Company`, `Job` or `Post` |
| `urls` | array of strings | ✅ | LinkedIn URLs matching the selected type |
| `findEmail` | boolean | | Profile mode only, default `false`. Also finds the person's verified work email (see below) |

#### Example inputs

```json
{
  "type": "Profile",
  "urls": [
    "https://www.linkedin.com/in/satyanadella/",
    "https://www.linkedin.com/in/jeffweiner08/"
  ]
}
```

Profiles **with verified work email**:

```json
{
  "type": "Profile",
  "findEmail": true,
  "urls": ["https://www.linkedin.com/in/satyanadella/"]
}
```

```json
{
  "type": "Company",
  "urls": [
    "https://www.linkedin.com/company/microsoft/",
    "https://www.linkedin.com/company/bereal/"
  ]
}
```

```json
{ "type": "Job", "urls": ["https://www.linkedin.com/jobs/view/4440458716/"] }
```

```json
{ "type": "Post", "urls": ["https://www.linkedin.com/posts/reidhoffman_give-people-a-reason-to-want-the-ai-future-activity-7508645307132600321-dOsB"] }
```

***

### 🔎 Search LinkedIn without cookies (`mode: "search"`)

Find LinkedIn profiles and companies **without a LinkedIn account, without cookies and without Sales Navigator**. The actor runs a Google x-ray search of public LinkedIn pages (`site:linkedin.com/in` or `site:linkedin.com/company`) and parses every result.

| Field | Description |
|---|---|
| `searchType` | `people` (profiles, default) or `company` |
| `keywords` | Industry, skills, any words: `marketing agency`, `saas`, `shopify` |
| `role` | Job title: `CEO`, `head of sales`, `recruiter` |
| `location` | City, region or country: `Paris`, `London`, `Texas` |
| `maxResults` | Max leads (default 20, min 5). Google pages hold ~10 results: multiples of 10 work best |
| `findPeopleAtCompanies` | Company search: also find people with the `role` at each company found |
| `peoplePerCompany` | 5 to 10 profiles per company (default 10) |
| `scrapeResults` | Also scrape the full profile / company page of each lead (billed like URL mode) |
| `findEmail` | Also find the verified work email of each person found |
| `country`, `language` | Google country (`us`, `fr`, `gb`...) and language (`en`, `fr`...) |

Example: CEOs of agencies in Paris, with verified emails:

```json
{ "mode": "search", "searchType": "people", "role": "CEO", "keywords": "agency", "location": "Paris", "maxResults": 50, "findEmail": true }
```

Example: marketing agencies in Lyon, then their CEO:

```json
{ "mode": "search", "searchType": "company", "keywords": "marketing agency", "location": "Lyon", "maxResults": 20, "findPeopleAtCompanies": true, "role": "CEO" }
```

Output row (real result, trimmed):

```json
{
  "resultType": "people",
  "linkedinUrl": "https://www.linkedin.com/in/valeriebodocco",
  "name": "Valérie Bodocco",
  "position": "CEO",
  "company": "L'Agence de Paris",
  "location": null,
  "title": "Valérie Bodocco - CEO - L'Agence de Paris",
  "snippet": "En immobilier, je dirige depuis 2010 le Groupe L'Agence...",
  "query": "CEO agency Paris site:linkedin.com/in",
  "rank": 1
}
```

People found through `findPeopleAtCompanies` also carry `sourceCompanyName`, `sourceCompanyUrl` and `companyMatch` (`true` when the result mentions the company; `false` rows are looser Google matches such as former employees or namesakes, and come last).

Good to know: search covers what Google indexes of public LinkedIn pages (very broad, but not 100 % of LinkedIn), and `name` / `position` / `company` are parsed from the Google title and snippet. Turn on `scrapeResults` when you need the full, structured profile.

***

### 📤 Output examples (trimmed)

**Profile**

```json
{
  "name": "Satya Nadella",
  "first_name": "Satya",
  "last_name": "Nadella",
  "position": "Chairman and CEO at Microsoft",
  "city": "Redmond, Washington, United States",
  "country_code": "US",
  "followers": 12183622,
  "connections": 500,
  "current_company": { "name": "Microsoft", "company_id": "microsoft", "title": "Chairman and CEO" },
  "about": "As chairman and CEO of Microsoft, I define my mission...",
  "experience": [{ "title": "Chairman and CEO", "company": "Microsoft", "start_date": "..." }],
  "education": [{ "title": "The University of Chicago Booth School of Business" }],
  "url": "https://www.linkedin.com/in/satyanadella"
}
```

With `findEmail: true`, each profile row gets these extra fields:

```json
{
  "email": "jane.doe@acme.com",
  "email_status": "found",
  "email_confidence": "verified",
  "email_pattern": "first.last",
  "email_domain": "acme.com",
  "email_domain_source": "guessed-from-company"
}
```

**Company**

```json
{
  "name": "Microsoft",
  "industries": "Software Development",
  "company_size": "10,001+ employees",
  "headquarters": "Redmond, Washington",
  "website": "https://news.microsoft.com/",
  "followers": 29163922,
  "employees_in_linkedin": 231769,
  "url": "https://www.linkedin.com/company/microsoft"
}
```

**Job**

```json
{
  "job_title": "Data Engineer Expérimenté F/H",
  "company_name": "EY",
  "job_location": "Paris, Île-de-France, France",
  "job_seniority_level": "Mid-Senior level",
  "job_employment_type": "Full-time",
  "job_function": "Information Technology",
  "job_num_applicants": 98,
  "job_posted_date": "2026-09-23T08:00:26.424Z",
  "job_summary": "Chez EY, nous sommes « All in » pour façonner votre avenir...",
  "url": "https://www.linkedin.com/jobs/view/4440458716/"
}
```

**Post**

```json
{
  "user_id": "reidhoffman",
  "date_posted": "2026-09-23T21:55:45.104Z",
  "post_type": "post",
  "num_likes": 492,
  "num_comments": 151,
  "post_text": "If people can't point to something in their lives that has become easier, more affordable...",
  "url": "https://www.linkedin.com/posts/reidhoffman_give-people-a-reason-to-want-the-ai-future-activity-7508645307132600321-dOsB"
}
```

Every row also contains the original `input` and a `timestamp`. Field names are stable, so you can map them once in your CRM or spreadsheet.

***

### 📧 Find verified work emails (`findEmail`)

Turn a list of LinkedIn profile URLs into a list of **verified professional emails**, in the same run.

1. The actor takes the person's **first and last name** and **current company** from the profile.
2. The company domain comes from the profile when it is there; otherwise it is deduced from the company name (only domains that actually receive email are kept).
3. The usual corporate patterns (`first.last`, `first`, `flast`, `firstlast`...) are tested one by one with a **live SMTP check**, stopping at the first verified address.

| `email_status` | Meaning | Charged? |
|---|---|---|
| `found` | Mailbox verified (`email_confidence: "verified"`) | ✅ `email-found` |
| `catch-all` | The domain accepts every address: `email` is the most likely pattern, **unverified** (`email_confidence: "catch-all"`) | ❌ free |
| `not-found` | No tested pattern exists | ❌ |
| `unknown` | The mail server gave no clear answer | ❌ |
| `no-mx` / `no-company` | No mail domain for the current company | ❌ |

The profile itself is always delivered and billed as a normal `profile`, whatever the email result.

***

### 💰 Pricing (pay per result)

**Available on paid Apify plans only.** You pay a fixed price per LinkedIn record actually returned. No start fee, no monthly rental, no charge for failed URLs.

| Event | What triggers it | Price |
|---|---|---|
| `profile` | 1 profile returned | $3.50 / 1,000 |
| `company` | 1 company page returned | $23.90 / 1,000 |
| `job` | 1 job listing returned | $5.90 / 1,000 |
| `post` | 1 post returned | $5.90 / 1,000 |
| `search-result` | 1 LinkedIn profile or company found by a search (`mode: "search"`) | $4.90 / 1,000 |
| `email-found` | 1 **verified** work email found (`findEmail`) | $9.00 / 1,000 |

| Example run | Records | Approx. cost |
|---|---|---|
| Quick test | 10 profiles | ~$0.035 |
| Lead list | 1,000 profiles | ~$3.50 |
| Account list | 1,000 companies | ~$23.90 |
| Lead list + emails | 1,000 profiles, `findEmail` on, 400 verified emails | ~$3.50 + $3.60 = ~$7.10 |
| LinkedIn search | 1,000 people found by keyword + title + city | ~$4.90 |
| Search + emails | 1,000 people found, `findEmail` on, 350 verified emails | ~$4.90 + $3.15 = ~$8.05 |

Set **Maximum cost per run** in the run options to cap your spend: duplicate URLs are removed and the actor only scrapes as many URLs as your limit can pay for; the rest are skipped and listed in the log. With `findEmail`, each URL reserves the price of a profile **and** an email. In search mode, a Google page is only requested when your limit still covers at least 5 more results. Runs started from a free Apify plan stop immediately with an upgrade message, at no cost.

***

### 🔌 Use it as a LinkedIn API

Run it synchronously and get the rows in one HTTP call:

```bash
curl -X POST "https://api.apify.com/v2/acts/pnda~linkedin-scraper/run-sync-get-dataset-items?token=<APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"type":"Company","urls":["https://www.linkedin.com/company/microsoft/"]}'
```

Or use the Apify client for JavaScript/Python, the n8n / Make / Zapier integrations, webhooks, or Apify Schedules for recurring refreshes.

***

### 🚀 Why this actor

- ✅ **Search + scrape + email in one actor**: find LinkedIn profiles, scrape profiles, company data, jobs and posts, get verified emails. One integration instead of five.
- ✅ **No cookies, no login**: zero risk for your LinkedIn account.
- ✅ **Bulk by URL**: hundreds of URLs per run, one clean row per URL.
- ✅ **Rich data**: full career history, company headcount, applicants count, post engagement.
- ✅ **Fair billing**: invalid and dead URLs are never charged.

***

### ❓ FAQ

**Do I need a LinkedIn account, cookies or a proxy?** No.

**How fresh is the data?** Records are collected when you run the actor, typically within seconds to a few minutes per batch.

**What if a URL fails?** It is not charged. The error (e.g. `dead_page`) is stored in the key-value store record `FAILED_URLS`.

**Does it return emails?** Yes, for profiles, if you turn on `findEmail`. The email is built from the name and current company and verified over SMTP; you pay $9 / 1,000 only for verified emails. Catch-all guesses are returned for free, clearly flagged.

**Can I use it on the free Apify plan?** No. This Actor is available on paid Apify plans only ([pricing](https://apify.com/pricing)).

**Can I search LinkedIn by keyword without cookies?** Yes: `mode: "search"` finds LinkedIn profiles and companies by keyword, job title and location through Google, with no LinkedIn login, no cookies and no Sales Navigator subscription. You pay $4.90 / 1,000 results found; empty searches are free.

**Is it a Sales Navigator alternative?** For prospect lists, yes: search by title + industry + city, get profile URLs, names, positions and companies, then verified emails. It does not send connection requests or messages.

**Is it legal?** It only collects publicly available data. You are responsible for using it in compliance with GDPR, CCPA and other laws in your jurisdiction. Do not use personal data without a legitimate purpose.

***

### ▶️ Start now

Search LinkedIn or paste your URLs, click **Run**, export your dataset. LinkedIn data and leads on tap: no cookies, no login.

# Actor input Schema

## `mode` (type: `string`):

"Scrape URLs": paste LinkedIn URLs and get full records. "Search LinkedIn (no cookies)": find LinkedIn profiles or companies from keywords, job title and location through Google (no login, no cookies, no LinkedIn account), then optionally scrape them and find their verified work email.

## `type` (type: `string`):

URL mode: what kind of LinkedIn URLs are you providing?

## `urls` (type: `array`):

URL mode: LinkedIn URLs matching the selected content type.

## `searchType` (type: `string`):

Search mode: find people (linkedin.com/in profiles) or companies (linkedin.com/company pages).

## `keywords` (type: `string`):

Search mode: industry, skills or any words, e.g. "marketing agency", "saas", "shopify".

## `role` (type: `string`):

Search mode: job title to look for, e.g. "CEO", "head of sales", "recruiter". People search: added to the query. Company search with "Find people at each company": the role searched at each company.

## `location` (type: `string`):

Search mode: city, region or country, e.g. "Paris", "London", "Texas".

## `maxResults` (type: `integer`):

Search mode: maximum number of leads (people or companies) to return. Google pages hold about 10 results, so multiples of 10 work best. Minimum 5.

## `findPeopleAtCompanies` (type: `boolean`):

Company search only: for every company found, also search its employees with the job title in "Job title / role" (one extra search per company, up to "People per company" profiles, each billed as a search result).

## `peoplePerCompany` (type: `integer`):

With "Find people at each company": maximum profiles per company (5 to 10).

## `scrapeResults` (type: `boolean`):

Search mode: also scrape each profile / company found (same data as URL mode), billed per record like URL mode.

## `country` (type: `string`):

Search mode: two-letter Google country code used for the search (gl), e.g. us, fr, gb, de.

## `language` (type: `string`):

Search mode: two-letter Google interface language (hl), e.g. en, fr.

## `findEmail` (type: `boolean`):

URL mode with Profile URLs, or search mode for people: finds the person's professional email from their name and current company (company domain from the profile, otherwise guessed from the company name), verified live over SMTP. Billed only when a verified email is found ($9 / 1,000). Catch-all domains return a best guess with confidence "catch-all", free of charge.

## `useCache` (type: `boolean`):

On: profiles and company pages already scraped recently (by any run) are returned from a shared result cache instead of being scraped again: faster, same data, same price. Failed pages are never cached. Jobs and posts are always scraped live. Off: everything is scraped live.

## `maxCacheAgeDays` (type: `integer`):

With "Reuse recent results": only reuse results at most this many days old. 0 = always scrape live. Empty = 30 days.

## Actor input object example

```json
{
  "mode": "urls",
  "type": "Profile",
  "urls": [
    "https://www.linkedin.com/in/satyanadella/"
  ],
  "searchType": "people",
  "maxResults": 20,
  "findPeopleAtCompanies": false,
  "peoplePerCompany": 10,
  "scrapeResults": false,
  "country": "us",
  "language": "en",
  "findEmail": false,
  "useCache": true
}
```

# Actor output Schema

## `dataset` (type: `string`):

All scraped records (JSON, CSV, Excel).

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "mode": "urls",
    "type": "Profile",
    "urls": [
        "https://www.linkedin.com/in/satyanadella/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("pnda/linkedin-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "mode": "urls",
    "type": "Profile",
    "urls": ["https://www.linkedin.com/in/satyanadella/"],
}

# Run the Actor and wait for it to finish
run = client.actor("pnda/linkedin-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "urls",
  "type": "Profile",
  "urls": [
    "https://www.linkedin.com/in/satyanadella/"
  ]
}' |
apify call pnda/linkedin-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,pnda/linkedin-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/btNUul6dyyuLVpSsd/builds/oFPEUzyalP4gU1W3e/openapi.json
