{
  "data": {
    "id": "K2R0hntX5ehmLdeoP",
    "actId": "Ej688LPvwfEI3kev6",
    "userId": "ahCzxnwfcj5Jy1qRJ",
    "startedAt": "2026-10-12T21:29:02.294Z",
    "finishedAt": "2026-10-12T21:29:25.175Z",
    "status": "SUCCEEDED",
    "meta": {
      "origin": "API"
    },
    "stats": {
      "durationMillis": 22802,
      "runTimeSecs": 22.802,
      "computeUnits": 0.025335555555555556,
      "imageSizeBytes": 585481728
    },
    "options": {
      "useCache": true,
      "betaPackages": false,
      "tag": "latest",
      "memoryMbytes": 4096,
      "diskMbytes": 8192
    },
    "exitCode": 0,
    "inputSchema": "{\n  \"title\": \"LinkedIn Profile Scraper with Email input\",\n  \"type\": \"object\",\n  \"schemaVersion\": 1,\n  \"properties\": {\n    \"profileUrls\": {\n      \"title\": \"👤 LinkedIn profiles\",\n      \"type\": \"array\",\n      \"editor\": \"stringList\",\n      \"description\": \"LinkedIn profile URLs or slugs, one per line — <b>https://www.linkedin.com/in/satyanadella</b> or <b>satyanadella</b>. One row per profile. Profiles that do not exist or are hidden from logged-out visitors are free.\",\n      \"prefill\": [\n        \"https://www.linkedin.com/in/satyanadella\",\n        \"https://www.linkedin.com/in/jeffweiner08\",\n        \"justinwelsh\"\n      ]\n    },\n    \"startUrls\": {\n      \"title\": \"🔗 Profiles from a file or sheet\",\n      \"type\": \"array\",\n      \"editor\": \"requestListSources\",\n      \"default\": [],\n      \"description\": \"The same thing for long lists — upload a file or link a Google Sheet (or any text/CSV URL) that contains LinkedIn profile URLs.\"\n    },\n    \"findEmail\": {\n      \"title\": \"📧 Find the work e-mail ($)\",\n      \"type\": \"boolean\",\n      \"default\": true,\n      \"description\": \"Find each person's work e-mail: company website, the address layout it uses, mail-domain check, confidence. A row WITH an e-mail is charged as 'Profile with e-mail'; a row without one is charged as a plain 'Profile'. Switch off to get profiles only.\",\n      \"sectionCaption\": \"📧 Work e-mail\"\n    },\n    \"minConfidence\": {\n      \"title\": \"Minimum e-mail confidence to pay for\",\n      \"type\": \"string\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"low\",\n        \"medium\",\n        \"high\",\n        \"confirmed\"\n      ],\n      \"enumTitles\": [\n        \"low — layout guessed from the most common corporate format (unverified)\",\n        \"medium — layout seen on the company's own site\",\n        \"high — layout confirmed by 2+ addresses on the site\",\n        \"confirmed — the address itself is published on the site\"\n      ],\n      \"default\": \"medium\",\n      \"description\": \"Used only when the SMTP mailbox check is unavailable in a run (normally every address is mailbox-checked and only a verified one is put into 'email'). Below this level the address is NOT put into 'email': it goes to 'emailGuess' (and 'alternatives') and the row is charged as a plain profile. low = most common layout, nothing confirms it (emailStatus unverified-guess); medium = the company's own site uses this layout (pattern-confirmed); high = 2+ addresses on the site confirm it; confirmed = the address is published on the site (found-on-website). No mailbox (SMTP) check is made.\",\n      \"prefill\": \"medium\"\n    },\n    \"companyOverride\": {\n      \"title\": \"🏢 Company override\",\n      \"type\": \"string\",\n      \"editor\": \"textfield\",\n      \"default\": \"\",\n      \"description\": \"Use this company name or domain for everyone instead of what the profiles say — handy when all profiles work at one company, or when a company name cannot be turned into a website.\"\n    },\n    \"candidatesPerPerson\": {\n      \"title\": \"Alternative addresses per person\",\n      \"type\": \"integer\",\n      \"default\": 3,\n      \"minimum\": 1,\n      \"maximum\": 8,\n      \"description\": \"The best address goes into 'email'; runners-up go into 'alternatives'.\"\n    },\n    \"maxPagesPerCompany\": {\n      \"title\": \"Company pages to read\",\n      \"type\": \"integer\",\n      \"default\": 4,\n      \"minimum\": 1,\n      \"maximum\": 10,\n      \"description\": \"Home page plus contact / team / about pages, to learn how the company writes its addresses.\"\n    },\n    \"checkMx\": {\n      \"title\": \"Check that the mail domain accepts mail\",\n      \"type\": \"boolean\",\n      \"default\": true,\n      \"description\": \"DNS MX check. It always runs, because it decides the charge: only an address on a domain with an MX record is delivered as an e-mail. A domain without an MX record, one that takes no mail, or one that does not answer DNS after three tries leaves the row a plain profile.\"\n    },\n    \"includePosts\": {\n      \"title\": \"📰 Add the latest posts and articles\",\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"description\": \"The person's recent posts (usually 5–9) and articles (up to 10) inside the same row. No extra charge.\",\n      \"sectionCaption\": \"What else to put in the row\"\n    },\n    \"maxItems\": {\n      \"title\": \"Maximum profiles per run\",\n      \"type\": \"integer\",\n      \"default\": 10000,\n      \"minimum\": 1,\n      \"description\": \"A hard ceiling on what one run reads and bills.\",\n      \"sectionCaption\": \"Advanced\"\n    },\n    \"concurrency\": {\n      \"title\": \"Parallel profiles\",\n      \"type\": \"integer\",\n      \"default\": 3,\n      \"minimum\": 1,\n      \"maximum\": 10,\n      \"description\": \"How many profiles to read at the same time. Keep it low — LinkedIn dislikes bursts.\"\n    },\n    \"pageTimeoutSecs\": {\n      \"title\": \"Company page timeout (seconds)\",\n      \"type\": \"integer\",\n      \"default\": 15,\n      \"minimum\": 5,\n      \"maximum\": 60,\n      \"description\": \"How long to wait for one company web page before giving up on it.\"\n    },\n    \"proxyConfiguration\": {\n      \"title\": \"Proxy configuration\",\n      \"type\": \"object\",\n      \"editor\": \"proxy\",\n      \"default\": {\n        \"useApifyProxy\": true,\n        \"apifyProxyGroups\": [\n          \"RESIDENTIAL\"\n        ]\n      },\n      \"prefill\": {\n        \"useApifyProxy\": true,\n        \"apifyProxyGroups\": [\n          \"RESIDENTIAL\"\n        ]\n      },\n      \"description\": \"Residential, a new address for every profile — included in the price, nothing to set up. LinkedIn blocks direct and datacenter requests after a few dozen profiles, so those settings are ignored. Company websites are read directly. Only your own proxy URLs replace this (then the second route for refused profiles is off).\"\n    }\n  },\n  \"required\": []\n}",
    "readme": "**LinkedIn Profile Scraper with Email** turns LinkedIn profile URLs into complete rows: the **full public profile** — name, headline, current title and company, location, about, followers, the whole experience history with dates, education, certifications, skills, recommendations — **plus the person's work e-mail address, with the mailbox verified by an SMTP check**, and the evidence behind it.\n\n**$3.20 per 1,000 profiles, $8 per 1,000 profiles with e-mail** — and you pay the e-mail price **only when the mailbox is verified** by an SMTP check (no e-mail is sent). Catch-all domains (the mail server accepts any address) are returned unverified and not charged as an e-mail. No LinkedIn login, no cookies, no account at risk, no start fee. Profiles that do not exist or that LinkedIn hides from logged-out visitors are free.\n\n## Tested head-to-head — 9 October 2026\n\nThe same 10 public LinkedIn profiles of founders and executives (Apify, Single Grain, Gates Foundation, Microsoft, Stripe, HubSpot and others) went to this Actor and to the most-used LinkedIn profile scraper with e-mail search on the Apify Store, on the same day:\n\n| | This Actor | harvestapi/linkedin-profile-scraper (profile + e-mail search) |\n|---|---|---|\n| Mailbox-verified work e-mails | **7 of 10** | 8 of 10 |\n| Catch-all domains (no mailbox can be confirmed) | 3 — returned unverified in `emailGuess`, charged as plain profiles | 2 — returned as \"risky\", billed as e-mail searches |\n| Bill for the 10 profiles | **$0.066** | $0.10 |\n| Price per verified e-mail on this list | **$0.0094** | $0.0125 |\n\n5 of our 7 verified addresses are the same as the leader's; the other 2 are different verified mailboxes of the same people. The one verified address we missed belongs to a person whose public profile lists a different company as the only current position, so the address was built on that domain.\n\n## What is LinkedIn Profile Scraper with Email?\n\nA **LinkedIn email finder and profile scraper in one run**, for sales prospecting, recruiting and CRM enrichment. It reads the **public profile page** — the version LinkedIn shows search engines and logged-out visitors — and returns it as structured data. Then it turns the person's current company into its website, reads how that company writes its e-mail addresses (a team page that says `jane.doe@` tells you how everyone else is addressed), builds the person's address in that layout and checks that the mail domain accepts mail.\n\nOne row per person, one charge per row: **Profile with e-mail** when the row carries an address, **Profile** when it does not. Never both. No official LinkedIn API needed.\n\n## What data does it extract?\n\n| Field | Meaning |\n|---|---|\n| `fullName`, `firstName`, `lastName`, `headline` | Identity as shown on the profile |\n| `title`, `company`, `companyLinkedinUrl`, `currentPositions` | Current role(s) with the company page |\n| `otherCurrentCompanies`, `companyChosenBy` | When a person has several current jobs, `company` is the main one — named in the headline (or, when LinkedIn hides the headline, in the About text / profile website), then founder / CEO level, then the longest-held; the other current companies are in `otherCurrentCompanies`, and `companyChosenBy` says why. If the main company's mail server accepts any address, one check goes to the next current company (`emailCompany` says where the e-mail is) |\n| 📧 `email`, `confidence`, `emailStatus` | The work e-mail — **only a mailbox verified by the SMTP check** (`confidence: verified`, `emailStatus: mailbox-verified`); not verified: `catch-all`, `mailbox-unknown`, `mailbox-invalid` (see below) |\n| `emailVerified`, `emailCatchAll`, `emailVerification` | `true` — the mailbox exists; `false` — checked, not confirmed; `null` — not checked. `emailCatchAll: true` — the domain accepts any address. `emailVerification` — status (`safe`, `catch_all`, `unknown`, `invalid`…), score, time and every address tried |\n| `emailGuess` | The best unverified address when it is **not** put into `email` (catch-all domain, mailbox not confirmed, or the domain failed the DNS check) — not charged as an e-mail, use at your own risk |\n| `emailDomainStatus` | DNS verdict for the mail domain: `accepts-mail`, `risky`, `undeliverable`, `unknown` |\n| `emailPattern`, `foundOnSite`, `patternEvidence`, `patternEvidenceCount` | The layout used (`first.last`, `flast`, `first`…), whether the address itself is on the company site, and the published addresses that prove the layout |\n| `alternatives` | Runner-up addresses in the other plausible layouts |\n| `domain`, `domainSource`, `domainEvidence`, `companyWebsiteName` | The company website and how it was confirmed as the company's |\n| `emailProvider`, `emailMxHost`, `emailIsRole`, `emailIsFree`, `emailIsDisposable` | Mail-domain checks: Google Workspace, Microsoft 365…, role / free / disposable flags |\n| `summary` | One line: where the e-mail came from and how the row was charged |\n| `location`, `country`, `about`, `website` | Location, about text, website from the profile |\n| `city`, `region`, `countryCode` | The location split into parts (`Redmond` / `Washington` / `US`); city and region stay empty for a country-only or metro-area location |\n| `followers`, `connections`, `badges` | Follower count, \"500+\" connections, Creator / Top Voice |\n| `experience` | Every role, including each role inside a company group: title, company, company URL, `companyLogo`, `location`, `employmentType` (when shown), start, end, current flag, duration, full description |\n| `education` | Every school with `degree`, `fieldOfStudy`, `activities`, `grade`, `description`, `schoolLogo`, start and end |\n| `certifications`, `volunteering`, `publications`, `honorsAndAwards`, `organizations`, `skills`, `recommendations` | Every such section the public profile shows |\n| `languages`, `languageProficiencies`, `courses`, `projects`, `testScores`, `coursesTaught` | Languages with proficiency, courses, projects, test scores, LinkedIn Learning courses the person teaches |\n| `imageUrl`, `coverImageUrl`, `memberId`, `profileUrn` | Photo, cover image, LinkedIn member id and URN |\n| `similarProfiles`, `sameNameProfiles` | \"Other similar profiles\" (LinkedIn's \"People also viewed\" rail as logged-out visitors see it, usually 10–20: name, headline as the card shows it, location, followers, URL, photo) and \"Others named …\" when shown — free leads, no extra charge |\n| `latestPosts`, `articles` | With **Add the latest posts and articles** on: 5–9 recent posts and up to 10 articles |\n\nThe field names are the same as in our [LinkedIn Profile Scraper](https://apify.com/lergassy/linkedin-profile-scraper) (profile part) and [LinkedIn Email Finder](https://apify.com/lergassy/linkedin-email-finder) (e-mail part), so a pipeline built on either keeps working.\n\n## 💰 How much does it cost to scrape LinkedIn profiles with email?\n\n| Event | You pay for | FREE | BRONZE | SILVER | GOLD / PLATINUM / DIAMOND |\n|---|---|---|---|---|---|\n| **Profile with e-mail** | a row whose `email` is filled — the mailbox is verified by the SMTP check | $0.008 | $0.0076 | $0.0072 | $0.0068 |\n| **Profile** | a row without an e-mail (a guess only in `emailGuess` counts as no e-mail), or e-mail search off | $0.0032 | $0.00304 | $0.00288 | $0.00272 |\n| Error row, 404, profile hidden from logged-out visitors | — | **$0** | **$0** | **$0** | **$0** |\n\n- **The e-mail price is paid only for a verified mailbox.** A catch-all domain, a mailbox the SMTP check could not confirm, a person whose company has no findable website, an address on a domain that takes no mail or has no MX record, a domain that does not answer a DNS check after three tries — the row is delivered and charged as a plain **Profile** (the guess is kept in `emailGuess` and `alternatives`, except on a domain that takes no mail).\n- **No address on an unconfirmed domain.** An address is built only on a domain with evidence that it is the company's: you gave it, it is the parent's mail domain (Microsoft AI → microsoft.com), the company's LinkedIn page links it, the domain spells the company name, or the website carries the company's name. A look-alike domain is listed in `unconfirmedDomains` and the row is a plain **Profile**. Titles and credentials in names (Dr., Gov., PhD, MBA, Jr., emojis, text after a comma or a pipe) are removed before the address is written, and a middle name is never glued into it: \"John H. Cammack\" is john.cammack@, while a surname with particles stays whole (\"van der Berg\", \"de la Cruz\").\n- **Mailbox check, at most 2 per person** (9 October 2026): the address published on the company site or built on the company's own layout first, then the most likely layouts; the first mailbox that exists is the e-mail. Measured on 10 public profiles of founders and executives: **7 of 10 mailbox-verified e-mails**, 2 checks per verified address on average; the other 3 were catch-all domains, charged as plain profiles.\n- **Minimum e-mail confidence to pay for** applies only if the mailbox check is unavailable in a run (default `medium` since 5 October 2026): a `low` address — the most common layout, nothing on the company's site confirms it — goes to `emailGuess` instead of `email`, at the plain profile price. Set it to `low` to get such guesses in `email` and pay the e-mail price for them; `high` or `confirmed` to pay only for stronger evidence.\n- Experience, education, skills, posts, alternatives, evidence and domain checks: included. No fee per run, no proxy charge.\n- On Apify's free plan ($5 of monthly credit) that is about **620 profiles with e-mail** or **1,500 profiles** a month.\n\n### Bulk export: what 50,000 profiles actually cost\n\n| Job: 50,000 LinkedIn profiles | This Actor | harvestapi/linkedin-profile-scraper | dev_fusion/Linkedin-Profile-Scraper |\n|---|---|---|---|\n| Profiles only | **$160** | $200 | — |\n| Profiles + e-mail search | **$294** (e-mail on ~56% of rows — $8/1,000 for those, $3.20/1,000 for the rest) | $500 ($10/1,000 per e-mail **search**, found or not) | $500 ($10/1,000 rows) |\n\nPrices from the Apify Store on 1 October 2026 (FREE tier). The e-mail share is what we measured on a test list of 25 real profiles on 1 October 2026: **14 of 25 rows (56%) carried an e-mail**. An address is delivered only on a domain we could confirm as the company's own (and whose mail domain has a working MX record) — a person whose company we cannot pin to its website gets a plain profile row instead of a guess. Yours will differ, and you only pay $8/1,000 for the rows that actually carry an address. Since 9 October 2026 only a mailbox verified by an SMTP check is charged as an e-mail: on 10 public profiles of founders and executives that was 7 of 10; addresses on catch-all domains come at the plain profile price.\n\n### Why some profiles come back as free error rows\n\nEvery profile is read through a residential address, a new one for each profile. About one profile in five is hidden from logged-out visitors on that route (LinkedIn answers HTTP 999 or a login wall). Hidden profiles are opened through a second route: a web unblocker first, and a heavier unblocking service for the ones it cannot open — together they open most of them, even on a short list made only of hidden profiles. The second route is paid from the run's own margin and is included in the price. What still refuses — usually profiles their owners hid from search engines — comes back as an error row and costs nothing. This Actor never logs in. On our 120-profile test list on 1 October 2026 all 120 profiles were delivered, 31 of them through the second route — expect a few percent of error rows on other lists.\n\n### Run health\n\nWhen a run ends with many error rows, the Actor sends its developer the counts (rows delivered, error types, run ID) so the cause gets fixed fast. Your input and your results are never sent.\n\n### Very long lists\n\nWhen most of the last 30 profiles in a run are refused by rate limits (hidden profiles do not count), the rest of the list goes straight to the second route (with your own proxies: the run pauses for 90 seconds, and after two pauses stops). A run that gets within 45 seconds of its timeout stops taking new profiles the same way. Profiles that were not tried are not charged; their URLs are saved in the `NOT_ATTEMPTED` record of the run's key-value store and named in the status message. With **Max cost per run** set, the run stops by itself at that amount, green, with every written row paid for.\n\n## How to scrape LinkedIn profiles with email in three steps\n\n1. Paste LinkedIn profile URLs or slugs into **👤 LinkedIn profiles** — `https://www.linkedin.com/in/satyanadella` or `satyanadella` — or link a file / Google Sheet.\n2. Leave **📧 Find the work e-mail** on. Optionally raise **Minimum e-mail confidence to pay for**, or set **Company override** when the whole list works at one company.\n3. Press **Start**, then download JSON, CSV or Excel — or call it from the API, n8n, Make, Zapier or an AI agent.\n\n## ⬇️ Input\n\n```json\n{\n  \"profileUrls\": [\"https://www.linkedin.com/in/satyanadella\", \"jeffweiner08\", \"justinwelsh\"],\n  \"findEmail\": true,\n  \"minConfidence\": \"medium\",\n  \"includePosts\": false\n}\n```\n\n### Input options\n\n| Field | Default | What it does |\n|---|---|---|\n| `profileUrls` | 3 demo profiles | Profile URLs or slugs |\n| `startUrls` | — | A file or Google Sheet with profile URLs |\n| `findEmail` | `true` | Find the work e-mail; off = profiles only at the Profile price |\n| `minConfidence` | `medium` | Lowest confidence put into `email` and paid at the e-mail price; weaker guesses go to `emailGuess` |\n| `companyOverride` | — | One company name or domain for everyone |\n| `candidatesPerPerson` | 3 | How many addresses (best + alternatives) |\n| `maxPagesPerCompany` | 4 | Company pages read to learn the address layout |\n| `checkMx` | `true` | DNS check that the mail domain accepts mail — always runs, because only an address on a domain with an MX record is charged as an e-mail |\n| `includePosts` | `false` | Latest posts and articles in the row, no extra charge |\n| `maxItems`, `concurrency`, `pageTimeoutSecs`, `proxyConfiguration` | | Limits and network settings |\n\n## ⬆️ Output\n\n```json\n{\n  \"type\": \"profile\",\n  \"fullName\": \"Justin Welsh\",\n  \"firstName\": \"Justin\",\n  \"lastName\": \"Welsh\",\n  \"headline\": \"Writer & Entrepreneur. I write The Saturday Essay for 200,000+ ambitious people…\",\n  \"title\": \"Writer\",\n  \"company\": \"the saturday essay.\",\n  \"email\": null,\n  \"emailVerified\": false,\n  \"emailCatchAll\": true,\n  \"confidence\": \"low\",\n  \"emailStatus\": \"catch-all\",\n  \"domain\": \"justinwelsh.me\",\n  \"emailGuess\": \"justin.welsh@justinwelsh.me\",\n  \"emailDomainStatus\": \"accepts-mail\",\n  \"companyLinkedinUrl\": \"https://www.linkedin.com/company/saturday-essay\",\n  \"location\": \"New York City Metropolitan Area\",\n  \"city\": null,\n  \"region\": null,\n  \"countryCode\": \"US\",\n  \"followers\": 883050,\n  \"connections\": \"500+\",\n  \"experience\": [\n    { \"title\": \"Writer\", \"company\": \"the saturday essay.\", \"startDate\": \"Jan 2022\", \"endDate\": null, \"current\": true, \"duration\": \"4 years 10 months\", \"companyLogo\": \"https://media.licdn.com/dms/image/v2/…\", \"location\": null, \"employmentType\": null },\n    { \"title\": \"Founder\", \"company\": \"Justin Welsh\", \"startDate\": \"Aug 2019\", \"endDate\": null, \"current\": true, \"duration\": \"7 years 3 months\", \"companyLogo\": \"https://media.licdn.com/dms/image/v2/…\", \"location\": null, \"employmentType\": null }\n  ],\n  \"education\": [{ \"school\": \"The Ohio State University\", \"startDate\": \"1999\", \"endDate\": \"2003\", \"degree\": \"BSBA\", \"fieldOfStudy\": \"Marketing\", \"activities\": \"Phi Kappa Tau Fraternity, Project Open Hand, Economics Tutor\" }],\n  \"coverImageUrl\": \"https://media.licdn.com/dms/image/v2/…\",\n  \"memberId\": \"16259454\",\n  \"similarProfiles\": [{ \"name\": \"Will Polese\", \"headline\": \"ELSA, Corp\", \"location\": \"Bali, Indonesia\", \"followers\": 8000, \"linkedinUrl\": \"https://www.linkedin.com/in/willpolese\", \"imageUrl\": null }],\n  \"sameNameProfiles\": [],\n  \"linkedinUrl\": \"https://www.linkedin.com/in/justinwelsh\",\n  \"emailPattern\": \"first.last\",\n  \"emailPatternSource\": \"default\",\n  \"foundOnSite\": false,\n  \"alternatives\": [\n    { \"email\": \"justin@justinwelsh.me\", \"pattern\": \"first\" },\n    { \"email\": \"jwelsh@justinwelsh.me\", \"pattern\": \"flast\" }\n  ],\n  \"patternEvidence\": [],\n  \"emailProvider\": \"google\",\n  \"emailVerification\": { \"provider\": \"reoon\", \"status\": \"catch_all\", \"score\": 75, \"checkedAt\": \"2026-10-09T08:21:10.485Z\", \"checks\": 1, \"tried\": [{ \"email\": \"justin.welsh@justinwelsh.me\", \"status\": \"catch_all\" }] },\n  \"summary\": \"Not delivered as an e-mail: the mail server of justinwelsh.me accepts any address (catch-all), so no mailbox can be confirmed there; best unverified guess justin.welsh@justinwelsh.me is in \\\"emailGuess\\\". Charged as a plain profile.\",\n  \"scrapedAt\": \"2026-10-09T08:21:10.486Z\"\n}\n```\n\n### What the statuses mean\n\n| `emailStatus` | What it means | Charged as |\n|---|---|---|\n| `mailbox-verified` | the mailbox exists (SMTP check, `emailVerified: true`) | Profile with e-mail |\n| `catch-all` | the domain accepts any address — no mailbox can be confirmed; the address is in `emailGuess` | plain Profile |\n| `mailbox-unknown` / `mailbox-invalid` | the server would not say / no mailbox for the checked layouts | plain Profile |\n\nIf the mailbox check is unavailable in a run, the evidence rules apply instead (and `summary` says so):\n\n| `confidence` | `emailStatus` | What was checked | In `email` by default? |\n|---|---|---|---|\n| **confirmed** | `found-on-website` | the address itself is published on the company website | yes — Profile with e-mail |\n| **high** | `pattern-confirmed` | two or more personal addresses on the company site use this layout | yes — Profile with e-mail |\n| **medium** | `pattern-confirmed` | one personal address on the company site uses this layout | yes — Profile with e-mail |\n| **low** | `unverified-guess` | nothing: the most common corporate layout (`first.last`) on a domain that accepts mail | no — `emailGuess`, plain Profile price |\n| **unusable** | `undeliverable` / `risky` / `unknown` | the mail domain failed the DNS check | no — plain Profile price |\n\nUntil 5 October 2026 every address on a domain with an MX record was labelled `deliverable`. That label is gone: the DNS result is in `emailDomainStatus` and `emailMxHost`, and it says only that the **domain** takes mail, not that this mailbox exists.\n\nSince 9 October 2026 every address on a domain that takes mail also goes through an SMTP mailbox check (no e-mail is sent), and only a verified mailbox is charged as an e-mail.\n\n## Use cases for LinkedIn profile and e-mail data\n\n### Outbound from a LinkedIn search\nExport a search, paste the profile URLs, get title, company, career history and a work e-mail per person in one row — ready for a sequence.\n\n### Recruiting\nThe full career path with tenure per role, and an address to write to the candidate outside LinkedIn InMail.\n\n### CRM enrichment\nRefresh contacts on a schedule: job changes show up as a new current company, and the e-mail follows the new domain.\n\n### AI agents\nThrough the Apify MCP server an agent can ask *\"who is this person and how do I reach them?\"* and get one row back, with `summary` explaining the e-mail.\n\n## Integrations\n\nEvery run is available through the Apify API (JavaScript and Python clients), and the Actor works out of the box with n8n, Make, Zapier, Google Sheets, LangChain, webhooks and the Apify MCP server.\n\n```python\nfrom apify_client import ApifyClient\nclient = ApifyClient(\"<YOUR_APIFY_TOKEN>\")\nrun = client.actor(\"lergassy/linkedin-profile-email-scraper\").call(run_input={\n    \"profileUrls\": [\"https://www.linkedin.com/in/satyanadella\"], \"minConfidence\": \"medium\"})\nfor row in client.dataset(run[\"defaultDatasetId\"]).iterate_items():\n    print(row.get(\"fullName\"), row.get(\"email\"), row.get(\"confidence\"))\n```\n\n## ❓ FAQ\n\n### How is this different from harvestapi or dev_fusion?\nSame idea — LinkedIn profiles plus e-mail without cookies — at a lower price: $3.20 vs $4 per 1,000 plain profiles and $8 vs $10 per 1,000 profiles with e-mail. The bigger difference is **what you pay for**: harvestapi charges $10/1,000 for every e-mail *search*, and dev_fusion $10/1,000 for every row; here the e-mail price applies only to rows whose mailbox is verified, and every address comes with its evidence and the result of the mailbox check.\n\n### Do I need cookies or a LinkedIn account?\nNo. It reads public profiles only, so nothing can be restricted.\n\n### Why does a profile come back without an e-mail?\nThe profile lists no current company, the company has no website we can find (use **Company override** with its domain), the domain takes no mail, LinkedIn shows only the initial of the surname (\"Diego C.\") so the address cannot be written, or the mailbox could not be verified — usually a catch-all domain (then the address is in `emailGuess`). Those rows cost the plain Profile price.\n\n### Why is `email` empty but `emailGuess` filled?\nThe mailbox could not be verified — usually a catch-all domain (`emailCatchAll: true`), sometimes a server that will not say. The best address is in `emailGuess`, not charged as an e-mail; `emailVerification` shows what was checked.\n\n### What happens to an input that is not a profile URL?\nIt comes back as a free error row (`type: \"error\"`) that names the value, instead of being skipped silently.\n\n### Do I only need profiles, or only e-mails?\nProfiles only: [LinkedIn Profile Scraper](https://apify.com/lergassy/linkedin-profile-scraper). E-mail only, without the full profile: [LinkedIn Email Finder](https://apify.com/lergassy/linkedin-email-finder). This Actor is both in one row.\n\n### Is one row returned per profile?\nYes — one row per profile URL, one charge per row, duplicates in the input are read once.\n\n### Can I use it with the Apify API or an MCP server?\nYes. Call it from the API or the JavaScript / Python client, or let an AI agent call it through the Apify MCP server.\n\n### Can I integrate it with other apps?\nYes — n8n, Make, Zapier, Google Sheets, webhooks and anything that speaks HTTP.\n\n### Is it legal to scrape LinkedIn profiles and e-mails?\nThe Actor reads profiles that people have made public and builds business addresses from public company websites. The rows are personal data: under GDPR, CCPA and similar laws you need a lawful basis to process them, must respect opt-outs and anti-spam rules (CAN-SPAM, PECR), and must follow LinkedIn's terms. Use it for legitimate business purposes only; when in doubt, consult a lawyer.\n\n## Your feedback\n\nSomething missing or wrong in a row? Open an issue on the Issues tab — it gets answered fast. A review helps other buyers find the Actor.\n\n## You might also like\n\n| Actor | What it does |\n|---|---|\n| [LinkedIn Profile Scraper](https://apify.com/lergassy/linkedin-profile-scraper) | The same profiles without the e-mail step, $2–3 per 1,000 |\n| [LinkedIn Email Finder](https://apify.com/lergassy/linkedin-email-finder) | Work e-mail from a profile URL, paid per e-mail found |\n| [LinkedIn Company Scraper](https://apify.com/lergassy/linkedin-company-scraper) | Company pages: size, industry, website, HQ |\n| [LinkedIn Posts Scraper](https://apify.com/lergassy/linkedin-posts-scraper) | Posts and articles of people and companies |\n",
    "changelog": "# Changelog\n\n## 2026-10-09 (2)\n- Main company for people with several current jobs: `company` is now the one named in the headline (or, when LinkedIn hides the headline, in the About text or the profile's website), then founder / CEO level, then the longest-held — before, the first listed position was taken (a side project for some founders). New fields `otherCurrentCompanies`, `companyChosenBy`, `emailCompany`. When the main company's mail server accepts any address, the one remaining mailbox check goes to the most likely address at the next current company (still at most 2 checks per person).\n\n## 2026-10-09\n- Mailbox verification: every work e-mail is now checked by an SMTP mailbox check (new fields `emailVerified`, `emailCatchAll`, `emailVerification` with status, score and time). The row is charged as a profile with e-mail **only when the mailbox is verified**; addresses on catch-all domains and unconfirmed mailboxes come back in `emailGuess`, not charged as a profile with e-mail. New `confidence: verified` and `emailStatus` values `mailbox-verified`, `catch-all`, `mailbox-unknown`, `mailbox-invalid`.\n- Internal: cost-safety switches for the paid routes; run-health module updated (reports reliably when a run ends).\n\n## 2026-10-05 (2)\n- New fields `similarProfiles` (\"Other similar profiles\" — LinkedIn's \"People also viewed\" rail as logged-out visitors see it, usually 10–20 people with name, headline, location, followers, URL and photo) and `sameNameProfiles` (\"Others named …\", when shown). Same page, no extra request or charge.\n\n## 2026-10-05\n- E-mail honesty: `emailStatus` now says what was really checked — `found-on-website`, `pattern-confirmed` or `unverified-guess` (domain failures keep `undeliverable` / `risky` / `unknown`); it no longer says \"deliverable\", because no mailbox check is made. The domain's DNS verdict moved to the new `emailDomainStatus`.\n- Default \"Minimum e-mail confidence\" is now **medium**: an address built only from the most common layout goes to the new `emailGuess` field and the row is charged as a plain profile. Choose \"low\" to get such guesses in `email` (charged with e-mail) as before.\n- Profile part: every experience role (grouped roles were missing), education with degree and field of study (some schools were missing), company logos, `city` / `region` / `countryCode`, cover image, member id, languages with proficiency, courses, projects, test scores, courses taught.\n- An input value that is not a profile URL now gets a free error row instead of being skipped silently.\n\n## 2026-10-03\n- Profiles LinkedIn refuses on the first route now get one more unblocking route before the existing one, so more of them come back as full rows. Price unchanged; error rows stay free.\n- A short list made only of hidden profiles now gets the second route too, and hidden profiles no longer make the run send the rest of the list into it early.\n\n## 2026-10-02\n- Default memory now adapts to your input: short lists use less, long lists get more.\n\n## 2026-10-01\n- Initial release: full public LinkedIn profile (name, headline, current role, experience, education, skills and more) plus the person's work e-mail with its evidence and a confidence level, with no login or cookies.\n- The e-mail price is charged only when an address is found; otherwise the row is charged as a plain profile.\n- An e-mail is built only when the company's website is confirmed as that company's; unconfirmed domains return the profile without an address.\n- Addresses whose mail domain has no mail server or cannot be checked are returned as plain profiles.\n- Middle names are no longer merged into the last name when building the address.\n",
    "gitCommitId": "2e919265d7c77abb9e5ef225733db804e50f873d",
    "gitBranchName": "main",
    "actorDefinition": {
      "actorSpecification": 1,
      "name": "linkedin-profile-email-scraper",
      "title": "LinkedIn Profile Scraper with Email — No Cookies",
      "description": "LinkedIn profiles with work e-mail, without login or cookies: full profile (title, company, every role, education with degree, skills) plus the work e-mail with layout evidence and confidence. One row per profile; an e-mail is charged only at your minimum confidence; errors are free.",
      "version": "0.1",
      "maxMemoryMbytes": 2048,
      "defaultMemoryMbytes": "n = get(input, 'profileUrls.length', 0) + get(input, 'startUrls.length', 0); 512 + 512 * min(1, max(0, n - 10))",
      "dockerfile": "./Dockerfile",
      "input": {
        "title": "LinkedIn Profile Scraper with Email input",
        "type": "object",
        "schemaVersion": 1,
        "properties": {
          "profileUrls": {
            "title": "👤 LinkedIn profiles",
            "type": "array",
            "editor": "stringList",
            "description": "LinkedIn profile URLs or slugs, one per line — <b>https://www.linkedin.com/in/satyanadella</b> or <b>satyanadella</b>. One row per profile. Profiles that do not exist or are hidden from logged-out visitors are free.",
            "prefill": [
              "https://www.linkedin.com/in/satyanadella",
              "https://www.linkedin.com/in/jeffweiner08",
              "justinwelsh"
            ]
          },
          "startUrls": {
            "title": "🔗 Profiles from a file or sheet",
            "type": "array",
            "editor": "requestListSources",
            "default": [],
            "description": "The same thing for long lists — upload a file or link a Google Sheet (or any text/CSV URL) that contains LinkedIn profile URLs."
          },
          "findEmail": {
            "title": "📧 Find the work e-mail ($)",
            "type": "boolean",
            "default": true,
            "description": "Find each person's work e-mail: company website, the address layout it uses, mail-domain check, confidence. A row WITH an e-mail is charged as 'Profile with e-mail'; a row without one is charged as a plain 'Profile'. Switch off to get profiles only.",
            "sectionCaption": "📧 Work e-mail"
          },
          "minConfidence": {
            "title": "Minimum e-mail confidence to pay for",
            "type": "string",
            "editor": "select",
            "enum": [
              "low",
              "medium",
              "high",
              "confirmed"
            ],
            "enumTitles": [
              "low — layout guessed from the most common corporate format (unverified)",
              "medium — layout seen on the company's own site",
              "high — layout confirmed by 2+ addresses on the site",
              "confirmed — the address itself is published on the site"
            ],
            "default": "medium",
            "description": "Used only when the SMTP mailbox check is unavailable in a run (normally every address is mailbox-checked and only a verified one is put into 'email'). Below this level the address is NOT put into 'email': it goes to 'emailGuess' (and 'alternatives') and the row is charged as a plain profile. low = most common layout, nothing confirms it (emailStatus unverified-guess); medium = the company's own site uses this layout (pattern-confirmed); high = 2+ addresses on the site confirm it; confirmed = the address is published on the site (found-on-website). No mailbox (SMTP) check is made.",
            "prefill": "medium"
          },
          "companyOverride": {
            "title": "🏢 Company override",
            "type": "string",
            "editor": "textfield",
            "default": "",
            "description": "Use this company name or domain for everyone instead of what the profiles say — handy when all profiles work at one company, or when a company name cannot be turned into a website."
          },
          "candidatesPerPerson": {
            "title": "Alternative addresses per person",
            "type": "integer",
            "default": 3,
            "minimum": 1,
            "maximum": 8,
            "description": "The best address goes into 'email'; runners-up go into 'alternatives'."
          },
          "maxPagesPerCompany": {
            "title": "Company pages to read",
            "type": "integer",
            "default": 4,
            "minimum": 1,
            "maximum": 10,
            "description": "Home page plus contact / team / about pages, to learn how the company writes its addresses."
          },
          "checkMx": {
            "title": "Check that the mail domain accepts mail",
            "type": "boolean",
            "default": true,
            "description": "DNS MX check. It always runs, because it decides the charge: only an address on a domain with an MX record is delivered as an e-mail. A domain without an MX record, one that takes no mail, or one that does not answer DNS after three tries leaves the row a plain profile."
          },
          "includePosts": {
            "title": "📰 Add the latest posts and articles",
            "type": "boolean",
            "default": false,
            "description": "The person's recent posts (usually 5–9) and articles (up to 10) inside the same row. No extra charge.",
            "sectionCaption": "What else to put in the row"
          },
          "maxItems": {
            "title": "Maximum profiles per run",
            "type": "integer",
            "default": 10000,
            "minimum": 1,
            "description": "A hard ceiling on what one run reads and bills.",
            "sectionCaption": "Advanced"
          },
          "concurrency": {
            "title": "Parallel profiles",
            "type": "integer",
            "default": 3,
            "minimum": 1,
            "maximum": 10,
            "description": "How many profiles to read at the same time. Keep it low — LinkedIn dislikes bursts."
          },
          "pageTimeoutSecs": {
            "title": "Company page timeout (seconds)",
            "type": "integer",
            "default": 15,
            "minimum": 5,
            "maximum": 60,
            "description": "How long to wait for one company web page before giving up on it."
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "editor": "proxy",
            "default": {
              "useApifyProxy": true,
              "apifyProxyGroups": [
                "RESIDENTIAL"
              ]
            },
            "prefill": {
              "useApifyProxy": true,
              "apifyProxyGroups": [
                "RESIDENTIAL"
              ]
            },
            "description": "Residential, a new address for every profile — included in the price, nothing to set up. LinkedIn blocks direct and datacenter requests after a few dozen profiles, so those settings are ignored. Company websites are read directly. Only your own proxy URLs replace this (then the second route for refused profiles is off)."
          }
        },
        "required": []
      },
      "output": {
        "$schema": "https://apify-projects.github.io/actor-json-schemas/output.json",
        "actorOutputSchemaVersion": 1,
        "title": "Output of LinkedIn Profile Scraper with Email",
        "properties": {
          "results": {
            "type": "string",
            "title": "Profiles with e-mail (JSON)",
            "description": "One row per profile: current role, experience, education, skills, plus work e-mail, confidence and layout evidence.",
            "template": "{{links.apiDefaultDatasetUrl}}/items"
          },
          "runSummary": {
            "type": "string",
            "title": "Run summary (JSON)",
            "description": "JSON summary of the run: rows delivered, rows filtered out, failed inputs (free) and request statistics.",
            "template": "{{links.apiDefaultKeyValueStoreUrl}}/records/SUMMARY"
          },
          "notAttempted": {
            "type": "string",
            "title": "Inputs not attempted (JSON)",
            "description": "JSON list of inputs the run did not reach (time limit or \"Max cost per run\"). Not charged — pass them as input to a new run to continue. Present only when the run stopped early.",
            "template": "{{links.apiDefaultKeyValueStoreUrl}}/records/NOT_ATTEMPTED"
          }
        }
      },
      "storages": {
        "dataset": {
          "actorSpecification": 1,
          "fields": {
            "type": "object",
            "properties": {
              "type": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "profile or error"
              },
              "fullName": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Name"
              },
              "firstName": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "First name"
              },
              "lastName": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Last name"
              },
              "headline": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Headline"
              },
              "title": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Current title"
              },
              "company": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Current company"
              },
              "email": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Work e-mail whose mailbox was confirmed by an SMTP check (emailVerified true). Only rows with an e-mail are charged as profile-with-email. If the mailbox check is unavailable in a run, the old rule applies: filled at or above 'Minimum e-mail confidence'."
              },
              "emailVerified": {
                "type": [
                  "boolean",
                  "null"
                ],
                "nullable": true,
                "description": "true — the mailbox exists (SMTP mailbox check); false — checked but not confirmed (catch-all domain, unknown, invalid); null — not checked.",
                "example": true
              },
              "emailCatchAll": {
                "type": [
                  "boolean",
                  "null"
                ],
                "nullable": true,
                "description": "The company's mail server accepts any address (catch-all), so no address there can be confirmed.",
                "example": false
              },
              "emailVerification": {
                "type": [
                  "object",
                  "null"
                ],
                "nullable": true,
                "description": "The mailbox check: provider, status (safe, catch_all, unknown, invalid…), score, checkedAt, checks made, tried [{email, status}]."
              },
              "emailGuess": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "The best address built for the person when it is NOT delivered in 'email' (catch-all domain, mailbox not confirmed, confidence below your minimum, or a domain that failed the DNS check). Not charged as an e-mail.",
                "example": "satya.nadella@microsoft.com"
              },
              "confidence": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "verified (mailbox confirmed by SMTP check), confirmed (published on the company site), high, medium, low or unusable"
              },
              "emailStatus": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "What was really checked: mailbox-verified (SMTP mailbox check passed); catch-all (the server accepts any address, nothing can be confirmed), mailbox-unknown, mailbox-invalid; without a mailbox check: found-on-website, pattern-confirmed, unverified-guess; undeliverable / risky / unknown when the mail domain fails the DNS check.",
                "example": "mailbox-verified"
              },
              "emailReason": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Why an address was not delivered: no_mx_record, domain_not_found, domain_accepts_no_mail, dns_timeout, disposable_domain, possible_typo"
              },
              "domain": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Company website domain"
              },
              "companyLinkedinUrl": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Current company page"
              },
              "location": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Location"
              },
              "country": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Country code"
              },
              "city": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "City parsed from the profile location ('Redmond, Washington, United States' → Redmond). Null when LinkedIn shows only a country, a region or a metro area such as 'San Francisco Bay Area'.",
                "example": "Redmond"
              },
              "region": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "State / region parsed from the profile location.",
                "example": "Washington"
              },
              "countryCode": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "ISO 3166 two-letter country code of the profile location.",
                "example": "US"
              },
              "about": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "About"
              },
              "followers": {
                "type": [
                  "number",
                  "null"
                ],
                "nullable": true,
                "description": "Followers"
              },
              "connections": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Connections as shown (e.g. 500+)"
              },
              "badges": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Creator / Top Voice badges"
              },
              "website": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Website on the profile"
              },
              "experience": {
                "type": [
                  "array",
                  "null"
                ],
                "nullable": true,
                "description": "Every role in the Experience section, including each role inside a company group: title, company, companyLinkedinUrl, companyLogo, location, employmentType (only when the page shows it), startDate, endDate, current, duration, description. Logged-out visitors see at most the roles LinkedIn shows on the public page."
              },
              "currentPositions": {
                "type": [
                  "array",
                  "null"
                ],
                "nullable": true,
                "description": "Current positions: company, companyLinkedinUrl, companyLogo, title, location, employmentType, startDate, endDate, current."
              },
              "education": {
                "type": [
                  "array",
                  "null"
                ],
                "nullable": true,
                "description": "Every school in the Education section: school, schoolLinkedinUrl, schoolLogo, degree, fieldOfStudy, grade, activities, description, startDate, endDate."
              },
              "languages": {
                "type": [
                  "array",
                  "null"
                ],
                "nullable": true,
                "description": "Language names (see languageProficiencies for the proficiency)."
              },
              "awards": {
                "type": [
                  "array",
                  "null"
                ],
                "nullable": true,
                "description": "Awards"
              },
              "certifications": {
                "type": [
                  "array",
                  "null"
                ],
                "description": "Licenses and certifications: name, issuer, issuedAt, expiresAt, url, credentialId, issuerLinkedinUrl, logoUrl."
              },
              "volunteering": {
                "type": [
                  "array",
                  "null"
                ],
                "description": "Volunteer roles: role, organization, dates, description."
              },
              "publications": {
                "type": [
                  "array",
                  "null"
                ],
                "description": "Publications: title, publisher, date, link, description."
              },
              "honorsAndAwards": {
                "type": [
                  "array",
                  "null"
                ],
                "description": "Honors and awards: title, issuer, date, description."
              },
              "organizations": {
                "type": [
                  "array",
                  "null"
                ],
                "description": "Organizations: name, role, startDate, endDate, current, description."
              },
              "skills": {
                "type": [
                  "array",
                  "null"
                ],
                "description": "Skills listed on the public profile."
              },
              "recommendations": {
                "type": [
                  "array",
                  "null"
                ],
                "description": "Recommendations received: who wrote it, their profile link, the text."
              },
              "languageProficiencies": {
                "type": [
                  "array",
                  "null"
                ],
                "nullable": true,
                "description": "Languages with the proficiency the person states: [{name, proficiency}]. Empty when the profile shows no Languages section.",
                "example": [
                  {
                    "name": "English",
                    "proficiency": "Native or bilingual proficiency"
                  }
                ]
              },
              "courses": {
                "type": [
                  "array",
                  "null"
                ],
                "nullable": true,
                "description": "Courses the person lists (Courses section): [{name, number}].",
                "example": [
                  {
                    "name": "Business Finance",
                    "number": "BUS M 520"
                  }
                ]
              },
              "projects": {
                "type": [
                  "array",
                  "null"
                ],
                "nullable": true,
                "description": "Projects section: [{title, url, startDate, endDate, current, description}].",
                "example": [
                  {
                    "title": "Spend My Cents",
                    "url": "http://www.spendmycents.com/",
                    "startDate": "May 2013",
                    "endDate": null,
                    "current": false,
                    "description": "A reverse product search engine…"
                  }
                ]
              },
              "testScores": {
                "type": [
                  "array",
                  "null"
                ],
                "nullable": true,
                "description": "Test scores section: [{name, score, date, description}].",
                "example": [
                  {
                    "name": "GMAT",
                    "score": "590",
                    "date": "Aug 2011",
                    "description": null
                  }
                ]
              },
              "coursesTaught": {
                "type": [
                  "array",
                  "null"
                ],
                "nullable": true,
                "description": "LinkedIn Learning courses the person teaches ('Courses by …'): [{title, url, imageUrl, duration, viewers}].",
                "example": [
                  {
                    "title": "How to Use Generative AI: Building an AI-First Mindset",
                    "url": "https://www.linkedin.com/learning/how-to-use-generative-ai-building-an-ai-first-mindset",
                    "imageUrl": "https://media.licdn.com/dms/image/v2/…",
                    "duration": "48m",
                    "viewers": 414851
                  }
                ]
              },
              "imageUrl": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Photo"
              },
              "coverImageUrl": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Profile cover (background) image URL.",
                "example": "https://media.licdn.com/dms/image/v2/D4D16AQ…/profile-displaybackgroundimage-shrink_200_800/…"
              },
              "memberId": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "LinkedIn member id shown on the public page (the number in urn:li:member:…). Null when the page does not carry it.",
                "example": "1213"
              },
              "profileUrn": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "LinkedIn member URN of the profile.",
                "example": "urn:li:member:1213"
              },
              "similarProfiles": {
                "type": [
                  "array",
                  "null"
                ],
                "nullable": true,
                "description": "\"Other similar profiles\" from the side rail of the public profile (LinkedIn's \"People also viewed\" list as logged-out visitors see it, usually 10–20): [{name, headline, location, followers, linkedinUrl, imageUrl}]. headline is what the card shows — usually the person's current company. [] when the page has no such rail.",
                "example": [
                  {
                    "name": "Melinda French Gates",
                    "headline": "Pivotal",
                    "location": "United States",
                    "followers": 7000000,
                    "linkedinUrl": "https://www.linkedin.com/in/melindagates",
                    "imageUrl": "https://media.licdn.com/dms/image/v2/…"
                  }
                ]
              },
              "sameNameProfiles": {
                "type": [
                  "array",
                  "null"
                ],
                "nullable": true,
                "description": "\"Others named <name>\" from the side rail, when LinkedIn shows it (only for some names): [{name, headline, location, followers, linkedinUrl, imageUrl}] — other people with the same name; headline and followers are usually null.",
                "example": [
                  {
                    "name": "Reid Hoffman",
                    "headline": null,
                    "location": "Florence, KY",
                    "followers": null,
                    "linkedinUrl": "https://www.linkedin.com/in/reid-hoffman-7143a718a",
                    "imageUrl": "https://media.licdn.com/dms/image/v2/…"
                  }
                ]
              },
              "linkedinUrl": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Profile URL"
              },
              "slug": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Profile slug"
              },
              "latestPosts": {
                "type": [
                  "array",
                  "null"
                ],
                "nullable": true,
                "description": "Recent posts (optional)"
              },
              "articles": {
                "type": [
                  "array",
                  "null"
                ],
                "nullable": true,
                "description": "Articles (optional)"
              },
              "domainSource": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "How the company's domain was confirmed: input (you gave it), parent (parent company's mail domain, e.g. Microsoft AI → microsoft.com), linkedin (the company's LinkedIn page links it), directory (the domain spells the company name), site (the website carries the company's name). Unconfirmed domains are never used."
              },
              "domainEvidence": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "One-line reason the domain is the company's."
              },
              "unconfirmedDomains": {
                "type": [
                  "array",
                  "null"
                ],
                "nullable": true,
                "items": {
                  "type": "string"
                },
                "description": "Domains found for the company name that could not be confirmed as its website — no address was built on them and the row was charged as a plain profile."
              },
              "companyWebsiteName": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Company name as the website says it"
              },
              "emailPattern": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Layout used, e.g. first.last"
              },
              "emailPatternSource": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "site when learnt from the company website, else default"
              },
              "foundOnSite": {
                "type": [
                  "boolean",
                  "null"
                ],
                "nullable": true,
                "description": "The address itself is published on the company site"
              },
              "alternatives": {
                "type": [
                  "array",
                  "null"
                ],
                "nullable": true,
                "description": "Runner-up addresses"
              },
              "patternEvidence": {
                "type": [
                  "array",
                  "null"
                ],
                "nullable": true,
                "description": "Addresses on the site that show the layout"
              },
              "patternEvidenceCount": {
                "type": [
                  "number",
                  "null"
                ],
                "nullable": true,
                "description": "How many"
              },
              "emailProvider": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Mail provider"
              },
              "emailMxHost": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "MX host"
              },
              "emailDomainStatus": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "DNS verdict for the mail domain: accepts-mail (MX record found), risky (no MX record, disposable or typo'd domain), undeliverable, unknown (DNS did not answer). Says nothing about the mailbox itself.",
                "example": "accepts-mail"
              },
              "emailIsRole": {
                "type": [
                  "boolean",
                  "null"
                ],
                "nullable": true,
                "description": "Role address"
              },
              "emailIsFree": {
                "type": [
                  "boolean",
                  "null"
                ],
                "nullable": true,
                "description": "Free mailbox domain"
              },
              "emailIsDisposable": {
                "type": [
                  "boolean",
                  "null"
                ],
                "nullable": true,
                "description": "Disposable domain"
              },
              "summary": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "One-line explanation of the e-mail and of how the row was charged"
              },
              "error": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Why the profile could not be read"
              },
              "input": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "Error rows only: the input value that could not be used.",
                "example": "not a url"
              },
              "scrapedAt": {
                "type": [
                  "string",
                  "null"
                ],
                "nullable": true,
                "description": "When the row was made"
              }
            }
          },
          "views": {
            "profiles": {
              "title": "Profiles with e-mail",
              "transformation": {
                "fields": [
                  "fullName",
                  "title",
                  "company",
                  "email",
                  "emailVerified",
                  "confidence",
                  "location",
                  "followers",
                  "headline",
                  "linkedinUrl",
                  "domain"
                ]
              },
              "display": {
                "component": "table",
                "properties": {
                  "fullName": {
                    "label": "Name"
                  },
                  "title": {
                    "label": "Title"
                  },
                  "company": {
                    "label": "Company"
                  },
                  "email": {
                    "label": "E-mail"
                  },
                  "emailVerified": {
                    "label": "Mailbox verified"
                  },
                  "confidence": {
                    "label": "Confidence"
                  },
                  "location": {
                    "label": "Location"
                  },
                  "followers": {
                    "label": "Followers",
                    "format": "number"
                  },
                  "headline": {
                    "label": "Headline"
                  },
                  "linkedinUrl": {
                    "label": "LinkedIn",
                    "format": "link"
                  },
                  "domain": {
                    "label": "Domain"
                  }
                }
              }
            }
          }
        },
        "keyValueStore": {
          "actorKeyValueStoreSchemaVersion": 1,
          "title": "Run records of LinkedIn Profile Scraper with Email — No Cookies",
          "description": "Records the Actor saves next to its dataset: a JSON run summary and, when the run stops early, the inputs it did not reach.",
          "collections": {
            "runSummary": {
              "title": "Run summary",
              "description": "JSON summary of the run: rows delivered, rows filtered out, failed inputs (free) and request statistics.",
              "key": "SUMMARY"
            },
            "notAttempted": {
              "title": "Inputs not attempted",
              "description": "JSON list of inputs the run did not reach (time limit or \"Max cost per run\"). Not charged — pass them as input to a new run to continue.",
              "key": "NOT_ATTEMPTED"
            }
          }
        }
      },
      "readme": "**LinkedIn Profile Scraper with Email** turns LinkedIn profile URLs into complete rows: the **full public profile** — name, headline, current title and company, location, about, followers, the whole experience history with dates, education, certifications, skills, recommendations — **plus the person's work e-mail address, with the mailbox verified by an SMTP check**, and the evidence behind it.\n\n**$3.20 per 1,000 profiles, $8 per 1,000 profiles with e-mail** — and you pay the e-mail price **only when the mailbox is verified** by an SMTP check (no e-mail is sent). Catch-all domains (the mail server accepts any address) are returned unverified and not charged as an e-mail. No LinkedIn login, no cookies, no account at risk, no start fee. Profiles that do not exist or that LinkedIn hides from logged-out visitors are free.\n\n## Tested head-to-head — 9 October 2026\n\nThe same 10 public LinkedIn profiles of founders and executives (Apify, Single Grain, Gates Foundation, Microsoft, Stripe, HubSpot and others) went to this Actor and to the most-used LinkedIn profile scraper with e-mail search on the Apify Store, on the same day:\n\n| | This Actor | harvestapi/linkedin-profile-scraper (profile + e-mail search) |\n|---|---|---|\n| Mailbox-verified work e-mails | **7 of 10** | 8 of 10 |\n| Catch-all domains (no mailbox can be confirmed) | 3 — returned unverified in `emailGuess`, charged as plain profiles | 2 — returned as \"risky\", billed as e-mail searches |\n| Bill for the 10 profiles | **$0.066** | $0.10 |\n| Price per verified e-mail on this list | **$0.0094** | $0.0125 |\n\n5 of our 7 verified addresses are the same as the leader's; the other 2 are different verified mailboxes of the same people. The one verified address we missed belongs to a person whose public profile lists a different company as the only current position, so the address was built on that domain.\n\n## What is LinkedIn Profile Scraper with Email?\n\nA **LinkedIn email finder and profile scraper in one run**, for sales prospecting, recruiting and CRM enrichment. It reads the **public profile page** — the version LinkedIn shows search engines and logged-out visitors — and returns it as structured data. Then it turns the person's current company into its website, reads how that company writes its e-mail addresses (a team page that says `jane.doe@` tells you how everyone else is addressed), builds the person's address in that layout and checks that the mail domain accepts mail.\n\nOne row per person, one charge per row: **Profile with e-mail** when the row carries an address, **Profile** when it does not. Never both. No official LinkedIn API needed.\n\n## What data does it extract?\n\n| Field | Meaning |\n|---|---|\n| `fullName`, `firstName`, `lastName`, `headline` | Identity as shown on the profile |\n| `title`, `company`, `companyLinkedinUrl`, `currentPositions` | Current role(s) with the company page |\n| `otherCurrentCompanies`, `companyChosenBy` | When a person has several current jobs, `company` is the main one — named in the headline (or, when LinkedIn hides the headline, in the About text / profile website), then founder / CEO level, then the longest-held; the other current companies are in `otherCurrentCompanies`, and `companyChosenBy` says why. If the main company's mail server accepts any address, one check goes to the next current company (`emailCompany` says where the e-mail is) |\n| 📧 `email`, `confidence`, `emailStatus` | The work e-mail — **only a mailbox verified by the SMTP check** (`confidence: verified`, `emailStatus: mailbox-verified`); not verified: `catch-all`, `mailbox-unknown`, `mailbox-invalid` (see below) |\n| `emailVerified`, `emailCatchAll`, `emailVerification` | `true` — the mailbox exists; `false` — checked, not confirmed; `null` — not checked. `emailCatchAll: true` — the domain accepts any address. `emailVerification` — status (`safe`, `catch_all`, `unknown`, `invalid`…), score, time and every address tried |\n| `emailGuess` | The best unverified address when it is **not** put into `email` (catch-all domain, mailbox not confirmed, or the domain failed the DNS check) — not charged as an e-mail, use at your own risk |\n| `emailDomainStatus` | DNS verdict for the mail domain: `accepts-mail`, `risky`, `undeliverable`, `unknown` |\n| `emailPattern`, `foundOnSite`, `patternEvidence`, `patternEvidenceCount` | The layout used (`first.last`, `flast`, `first`…), whether the address itself is on the company site, and the published addresses that prove the layout |\n| `alternatives` | Runner-up addresses in the other plausible layouts |\n| `domain`, `domainSource`, `domainEvidence`, `companyWebsiteName` | The company website and how it was confirmed as the company's |\n| `emailProvider`, `emailMxHost`, `emailIsRole`, `emailIsFree`, `emailIsDisposable` | Mail-domain checks: Google Workspace, Microsoft 365…, role / free / disposable flags |\n| `summary` | One line: where the e-mail came from and how the row was charged |\n| `location`, `country`, `about`, `website` | Location, about text, website from the profile |\n| `city`, `region`, `countryCode` | The location split into parts (`Redmond` / `Washington` / `US`); city and region stay empty for a country-only or metro-area location |\n| `followers`, `connections`, `badges` | Follower count, \"500+\" connections, Creator / Top Voice |\n| `experience` | Every role, including each role inside a company group: title, company, company URL, `companyLogo`, `location`, `employmentType` (when shown), start, end, current flag, duration, full description |\n| `education` | Every school with `degree`, `fieldOfStudy`, `activities`, `grade`, `description`, `schoolLogo`, start and end |\n| `certifications`, `volunteering`, `publications`, `honorsAndAwards`, `organizations`, `skills`, `recommendations` | Every such section the public profile shows |\n| `languages`, `languageProficiencies`, `courses`, `projects`, `testScores`, `coursesTaught` | Languages with proficiency, courses, projects, test scores, LinkedIn Learning courses the person teaches |\n| `imageUrl`, `coverImageUrl`, `memberId`, `profileUrn` | Photo, cover image, LinkedIn member id and URN |\n| `similarProfiles`, `sameNameProfiles` | \"Other similar profiles\" (LinkedIn's \"People also viewed\" rail as logged-out visitors see it, usually 10–20: name, headline as the card shows it, location, followers, URL, photo) and \"Others named …\" when shown — free leads, no extra charge |\n| `latestPosts`, `articles` | With **Add the latest posts and articles** on: 5–9 recent posts and up to 10 articles |\n\nThe field names are the same as in our [LinkedIn Profile Scraper](https://apify.com/lergassy/linkedin-profile-scraper) (profile part) and [LinkedIn Email Finder](https://apify.com/lergassy/linkedin-email-finder) (e-mail part), so a pipeline built on either keeps working.\n\n## 💰 How much does it cost to scrape LinkedIn profiles with email?\n\n| Event | You pay for | FREE | BRONZE | SILVER | GOLD / PLATINUM / DIAMOND |\n|---|---|---|---|---|---|\n| **Profile with e-mail** | a row whose `email` is filled — the mailbox is verified by the SMTP check | $0.008 | $0.0076 | $0.0072 | $0.0068 |\n| **Profile** | a row without an e-mail (a guess only in `emailGuess` counts as no e-mail), or e-mail search off | $0.0032 | $0.00304 | $0.00288 | $0.00272 |\n| Error row, 404, profile hidden from logged-out visitors | — | **$0** | **$0** | **$0** | **$0** |\n\n- **The e-mail price is paid only for a verified mailbox.** A catch-all domain, a mailbox the SMTP check could not confirm, a person whose company has no findable website, an address on a domain that takes no mail or has no MX record, a domain that does not answer a DNS check after three tries — the row is delivered and charged as a plain **Profile** (the guess is kept in `emailGuess` and `alternatives`, except on a domain that takes no mail).\n- **No address on an unconfirmed domain.** An address is built only on a domain with evidence that it is the company's: you gave it, it is the parent's mail domain (Microsoft AI → microsoft.com), the company's LinkedIn page links it, the domain spells the company name, or the website carries the company's name. A look-alike domain is listed in `unconfirmedDomains` and the row is a plain **Profile**. Titles and credentials in names (Dr., Gov., PhD, MBA, Jr., emojis, text after a comma or a pipe) are removed before the address is written, and a middle name is never glued into it: \"John H. Cammack\" is john.cammack@, while a surname with particles stays whole (\"van der Berg\", \"de la Cruz\").\n- **Mailbox check, at most 2 per person** (9 October 2026): the address published on the company site or built on the company's own layout first, then the most likely layouts; the first mailbox that exists is the e-mail. Measured on 10 public profiles of founders and executives: **7 of 10 mailbox-verified e-mails**, 2 checks per verified address on average; the other 3 were catch-all domains, charged as plain profiles.\n- **Minimum e-mail confidence to pay for** applies only if the mailbox check is unavailable in a run (default `medium` since 5 October 2026): a `low` address — the most common layout, nothing on the company's site confirms it — goes to `emailGuess` instead of `email`, at the plain profile price. Set it to `low` to get such guesses in `email` and pay the e-mail price for them; `high` or `confirmed` to pay only for stronger evidence.\n- Experience, education, skills, posts, alternatives, evidence and domain checks: included. No fee per run, no proxy charge.\n- On Apify's free plan ($5 of monthly credit) that is about **620 profiles with e-mail** or **1,500 profiles** a month.\n\n### Bulk export: what 50,000 profiles actually cost\n\n| Job: 50,000 LinkedIn profiles | This Actor | harvestapi/linkedin-profile-scraper | dev_fusion/Linkedin-Profile-Scraper |\n|---|---|---|---|\n| Profiles only | **$160** | $200 | — |\n| Profiles + e-mail search | **$294** (e-mail on ~56% of rows — $8/1,000 for those, $3.20/1,000 for the rest) | $500 ($10/1,000 per e-mail **search**, found or not) | $500 ($10/1,000 rows) |\n\nPrices from the Apify Store on 1 October 2026 (FREE tier). The e-mail share is what we measured on a test list of 25 real profiles on 1 October 2026: **14 of 25 rows (56%) carried an e-mail**. An address is delivered only on a domain we could confirm as the company's own (and whose mail domain has a working MX record) — a person whose company we cannot pin to its website gets a plain profile row instead of a guess. Yours will differ, and you only pay $8/1,000 for the rows that actually carry an address. Since 9 October 2026 only a mailbox verified by an SMTP check is charged as an e-mail: on 10 public profiles of founders and executives that was 7 of 10; addresses on catch-all domains come at the plain profile price.\n\n### Why some profiles come back as free error rows\n\nEvery profile is read through a residential address, a new one for each profile. About one profile in five is hidden from logged-out visitors on that route (LinkedIn answers HTTP 999 or a login wall). Hidden profiles are opened through a second route: a web unblocker first, and a heavier unblocking service for the ones it cannot open — together they open most of them, even on a short list made only of hidden profiles. The second route is paid from the run's own margin and is included in the price. What still refuses — usually profiles their owners hid from search engines — comes back as an error row and costs nothing. This Actor never logs in. On our 120-profile test list on 1 October 2026 all 120 profiles were delivered, 31 of them through the second route — expect a few percent of error rows on other lists.\n\n### Run health\n\nWhen a run ends with many error rows, the Actor sends its developer the counts (rows delivered, error types, run ID) so the cause gets fixed fast. Your input and your results are never sent.\n\n### Very long lists\n\nWhen most of the last 30 profiles in a run are refused by rate limits (hidden profiles do not count), the rest of the list goes straight to the second route (with your own proxies: the run pauses for 90 seconds, and after two pauses stops). A run that gets within 45 seconds of its timeout stops taking new profiles the same way. Profiles that were not tried are not charged; their URLs are saved in the `NOT_ATTEMPTED` record of the run's key-value store and named in the status message. With **Max cost per run** set, the run stops by itself at that amount, green, with every written row paid for.\n\n## How to scrape LinkedIn profiles with email in three steps\n\n1. Paste LinkedIn profile URLs or slugs into **👤 LinkedIn profiles** — `https://www.linkedin.com/in/satyanadella` or `satyanadella` — or link a file / Google Sheet.\n2. Leave **📧 Find the work e-mail** on. Optionally raise **Minimum e-mail confidence to pay for**, or set **Company override** when the whole list works at one company.\n3. Press **Start**, then download JSON, CSV or Excel — or call it from the API, n8n, Make, Zapier or an AI agent.\n\n## ⬇️ Input\n\n```json\n{\n  \"profileUrls\": [\"https://www.linkedin.com/in/satyanadella\", \"jeffweiner08\", \"justinwelsh\"],\n  \"findEmail\": true,\n  \"minConfidence\": \"medium\",\n  \"includePosts\": false\n}\n```\n\n### Input options\n\n| Field | Default | What it does |\n|---|---|---|\n| `profileUrls` | 3 demo profiles | Profile URLs or slugs |\n| `startUrls` | — | A file or Google Sheet with profile URLs |\n| `findEmail` | `true` | Find the work e-mail; off = profiles only at the Profile price |\n| `minConfidence` | `medium` | Lowest confidence put into `email` and paid at the e-mail price; weaker guesses go to `emailGuess` |\n| `companyOverride` | — | One company name or domain for everyone |\n| `candidatesPerPerson` | 3 | How many addresses (best + alternatives) |\n| `maxPagesPerCompany` | 4 | Company pages read to learn the address layout |\n| `checkMx` | `true` | DNS check that the mail domain accepts mail — always runs, because only an address on a domain with an MX record is charged as an e-mail |\n| `includePosts` | `false` | Latest posts and articles in the row, no extra charge |\n| `maxItems`, `concurrency`, `pageTimeoutSecs`, `proxyConfiguration` | | Limits and network settings |\n\n## ⬆️ Output\n\n```json\n{\n  \"type\": \"profile\",\n  \"fullName\": \"Justin Welsh\",\n  \"firstName\": \"Justin\",\n  \"lastName\": \"Welsh\",\n  \"headline\": \"Writer & Entrepreneur. I write The Saturday Essay for 200,000+ ambitious people…\",\n  \"title\": \"Writer\",\n  \"company\": \"the saturday essay.\",\n  \"email\": null,\n  \"emailVerified\": false,\n  \"emailCatchAll\": true,\n  \"confidence\": \"low\",\n  \"emailStatus\": \"catch-all\",\n  \"domain\": \"justinwelsh.me\",\n  \"emailGuess\": \"justin.welsh@justinwelsh.me\",\n  \"emailDomainStatus\": \"accepts-mail\",\n  \"companyLinkedinUrl\": \"https://www.linkedin.com/company/saturday-essay\",\n  \"location\": \"New York City Metropolitan Area\",\n  \"city\": null,\n  \"region\": null,\n  \"countryCode\": \"US\",\n  \"followers\": 883050,\n  \"connections\": \"500+\",\n  \"experience\": [\n    { \"title\": \"Writer\", \"company\": \"the saturday essay.\", \"startDate\": \"Jan 2022\", \"endDate\": null, \"current\": true, \"duration\": \"4 years 10 months\", \"companyLogo\": \"https://media.licdn.com/dms/image/v2/…\", \"location\": null, \"employmentType\": null },\n    { \"title\": \"Founder\", \"company\": \"Justin Welsh\", \"startDate\": \"Aug 2019\", \"endDate\": null, \"current\": true, \"duration\": \"7 years 3 months\", \"companyLogo\": \"https://media.licdn.com/dms/image/v2/…\", \"location\": null, \"employmentType\": null }\n  ],\n  \"education\": [{ \"school\": \"The Ohio State University\", \"startDate\": \"1999\", \"endDate\": \"2003\", \"degree\": \"BSBA\", \"fieldOfStudy\": \"Marketing\", \"activities\": \"Phi Kappa Tau Fraternity, Project Open Hand, Economics Tutor\" }],\n  \"coverImageUrl\": \"https://media.licdn.com/dms/image/v2/…\",\n  \"memberId\": \"16259454\",\n  \"similarProfiles\": [{ \"name\": \"Will Polese\", \"headline\": \"ELSA, Corp\", \"location\": \"Bali, Indonesia\", \"followers\": 8000, \"linkedinUrl\": \"https://www.linkedin.com/in/willpolese\", \"imageUrl\": null }],\n  \"sameNameProfiles\": [],\n  \"linkedinUrl\": \"https://www.linkedin.com/in/justinwelsh\",\n  \"emailPattern\": \"first.last\",\n  \"emailPatternSource\": \"default\",\n  \"foundOnSite\": false,\n  \"alternatives\": [\n    { \"email\": \"justin@justinwelsh.me\", \"pattern\": \"first\" },\n    { \"email\": \"jwelsh@justinwelsh.me\", \"pattern\": \"flast\" }\n  ],\n  \"patternEvidence\": [],\n  \"emailProvider\": \"google\",\n  \"emailVerification\": { \"provider\": \"reoon\", \"status\": \"catch_all\", \"score\": 75, \"checkedAt\": \"2026-10-09T08:21:10.485Z\", \"checks\": 1, \"tried\": [{ \"email\": \"justin.welsh@justinwelsh.me\", \"status\": \"catch_all\" }] },\n  \"summary\": \"Not delivered as an e-mail: the mail server of justinwelsh.me accepts any address (catch-all), so no mailbox can be confirmed there; best unverified guess justin.welsh@justinwelsh.me is in \\\"emailGuess\\\". Charged as a plain profile.\",\n  \"scrapedAt\": \"2026-10-09T08:21:10.486Z\"\n}\n```\n\n### What the statuses mean\n\n| `emailStatus` | What it means | Charged as |\n|---|---|---|\n| `mailbox-verified` | the mailbox exists (SMTP check, `emailVerified: true`) | Profile with e-mail |\n| `catch-all` | the domain accepts any address — no mailbox can be confirmed; the address is in `emailGuess` | plain Profile |\n| `mailbox-unknown` / `mailbox-invalid` | the server would not say / no mailbox for the checked layouts | plain Profile |\n\nIf the mailbox check is unavailable in a run, the evidence rules apply instead (and `summary` says so):\n\n| `confidence` | `emailStatus` | What was checked | In `email` by default? |\n|---|---|---|---|\n| **confirmed** | `found-on-website` | the address itself is published on the company website | yes — Profile with e-mail |\n| **high** | `pattern-confirmed` | two or more personal addresses on the company site use this layout | yes — Profile with e-mail |\n| **medium** | `pattern-confirmed` | one personal address on the company site uses this layout | yes — Profile with e-mail |\n| **low** | `unverified-guess` | nothing: the most common corporate layout (`first.last`) on a domain that accepts mail | no — `emailGuess`, plain Profile price |\n| **unusable** | `undeliverable` / `risky` / `unknown` | the mail domain failed the DNS check | no — plain Profile price |\n\nUntil 5 October 2026 every address on a domain with an MX record was labelled `deliverable`. That label is gone: the DNS result is in `emailDomainStatus` and `emailMxHost`, and it says only that the **domain** takes mail, not that this mailbox exists.\n\nSince 9 October 2026 every address on a domain that takes mail also goes through an SMTP mailbox check (no e-mail is sent), and only a verified mailbox is charged as an e-mail.\n\n## Use cases for LinkedIn profile and e-mail data\n\n### Outbound from a LinkedIn search\nExport a search, paste the profile URLs, get title, company, career history and a work e-mail per person in one row — ready for a sequence.\n\n### Recruiting\nThe full career path with tenure per role, and an address to write to the candidate outside LinkedIn InMail.\n\n### CRM enrichment\nRefresh contacts on a schedule: job changes show up as a new current company, and the e-mail follows the new domain.\n\n### AI agents\nThrough the Apify MCP server an agent can ask *\"who is this person and how do I reach them?\"* and get one row back, with `summary` explaining the e-mail.\n\n## Integrations\n\nEvery run is available through the Apify API (JavaScript and Python clients), and the Actor works out of the box with n8n, Make, Zapier, Google Sheets, LangChain, webhooks and the Apify MCP server.\n\n```python\nfrom apify_client import ApifyClient\nclient = ApifyClient(\"<YOUR_APIFY_TOKEN>\")\nrun = client.actor(\"lergassy/linkedin-profile-email-scraper\").call(run_input={\n    \"profileUrls\": [\"https://www.linkedin.com/in/satyanadella\"], \"minConfidence\": \"medium\"})\nfor row in client.dataset(run[\"defaultDatasetId\"]).iterate_items():\n    print(row.get(\"fullName\"), row.get(\"email\"), row.get(\"confidence\"))\n```\n\n## ❓ FAQ\n\n### How is this different from harvestapi or dev_fusion?\nSame idea — LinkedIn profiles plus e-mail without cookies — at a lower price: $3.20 vs $4 per 1,000 plain profiles and $8 vs $10 per 1,000 profiles with e-mail. The bigger difference is **what you pay for**: harvestapi charges $10/1,000 for every e-mail *search*, and dev_fusion $10/1,000 for every row; here the e-mail price applies only to rows whose mailbox is verified, and every address comes with its evidence and the result of the mailbox check.\n\n### Do I need cookies or a LinkedIn account?\nNo. It reads public profiles only, so nothing can be restricted.\n\n### Why does a profile come back without an e-mail?\nThe profile lists no current company, the company has no website we can find (use **Company override** with its domain), the domain takes no mail, LinkedIn shows only the initial of the surname (\"Diego C.\") so the address cannot be written, or the mailbox could not be verified — usually a catch-all domain (then the address is in `emailGuess`). Those rows cost the plain Profile price.\n\n### Why is `email` empty but `emailGuess` filled?\nThe mailbox could not be verified — usually a catch-all domain (`emailCatchAll: true`), sometimes a server that will not say. The best address is in `emailGuess`, not charged as an e-mail; `emailVerification` shows what was checked.\n\n### What happens to an input that is not a profile URL?\nIt comes back as a free error row (`type: \"error\"`) that names the value, instead of being skipped silently.\n\n### Do I only need profiles, or only e-mails?\nProfiles only: [LinkedIn Profile Scraper](https://apify.com/lergassy/linkedin-profile-scraper). E-mail only, without the full profile: [LinkedIn Email Finder](https://apify.com/lergassy/linkedin-email-finder). This Actor is both in one row.\n\n### Is one row returned per profile?\nYes — one row per profile URL, one charge per row, duplicates in the input are read once.\n\n### Can I use it with the Apify API or an MCP server?\nYes. Call it from the API or the JavaScript / Python client, or let an AI agent call it through the Apify MCP server.\n\n### Can I integrate it with other apps?\nYes — n8n, Make, Zapier, Google Sheets, webhooks and anything that speaks HTTP.\n\n### Is it legal to scrape LinkedIn profiles and e-mails?\nThe Actor reads profiles that people have made public and builds business addresses from public company websites. The rows are personal data: under GDPR, CCPA and similar laws you need a lawful basis to process them, must respect opt-outs and anti-spam rules (CAN-SPAM, PECR), and must follow LinkedIn's terms. Use it for legitimate business purposes only; when in doubt, consult a lawyer.\n\n## Your feedback\n\nSomething missing or wrong in a row? Open an issue on the Issues tab — it gets answered fast. A review helps other buyers find the Actor.\n\n## You might also like\n\n| Actor | What it does |\n|---|---|\n| [LinkedIn Profile Scraper](https://apify.com/lergassy/linkedin-profile-scraper) | The same profiles without the e-mail step, $2–3 per 1,000 |\n| [LinkedIn Email Finder](https://apify.com/lergassy/linkedin-email-finder) | Work e-mail from a profile URL, paid per e-mail found |\n| [LinkedIn Company Scraper](https://apify.com/lergassy/linkedin-company-scraper) | Company pages: size, industry, website, HQ |\n| [LinkedIn Posts Scraper](https://apify.com/lergassy/linkedin-posts-scraper) | Posts and articles of people and companies |\n",
      "changelog": "# Changelog\n\n## 2026-10-09 (2)\n- Main company for people with several current jobs: `company` is now the one named in the headline (or, when LinkedIn hides the headline, in the About text or the profile's website), then founder / CEO level, then the longest-held — before, the first listed position was taken (a side project for some founders). New fields `otherCurrentCompanies`, `companyChosenBy`, `emailCompany`. When the main company's mail server accepts any address, the one remaining mailbox check goes to the most likely address at the next current company (still at most 2 checks per person).\n\n## 2026-10-09\n- Mailbox verification: every work e-mail is now checked by an SMTP mailbox check (new fields `emailVerified`, `emailCatchAll`, `emailVerification` with status, score and time). The row is charged as a profile with e-mail **only when the mailbox is verified**; addresses on catch-all domains and unconfirmed mailboxes come back in `emailGuess`, not charged as a profile with e-mail. New `confidence: verified` and `emailStatus` values `mailbox-verified`, `catch-all`, `mailbox-unknown`, `mailbox-invalid`.\n- Internal: cost-safety switches for the paid routes; run-health module updated (reports reliably when a run ends).\n\n## 2026-10-05 (2)\n- New fields `similarProfiles` (\"Other similar profiles\" — LinkedIn's \"People also viewed\" rail as logged-out visitors see it, usually 10–20 people with name, headline, location, followers, URL and photo) and `sameNameProfiles` (\"Others named …\", when shown). Same page, no extra request or charge.\n\n## 2026-10-05\n- E-mail honesty: `emailStatus` now says what was really checked — `found-on-website`, `pattern-confirmed` or `unverified-guess` (domain failures keep `undeliverable` / `risky` / `unknown`); it no longer says \"deliverable\", because no mailbox check is made. The domain's DNS verdict moved to the new `emailDomainStatus`.\n- Default \"Minimum e-mail confidence\" is now **medium**: an address built only from the most common layout goes to the new `emailGuess` field and the row is charged as a plain profile. Choose \"low\" to get such guesses in `email` (charged with e-mail) as before.\n- Profile part: every experience role (grouped roles were missing), education with degree and field of study (some schools were missing), company logos, `city` / `region` / `countryCode`, cover image, member id, languages with proficiency, courses, projects, test scores, courses taught.\n- An input value that is not a profile URL now gets a free error row instead of being skipped silently.\n\n## 2026-10-03\n- Profiles LinkedIn refuses on the first route now get one more unblocking route before the existing one, so more of them come back as full rows. Price unchanged; error rows stay free.\n- A short list made only of hidden profiles now gets the second route too, and hidden profiles no longer make the run send the rest of the list into it early.\n\n## 2026-10-02\n- Default memory now adapts to your input: short lists use less, long lists get more.\n\n## 2026-10-01\n- Initial release: full public LinkedIn profile (name, headline, current role, experience, education, skills and more) plus the person's work e-mail with its evidence and a confidence level, with no login or cookies.\n- The e-mail price is charged only when an address is found; otherwise the row is charged as a plain profile.\n- An e-mail is built only when the company's website is confirmed as that company's; unconfirmed domains return the profile without an address.\n- Addresses whose mail domain has no mail server or cannot be checked are returned as plain profiles.\n- Middle names are no longer merged into the last name when building the address.\n"
    },
    "buildNumber": "0.1.34",
    "imageDigest": "20a3021f54324ce4b1712431438d18cd1d6f4fdc0d202a9db203a59719461611",
    "actVersion": {
      "sourceType": "GIT_REPO",
      "buildTag": "latest",
      "versionNumber": "0.1"
    },
    "usage": {
      "ACTOR_COMPUTE_UNITS": 0.025335555555555556
    }
  }
}