{
  "data": {
    "id": "do8Fd1bCXvy4uJKod",
    "actId": "WJMzyiITEikwHLwwS",
    "userId": "37EfuyJq9V1PGIamn",
    "startedAt": "2026-10-02T20:12:57.355Z",
    "finishedAt": "2026-10-02T20:13:17.263Z",
    "status": "SUCCEEDED",
    "meta": {
      "origin": "CLI"
    },
    "stats": {
      "durationMillis": 19827,
      "runTimeSecs": 19.827,
      "computeUnits": 0.02203,
      "imageSizeBytes": 308944384
    },
    "options": {
      "useCache": true,
      "betaPackages": false,
      "memoryMbytes": 4096,
      "diskMbytes": 8192
    },
    "exitCode": 0,
    "inputSchema": "{\n  \"title\": \"LinkedIn Email Finder Input\",\n  \"type\": \"object\",\n  \"schemaVersion\": 1,\n  \"properties\": {\n    \"profiles\": {\n      \"title\": \"LinkedIn Profile URLs\",\n      \"type\": \"array\",\n      \"description\": \"List of LinkedIn profile URLs (e.g. https://www.linkedin.com/in/username/). The actor fetches each profile to extract name and current company, then derives the most likely work email. Use this OR the 'contacts' field below.\",\n      \"editor\": \"stringList\",\n      \"items\": {\n        \"type\": \"string\",\n        \"minLength\": 1\n      },\n      \"default\": [],\n      \"prefill\": [\n        \"https://www.linkedin.com/in/satyanadella/\"\n      ]\n    },\n    \"contacts\": {\n      \"title\": \"Direct Contacts (skip LinkedIn fetch)\",\n      \"type\": \"array\",\n      \"description\": \"Pre-extracted contacts as objects with firstName, lastName, and either company or domain. These skip the LinkedIn profile fetch entirely (cheaper). With a company name but no domain, add companyLinkedinUrl or companyUrl when you have it: a name shared by several companies is returned unresolved rather than guessed. You may add linkedinUrl: it is only fetched when the name or the company/domain is missing. Example: [{\\\"firstName\\\":\\\"Jane\\\",\\\"lastName\\\":\\\"Doe\\\",\\\"domain\\\":\\\"stripe.com\\\"}].\",\n      \"editor\": \"json\",\n      \"default\": []\n    },\n    \"domainOverride\": {\n      \"title\": \"Domain Override\",\n      \"type\": \"string\",\n      \"description\": \"Force all lookups to use this domain (e.g. 'stripe.com'). Useful when LinkedIn shows a parent brand but you want subsidiary emails.\",\n      \"editor\": \"textfield\",\n      \"default\": \"\"\n    },\n    \"verifyEmails\": {\n      \"title\": \"Verify Emails (mailbox check)\",\n      \"type\": \"boolean\",\n      \"description\": \"Check candidate addresses at the mailbox level, most common pattern first, and stop at the first confirmed mailbox. Up to 6 candidates are checked per person; a catch-all domain stops after one check. Rows report verificationStatus verified, catch_all or unverified. Off by default: without it, the top-ranked pattern is returned unverified.\",\n      \"editor\": \"checkbox\",\n      \"default\": false\n    },\n    \"maxVerificationCredits\": {\n      \"title\": \"Max Mailbox Checks per Run\",\n      \"type\": \"integer\",\n      \"description\": \"Upper bound on mailbox checks one run may perform when 'Verify Emails' is on (each candidate checked counts as one). When reached, remaining contacts are returned with their top pattern, marked unverified. Runs from a free Apify plan are limited to 20 checks.\",\n      \"editor\": \"number\",\n      \"default\": 300,\n      \"minimum\": 0,\n      \"maximum\": 100000\n    },\n    \"maxResults\": {\n      \"title\": \"Max Profiles to Process\",\n      \"type\": \"integer\",\n      \"description\": \"Cap total profiles processed across all inputs.\",\n      \"editor\": \"number\",\n      \"default\": 10,\n      \"prefill\": 10,\n      \"minimum\": 1,\n      \"maximum\": 5000\n    },\n    \"proxyConfiguration\": {\n      \"title\": \"Connection settings\",\n      \"type\": \"object\",\n      \"description\": \"Connection settings for reading LinkedIn pages. The default works for most runs; leave it as is.\",\n      \"editor\": \"proxy\",\n      \"default\": {\n        \"useApifyProxy\": true,\n        \"apifyProxyGroups\": [\n          \"RESIDENTIAL\"\n        ]\n      }\n    }\n  }\n}",
    "readme": "# LinkedIn Email Finder — Profile URL to Email (No Login)\n\n## What you get\n\nGenerate likely work email addresses from LinkedIn profile URLs or name-and-domain pairs. **No login, cookies, or Sales Navigator seat.** Every result includes ranked candidates and an explicit confidence/verification status so an inferred address is never presented as guaranteed.\n\nWorks inside Claude, ChatGPT, and any MCP-compatible agent via the Apify connector. Pairs cleanly with [LinkedIn Employees Scraper](https://apify.com/thirdwatch/linkedin-company-employees-scraper) — run that first to build a target list, then this to fill in emails.\n\n## Two input modes\n\n### Mode 1 (recommended): Direct contacts\nBest for high-volume prospecting. Provide name + domain and the actor skips LinkedIn entirely. Name + company also works; add the company's `companyLinkedinUrl` or website when you have it, because a company name shared by several businesses is returned unresolved rather than guessed. **This is the right path when chaining from [LinkedIn Employees Scraper](https://apify.com/thirdwatch/linkedin-company-employees-scraper)** — that actor outputs name + company already.\n\n```json\n{\n  \"contacts\": [\n    {\"firstName\": \"Jane\", \"lastName\": \"Doe\", \"domain\": \"stripe.com\"},\n    {\"fullName\": \"John Smith\", \"company\": \"Acme Inc\", \"companyUrl\": \"https://acme.com\"}\n  ]\n}\n```\n\n### Mode 2: Profile URLs (best-effort)\nSupply LinkedIn profile URLs. The actor fetches each public profile for name + current employer, then reads the employer's website from its LinkedIn company page. If LinkedIn blocks the profile, or the employer's website can't be confirmed, the lookup comes back with `status: \"unresolved\"` and no email (free, in the no-email dataset) — never a guessed domain. **Use `domainOverride` to guarantee a usable domain** when you already know it.\n\n```json\n{\n  \"profiles\": [\n    \"https://www.linkedin.com/in/jane-doe-12a/\",\n    \"https://www.linkedin.com/in/jsmith-acme/\"\n  ],\n  \"domainOverride\": \"stripe.com\"\n}\n```\n\n## How it works\n\n1. **Extract name + company** — from the candidate's public LinkedIn profile page (no login needed)\n2. **Resolve domain (evidence only)** — the website listed on the person's own employer page on LinkedIn (from their profile, or a `companyLinkedinUrl` you supply). With a company name alone, the domain is used only when LinkedIn lists exactly one company by that name and its website matches the name; names shared by several companies come back unresolved rather than guessed. LinkedIn, social, link-shortener and free-mail hosts are never used as an email domain\n3. **Generate candidates** — 12 common B2B patterns weighted by real-world frequency: `first.last`, `first`, `flast`, `firstlast`, `f.last`, `firstl`, `last`, etc. Credentials (`, MBA`), nicknames and double first names are cleaned first\n4. **Verify (optional)** — with `verifyEmails` on, candidates are checked at the mailbox level in frequency order (up to 6 per person). The search stops at the first confirmed mailbox; a catch-all domain stops after one check; addresses the mail server rejects are never returned\n5. **Rank** — verified > catch_all > pattern\n\n## What you're charged for\n\nOnly rows that come back with an email address (`primaryEmail` is filled) are charged. That covers verified, catch-all, mailbox-full and unverified pattern matches; the `confidence` field tells them apart. Lookups that return no email are free, such as an unavailable profile, an employer whose domain could not be confirmed, a rejected `domainOverride`, or a domain where every candidate was rejected by the mail server.\n\nRows with an email go to the run's default dataset. Lookups without an email go to a separate, unbilled dataset, so you can still see what happened to each contact. If you set a maximum charge for the run, the actor never runs more lookups at once than the remaining budget can pay for, and stops looking up new contacts once the budget is used up.\n\n### Finding lookups without an email\n\nEach run writes a summary to its key-value store under the `OUTPUT` key (the **Run summary** link in the run's Output tab). It contains:\n\n| Field | Meaning |\n|---|---|\n| `emailsFound` | Rows in the default dataset (the billed results) |\n| `noEmail` | Lookups that returned no email (free) |\n| `noEmailDataset.itemsUrl` | API link to the free dataset with those lookups. Append `&token=<your API token>` if your storage is private |\n| `noEmailDataset.consoleUrl` | The same dataset in Apify Console |\n| `notProcessedChargeLimit` | Contacts not looked up because the run's maximum charge was reached |\n| `mailboxVerification` | When `verifyEmails` is on: mailbox checks completed (`creditsUsed`) and failed (`failures`) in this run |\n\nRows in the free dataset have the same fields as the default dataset, with `primaryEmail` empty and the reason in `unresolvedReason` or `confidence`. Through the API, read the `OUTPUT` record from the run's default key-value store, then fetch `noEmailDataset.itemsUrl`.\n\n## Output\n\n| Field | Description |\n|---|---|\n| `fullName` | Person's name |\n| `firstName` / `lastName` | Parsed name parts |\n| `company` | Current employer (from LinkedIn) |\n| `status` | `resolved`, or `unresolved` when no email could be honestly derived |\n| `unresolvedReason` | `profile_unavailable` / `employer_unknown` / `employer_domain_unresolved` / `employer_name_ambiguous` (several companies share the name: add `domain` or `companyLinkedinUrl`) / `name_missing` / `invalid_domain_override` |\n| `domain` | Employer email domain (empty when unresolved) |\n| `domainSource` / `domainEvidence` | Where the domain came from (`input`, `override`, `linkedin_company_page`, `company_name` when the company name is itself a domain such as `ujet.cx`) and the URL that backs it |\n| `primaryEmail` | Best-guess email. Always filled in the default dataset; empty in the free no-email dataset |\n| `candidates` | All weighted candidates `[{email, weight}]` |\n| `verificationStatus` | `verified` / `catch_all` / `unverified` when `verifyEmails` is on; `skipped` when it is off |\n| `verificationBackend` | Which check produced the status: `mailbox_api` (mailbox-level verification), `smtp` (basic mail-server check, used when mailbox verification is unavailable) or `none` |\n| `verificationDetail` | Why: e.g. `mailbox_safe` (mailbox confirmed), `mailbox_catch_all` (domain accepts every address), `mailbox_inconclusive` (mail server gave no definite answer), `mailbox_inbox_full`, `mailbox_check_failed` (the mailbox check could not complete), `no_candidate_verified`, `no_mx`, `credit_budget_exhausted` |\n| `verificationAttempts` | Each candidate checked and its mailbox result `[{email, status, score}]` |\n| `confidence` | `verified` / `catch_all` / `pattern` / `pattern_unverified` / `pattern_no_mx` / `mailbox_full` (mailbox exists but is full, so not deliverable today) / `all_candidates_rejected` / `unresolved` |\n| `verifiedEmails` | Emails confirmed at the mailbox level |\n| `mxHosts` | Mail servers found via DNS |\n| `catchAll` | Whether the domain accepts all addresses |\n| `profileUrl` | Original LinkedIn URL |\n\n## Verification reality check\n\nWith `verifyEmails` on, each candidate is checked at the mailbox level, without sending any email. A `verified` row means the mail server confirmed that exact mailbox.\n\n- **Catch-all domains** accept every address, so no single mailbox can be confirmed. The row returns the most likely pattern with `verificationStatus: catch_all`.\n- **Inconclusive servers** (greylisting, providers that hide mailbox validity) return `unverified` with the best remaining pattern.\n- If mailbox verification is temporarily unavailable, the affected rows are marked `unverified` with their best pattern rather than failing the run.\n\nUnverified pattern matches are right roughly 60-70% of the time on real B2B domains. Bounce-test them before mass sending.\n\n## Compared to alternatives\n\n| Tool | Cost | Login required | Verification |\n|---|---|---|---|\n| This actor | Pay per email found; lookups without an email are free | No | MX + optional mailbox verification |\n| Hunter.io | $0.049/search | API key | Yes |\n| Apollo | $99/mo seat | Account | Yes |\n| Snov | $0.027/credit | API key | Yes |\n\n## Tips\n\n1. **Pair with LinkedIn Employees Scraper** — run it first for prospect lists, then feed profile URLs here.\n2. **Use `domainOverride`** when LinkedIn shows a parent brand but you want subsidiary emails.\n3. **Enable `verifyEmails`** when you need confirmed mailboxes. `maxVerificationCredits` caps the number of mailbox checks per run.\n4. **Always bounce-test before mass sending** — pattern matches without mailbox verification still bounce 30–40% of the time.\n\n## Input parameters\n\n| Parameter | Required | Description |\n|---|---:|---|\n| `profiles` | No | List of LinkedIn profile URLs (e.g. https://www.linkedin.com/in/username/). The actor fetches each profile to extract name and current company, then derives the most likely work email. Use this OR the 'contacts' field below. |\n| `contacts` | No | Pre-extracted contacts as objects with firstName, lastName, and either company or domain. These skip the LinkedIn profile fetch entirely (cheaper). You may add linkedinUrl: it is only fetched when the name or the company/domain is missing. Example: [{\"firstName\":\"Jane\",\"lastName\":\"Doe\",\"domain\":\"stripe.com\"}]. |\n| `domainOverride` | No | Force all lookups to use this domain (e.g. 'stripe.com'). Useful when LinkedIn shows a parent brand but you want subsidiary emails. |\n| `verifyEmails` | No | Check candidates at the mailbox level, most common pattern first, stopping at the first confirmed mailbox (up to 6 per person). |\n| `maxVerificationCredits` | No | Upper bound on mailbox checks per run (default 300). Runs from a free Apify plan are limited to 20. |\n| `maxResults` | No | Cap total profiles processed across all inputs. |\n| `proxyConfiguration` | No | Connection settings for reading LinkedIn pages. The default works for most runs; leave it as is. |\n\n## Use cases\n\n- Sales teams building outreach lists\n- Agencies sourcing local-business leads\n- RevOps teams enriching CRM records\n\n## Limitations\n\n- **The more you provide, the better the match.** A company domain or LinkedIn company URL gives the most reliable results. If a company name matches several businesses (for example, several companies called \"Foxglove\"), the lookup returns no email rather than guessing. It comes back free, with `unresolvedReason: employer_name_ambiguous`.\n- **Some companies accept mail for every address (catch-all).** For these, the most likely address is returned with `verificationStatus: catch_all`, because no mail server can confirm an individual mailbox.\n- **LinkedIn profiles that require sign-in can't be read.** For those people, supply the name and company or domain directly.\n- **Lookups without an email are free.** They are stored in a separate dataset with the reason in `unresolvedReason` or `confidence` (see **Finding lookups without an email**).\n\nLast verified: 2026-10\n\nMore scrapers at [thirdwatch.dev](https://thirdwatch.dev).\n",
    "actorDefinition": {
      "$schema": "https://apify.com/schemas/v1/actor.ide.json",
      "actorSpecification": 1,
      "name": "linkedin-email-finder-scraper",
      "title": "LinkedIn Email Finder - Work Emails, No Login",
      "description": "Generate likely work emails from LinkedIn URLs or name-and-domain contacts. Get ranked candidates, MX status, catch-all detection, and optional mailbox verification.",
      "version": "1.0",
      "buildTag": "latest",
      "input": {
        "title": "LinkedIn Email Finder Input",
        "type": "object",
        "schemaVersion": 1,
        "properties": {
          "profiles": {
            "title": "LinkedIn Profile URLs",
            "type": "array",
            "description": "List of LinkedIn profile URLs (e.g. https://www.linkedin.com/in/username/). The actor fetches each profile to extract name and current company, then derives the most likely work email. Use this OR the 'contacts' field below.",
            "editor": "stringList",
            "items": {
              "type": "string",
              "minLength": 1
            },
            "default": [],
            "prefill": [
              "https://www.linkedin.com/in/satyanadella/"
            ]
          },
          "contacts": {
            "title": "Direct Contacts (skip LinkedIn fetch)",
            "type": "array",
            "description": "Pre-extracted contacts as objects with firstName, lastName, and either company or domain. These skip the LinkedIn profile fetch entirely (cheaper). With a company name but no domain, add companyLinkedinUrl or companyUrl when you have it: a name shared by several companies is returned unresolved rather than guessed. You may add linkedinUrl: it is only fetched when the name or the company/domain is missing. Example: [{\"firstName\":\"Jane\",\"lastName\":\"Doe\",\"domain\":\"stripe.com\"}].",
            "editor": "json",
            "default": []
          },
          "domainOverride": {
            "title": "Domain Override",
            "type": "string",
            "description": "Force all lookups to use this domain (e.g. 'stripe.com'). Useful when LinkedIn shows a parent brand but you want subsidiary emails.",
            "editor": "textfield",
            "default": ""
          },
          "verifyEmails": {
            "title": "Verify Emails (mailbox check)",
            "type": "boolean",
            "description": "Check candidate addresses at the mailbox level, most common pattern first, and stop at the first confirmed mailbox. Up to 6 candidates are checked per person; a catch-all domain stops after one check. Rows report verificationStatus verified, catch_all or unverified. Off by default: without it, the top-ranked pattern is returned unverified.",
            "editor": "checkbox",
            "default": false
          },
          "maxVerificationCredits": {
            "title": "Max Mailbox Checks per Run",
            "type": "integer",
            "description": "Upper bound on mailbox checks one run may perform when 'Verify Emails' is on (each candidate checked counts as one). When reached, remaining contacts are returned with their top pattern, marked unverified. Runs from a free Apify plan are limited to 20 checks.",
            "editor": "number",
            "default": 300,
            "minimum": 0,
            "maximum": 100000
          },
          "maxResults": {
            "title": "Max Profiles to Process",
            "type": "integer",
            "description": "Cap total profiles processed across all inputs.",
            "editor": "number",
            "default": 10,
            "prefill": 10,
            "minimum": 1,
            "maximum": 5000
          },
          "proxyConfiguration": {
            "title": "Connection settings",
            "type": "object",
            "description": "Connection settings for reading LinkedIn pages. The default works for most runs; leave it as is.",
            "editor": "proxy",
            "default": {
              "useApifyProxy": true,
              "apifyProxyGroups": [
                "RESIDENTIAL"
              ]
            }
          }
        }
      },
      "dockerfile": "../Dockerfile",
      "readme": "# LinkedIn Email Finder — Profile URL to Email (No Login)\n\n## What you get\n\nGenerate likely work email addresses from LinkedIn profile URLs or name-and-domain pairs. **No login, cookies, or Sales Navigator seat.** Every result includes ranked candidates and an explicit confidence/verification status so an inferred address is never presented as guaranteed.\n\nWorks inside Claude, ChatGPT, and any MCP-compatible agent via the Apify connector. Pairs cleanly with [LinkedIn Employees Scraper](https://apify.com/thirdwatch/linkedin-company-employees-scraper) — run that first to build a target list, then this to fill in emails.\n\n## Two input modes\n\n### Mode 1 (recommended): Direct contacts\nBest for high-volume prospecting. Provide name + domain and the actor skips LinkedIn entirely. Name + company also works; add the company's `companyLinkedinUrl` or website when you have it, because a company name shared by several businesses is returned unresolved rather than guessed. **This is the right path when chaining from [LinkedIn Employees Scraper](https://apify.com/thirdwatch/linkedin-company-employees-scraper)** — that actor outputs name + company already.\n\n```json\n{\n  \"contacts\": [\n    {\"firstName\": \"Jane\", \"lastName\": \"Doe\", \"domain\": \"stripe.com\"},\n    {\"fullName\": \"John Smith\", \"company\": \"Acme Inc\", \"companyUrl\": \"https://acme.com\"}\n  ]\n}\n```\n\n### Mode 2: Profile URLs (best-effort)\nSupply LinkedIn profile URLs. The actor fetches each public profile for name + current employer, then reads the employer's website from its LinkedIn company page. If LinkedIn blocks the profile, or the employer's website can't be confirmed, the lookup comes back with `status: \"unresolved\"` and no email (free, in the no-email dataset) — never a guessed domain. **Use `domainOverride` to guarantee a usable domain** when you already know it.\n\n```json\n{\n  \"profiles\": [\n    \"https://www.linkedin.com/in/jane-doe-12a/\",\n    \"https://www.linkedin.com/in/jsmith-acme/\"\n  ],\n  \"domainOverride\": \"stripe.com\"\n}\n```\n\n## How it works\n\n1. **Extract name + company** — from the candidate's public LinkedIn profile page (no login needed)\n2. **Resolve domain (evidence only)** — the website listed on the person's own employer page on LinkedIn (from their profile, or a `companyLinkedinUrl` you supply). With a company name alone, the domain is used only when LinkedIn lists exactly one company by that name and its website matches the name; names shared by several companies come back unresolved rather than guessed. LinkedIn, social, link-shortener and free-mail hosts are never used as an email domain\n3. **Generate candidates** — 12 common B2B patterns weighted by real-world frequency: `first.last`, `first`, `flast`, `firstlast`, `f.last`, `firstl`, `last`, etc. Credentials (`, MBA`), nicknames and double first names are cleaned first\n4. **Verify (optional)** — with `verifyEmails` on, candidates are checked at the mailbox level in frequency order (up to 6 per person). The search stops at the first confirmed mailbox; a catch-all domain stops after one check; addresses the mail server rejects are never returned\n5. **Rank** — verified > catch_all > pattern\n\n## What you're charged for\n\nOnly rows that come back with an email address (`primaryEmail` is filled) are charged. That covers verified, catch-all, mailbox-full and unverified pattern matches; the `confidence` field tells them apart. Lookups that return no email are free, such as an unavailable profile, an employer whose domain could not be confirmed, a rejected `domainOverride`, or a domain where every candidate was rejected by the mail server.\n\nRows with an email go to the run's default dataset. Lookups without an email go to a separate, unbilled dataset, so you can still see what happened to each contact. If you set a maximum charge for the run, the actor never runs more lookups at once than the remaining budget can pay for, and stops looking up new contacts once the budget is used up.\n\n### Finding lookups without an email\n\nEach run writes a summary to its key-value store under the `OUTPUT` key (the **Run summary** link in the run's Output tab). It contains:\n\n| Field | Meaning |\n|---|---|\n| `emailsFound` | Rows in the default dataset (the billed results) |\n| `noEmail` | Lookups that returned no email (free) |\n| `noEmailDataset.itemsUrl` | API link to the free dataset with those lookups. Append `&token=<your API token>` if your storage is private |\n| `noEmailDataset.consoleUrl` | The same dataset in Apify Console |\n| `notProcessedChargeLimit` | Contacts not looked up because the run's maximum charge was reached |\n| `mailboxVerification` | When `verifyEmails` is on: mailbox checks completed (`creditsUsed`) and failed (`failures`) in this run |\n\nRows in the free dataset have the same fields as the default dataset, with `primaryEmail` empty and the reason in `unresolvedReason` or `confidence`. Through the API, read the `OUTPUT` record from the run's default key-value store, then fetch `noEmailDataset.itemsUrl`.\n\n## Output\n\n| Field | Description |\n|---|---|\n| `fullName` | Person's name |\n| `firstName` / `lastName` | Parsed name parts |\n| `company` | Current employer (from LinkedIn) |\n| `status` | `resolved`, or `unresolved` when no email could be honestly derived |\n| `unresolvedReason` | `profile_unavailable` / `employer_unknown` / `employer_domain_unresolved` / `employer_name_ambiguous` (several companies share the name: add `domain` or `companyLinkedinUrl`) / `name_missing` / `invalid_domain_override` |\n| `domain` | Employer email domain (empty when unresolved) |\n| `domainSource` / `domainEvidence` | Where the domain came from (`input`, `override`, `linkedin_company_page`, `company_name` when the company name is itself a domain such as `ujet.cx`) and the URL that backs it |\n| `primaryEmail` | Best-guess email. Always filled in the default dataset; empty in the free no-email dataset |\n| `candidates` | All weighted candidates `[{email, weight}]` |\n| `verificationStatus` | `verified` / `catch_all` / `unverified` when `verifyEmails` is on; `skipped` when it is off |\n| `verificationBackend` | Which check produced the status: `mailbox_api` (mailbox-level verification), `smtp` (basic mail-server check, used when mailbox verification is unavailable) or `none` |\n| `verificationDetail` | Why: e.g. `mailbox_safe` (mailbox confirmed), `mailbox_catch_all` (domain accepts every address), `mailbox_inconclusive` (mail server gave no definite answer), `mailbox_inbox_full`, `mailbox_check_failed` (the mailbox check could not complete), `no_candidate_verified`, `no_mx`, `credit_budget_exhausted` |\n| `verificationAttempts` | Each candidate checked and its mailbox result `[{email, status, score}]` |\n| `confidence` | `verified` / `catch_all` / `pattern` / `pattern_unverified` / `pattern_no_mx` / `mailbox_full` (mailbox exists but is full, so not deliverable today) / `all_candidates_rejected` / `unresolved` |\n| `verifiedEmails` | Emails confirmed at the mailbox level |\n| `mxHosts` | Mail servers found via DNS |\n| `catchAll` | Whether the domain accepts all addresses |\n| `profileUrl` | Original LinkedIn URL |\n\n## Verification reality check\n\nWith `verifyEmails` on, each candidate is checked at the mailbox level, without sending any email. A `verified` row means the mail server confirmed that exact mailbox.\n\n- **Catch-all domains** accept every address, so no single mailbox can be confirmed. The row returns the most likely pattern with `verificationStatus: catch_all`.\n- **Inconclusive servers** (greylisting, providers that hide mailbox validity) return `unverified` with the best remaining pattern.\n- If mailbox verification is temporarily unavailable, the affected rows are marked `unverified` with their best pattern rather than failing the run.\n\nUnverified pattern matches are right roughly 60-70% of the time on real B2B domains. Bounce-test them before mass sending.\n\n## Compared to alternatives\n\n| Tool | Cost | Login required | Verification |\n|---|---|---|---|\n| This actor | Pay per email found; lookups without an email are free | No | MX + optional mailbox verification |\n| Hunter.io | $0.049/search | API key | Yes |\n| Apollo | $99/mo seat | Account | Yes |\n| Snov | $0.027/credit | API key | Yes |\n\n## Tips\n\n1. **Pair with LinkedIn Employees Scraper** — run it first for prospect lists, then feed profile URLs here.\n2. **Use `domainOverride`** when LinkedIn shows a parent brand but you want subsidiary emails.\n3. **Enable `verifyEmails`** when you need confirmed mailboxes. `maxVerificationCredits` caps the number of mailbox checks per run.\n4. **Always bounce-test before mass sending** — pattern matches without mailbox verification still bounce 30–40% of the time.\n\n## Input parameters\n\n| Parameter | Required | Description |\n|---|---:|---|\n| `profiles` | No | List of LinkedIn profile URLs (e.g. https://www.linkedin.com/in/username/). The actor fetches each profile to extract name and current company, then derives the most likely work email. Use this OR the 'contacts' field below. |\n| `contacts` | No | Pre-extracted contacts as objects with firstName, lastName, and either company or domain. These skip the LinkedIn profile fetch entirely (cheaper). You may add linkedinUrl: it is only fetched when the name or the company/domain is missing. Example: [{\"firstName\":\"Jane\",\"lastName\":\"Doe\",\"domain\":\"stripe.com\"}]. |\n| `domainOverride` | No | Force all lookups to use this domain (e.g. 'stripe.com'). Useful when LinkedIn shows a parent brand but you want subsidiary emails. |\n| `verifyEmails` | No | Check candidates at the mailbox level, most common pattern first, stopping at the first confirmed mailbox (up to 6 per person). |\n| `maxVerificationCredits` | No | Upper bound on mailbox checks per run (default 300). Runs from a free Apify plan are limited to 20. |\n| `maxResults` | No | Cap total profiles processed across all inputs. |\n| `proxyConfiguration` | No | Connection settings for reading LinkedIn pages. The default works for most runs; leave it as is. |\n\n## Use cases\n\n- Sales teams building outreach lists\n- Agencies sourcing local-business leads\n- RevOps teams enriching CRM records\n\n## Limitations\n\n- **The more you provide, the better the match.** A company domain or LinkedIn company URL gives the most reliable results. If a company name matches several businesses (for example, several companies called \"Foxglove\"), the lookup returns no email rather than guessing. It comes back free, with `unresolvedReason: employer_name_ambiguous`.\n- **Some companies accept mail for every address (catch-all).** For these, the most likely address is returned with `verificationStatus: catch_all`, because no mail server can confirm an individual mailbox.\n- **LinkedIn profiles that require sign-in can't be read.** For those people, supply the name and company or domain directly.\n- **Lookups without an email are free.** They are stored in a separate dataset with the reason in `unresolvedReason` or `confidence` (see **Finding lookups without an email**).\n\nLast verified: 2026-10\n\nMore scrapers at [thirdwatch.dev](https://thirdwatch.dev).\n",
      "storages": {
        "dataset": {
          "actorSpecification": 1,
          "fields": {},
          "views": {
            "overview": {
              "title": "Email Lookups",
              "transformation": {
                "fields": [
                  "fullName",
                  "company",
                  "domain",
                  "domainSource",
                  "primaryEmail",
                  "status",
                  "verificationStatus",
                  "verificationBackend",
                  "confidence",
                  "profileUrl"
                ]
              },
              "display": {
                "component": "table",
                "properties": {
                  "fullName": {
                    "label": "Name",
                    "format": "text"
                  },
                  "company": {
                    "label": "Company",
                    "format": "text"
                  },
                  "domain": {
                    "label": "Domain",
                    "format": "text"
                  },
                  "primaryEmail": {
                    "label": "Email",
                    "format": "text"
                  },
                  "verificationStatus": {
                    "label": "Status",
                    "format": "text"
                  },
                  "confidence": {
                    "label": "Confidence",
                    "format": "text"
                  },
                  "profileUrl": {
                    "label": "Profile",
                    "format": "link"
                  },
                  "domainSource": {
                    "label": "Domain source",
                    "format": "text"
                  },
                  "status": {
                    "label": "Lookup",
                    "format": "text"
                  },
                  "verificationBackend": {
                    "label": "Verified via",
                    "format": "text"
                  }
                }
              }
            }
          }
        }
      },
      "maxMemoryMbytes": 512,
      "defaultRunOptions": {
        "build": "latest",
        "memoryMbytes": 256,
        "timeoutSecs": 1800
      },
      "pricingModel": {
        "pricingType": "PAY_PER_EVENT",
        "pricePerEvent": 0.002,
        "events": {
          "apify-actor-start": {
            "displayName": "Actor start",
            "description": "Apify's fixed per-run start fee (one event per GB of memory, minimum one).",
            "priceUsd": 0.00005,
            "isCharged": true
          },
          "apify-default-dataset-item": {
            "displayName": "Email found",
            "description": "Charged once per row in the default dataset. Only rows with an email are written there; lookups without an email go to a separate free dataset and are not charged.",
            "priceUsd": 0.002,
            "isCharged": true,
            "pricingTiers": [
              {
                "tierName": "FREE",
                "priceUsd": 0.02
              },
              {
                "tierName": "BRONZE",
                "priceUsd": 0.0019
              },
              {
                "tierName": "SILVER",
                "priceUsd": 0.0018
              },
              {
                "tierName": "GOLD",
                "priceUsd": 0.0016
              }
            ]
          }
        }
      },
      "output": {
        "actorOutputSchemaVersion": 1,
        "title": "LinkedIn Email Finder Results",
        "properties": {
          "results": {
            "type": "string",
            "title": "Emails found",
            "description": "One row per contact with an email address. These are the billed results.",
            "template": "{{links.apiDefaultDatasetUrl}}/items"
          },
          "summary": {
            "type": "string",
            "title": "Run summary and lookups without an email",
            "description": "Counts for the run plus noEmailDataset.itemsUrl, a free dataset listing every lookup that returned no email and why.",
            "template": "{{links.apiDefaultKeyValueStoreUrl}}/records/OUTPUT"
          }
        }
      },
      "categories": [
        "LEAD_GENERATION",
        "SOCIAL_MEDIA"
      ]
    },
    "buildNumber": "1.0.23",
    "imageDigest": "f70034ce275bb0054aca21b9b17061e2e22d16e3638d44099ee7ca415bee5480",
    "actVersion": {
      "sourceType": "SOURCE_FILES",
      "buildTag": "latest",
      "versionNumber": "1.0"
    },
    "usage": {
      "ACTOR_COMPUTE_UNITS": 0.02203
    }
  }
}