# Bulk Company Email Lookup Scraper (`automation-lab/company-name-contact-resolver`) Actor

Resolve company names to likely official websites and displayed general emails or observed contact forms. Export one evidence-attributed row per company with explicit ambiguity and incomplete states.

- **URL**: https://apify.com/automation-lab/company-name-contact-resolver.md
- **Developed by:** [Automation Lab](https://apify.com/automation-lab) (community)
- **Categories:** Lead generation
- **Stats:** 2 total users, 1 monthly users, 92.3% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.82 / 1,000 company lookup completeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

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

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

## How to integrate an Actor?

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

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

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

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

# README

## Bulk Company Email Lookup Scraper

Turn company-name spreadsheets into source-attributed general contact channels. This **bulk company email lookup** Actor searches for likely official domains, reads public website pages, and returns a preferred displayed shared inbox or an observed contact-form page.

It does not guess personal emails, send invitations, verify mailbox deliverability, or promise complete web coverage.

### What does it do?

For each supplied company, the Actor searches public Brave Search result HTML directly, requires full name-token coverage and a matching hostname token, then checks the strongest candidate's homepage and observed contact/about links. Close-scoring domains remain ambiguous rather than being silently selected.

If you already know the website, supply it alongside the name to bypass search. That website is your supplied identity, not an independently certified official domain.

### Who is it for?

- Sales operations teams refreshing company-name spreadsheets.
- Researchers documenting public business contact evidence.
- CRM administrators separating confident contact results from review-needed matches.
- Agencies enriching client-authorized account lists.

### Why use this Actor?

One input produces one ordered result row, including unresolved companies. The result includes the precise page where an inbox or form was observed. Negative results remain distinct from failed requests, and no person-specific email patterns are generated.

### Getting started

1. Open the Actor and add company objects to `companies`.
2. Include an optional `country` hint for name searches.
3. Add `website` when the domain is already known.
4. Choose `maxPagesPerCompany` from 1 to 10.
5. Start the run and review `status` before exporting contacts.

```json
{
  "companies": [{ "name": "Apify", "website": "https://apify.com" }],
  "maxPagesPerCompany": 4
}
```

The prefilled example uses a known public website so your first run does not depend on search availability. Remove `website` to try name discovery; public search can block requests or change its response, producing an explicit uncharged `error` rather than a claim that no contact exists. A successful supplied-site run does not verify name-search availability.

### Input parameters

| Field | Behavior |
| --- | --- |
| `companies` | 1–1000 objects with nonempty `name`, optional `country`, and optional `website`. Input order and duplicate rows are preserved. |
| `country` | Appended to search text; not an independently verified geography filter. |
| `website` | Public HTTP(S) URL or domain; bypasses search and supplies the identity to inspect. |
| `maxPagesPerCompany` | Maximum website-page attempts for each company, including homepage; default 4, range 1–10. Search requests do not count toward this limit. |

Zero/unlimited page limits are unsupported. The run timeout and your billing budget may stop a large batch before every row is processed; completed rows remain partial results, not a completed batch.

### Output fields

| Field | Meaning |
| --- | --- |
| `companyName`, `country` | Original trimmed name and supplied hint. |
| `status` | Contact, ambiguity, absence, or failure disposition. |
| `contactValue` | Preferred email, observed form-page URL, or `not available` placeholder. Always interpret with status. |
| `email` | Displayed eligible role inbox, otherwise null. |
| `contactFormUrl` | Observed form page if no eligible inbox was found. |
| `sourceUrl` | Exact fetched contact evidence page. |
| `website` | Selected likely domain or supplied website. |
| `candidates` | Up to five domain candidates with heuristic scores and search evidence. |
| `pagesChecked` | Successfully retrieved evidence pages. |
| `diagnostics` | Bounded failure stage and safe response category (HTTP status, challenge, non-HTML, oversized/unrecognized response, redirects, or network/safety failure); no response bodies or request secrets. |
| `checkedAt` | UTC lookup timestamp. |

### Example result

A local lookup of Apify returned the following contact fields:

```json
{
  "companyName": "Apify",
  "country": null,
  "status": "email_found",
  "contactValue": "hello@apify.com",
  "email": "hello@apify.com",
  "contactFormUrl": null,
  "sourceUrl": "https://apify.com/contact",
  "website": "https://apify.com/"
}
```

The full row also includes candidates, checked pages, diagnostics, and the lookup timestamp. Results depend on what the source displays at run time.

### Contact selection rules

Eligible role prefixes include info, hello, contact, enquiries, inquiry, office, sales, support, admin, reception, and team. The Actor favors general inboxes over sales/support; addresses must be displayed in text or a mailto link and use the selected website hostname. Personal addresses and off-domain addresses are not selected.

A form requires an observed HTML form with an email input, message textarea, and positive contact/enquiry purpose in the form or its nearby heading. Order, newsletter, comment, review, survey and registration forms are excluded even on contact pages. A contact link alone is not proof of a form. Forms are never submitted. Purpose matching is conservative and English-language; unlabelled, JavaScript-only and external-hosted forms may be missed.

### Understanding dispositions

- `email_found`: eligible displayed general inbox selected.
- `contact_form_found`: observed contact/enquiry email-message form, no eligible inbox in checked pages.
- `not_available`: no eligible inbox or form found in successfully checked bounded pages.
- `ambiguous`: competing domain candidates are too close to choose safely.
- `unresolved`: no candidate passes conservative name/hostname checks.
- `incomplete`: one or more pages failed and no contact was found.
- `error`: name search or lookup failed.

`not_available` does not mean there is no email anywhere on the Internet. The contact placeholder on ambiguity or failure is not an absence verdict; use status. Heuristic scores are not identity probabilities.

### How much does it cost to look up company contacts?

Pay-per-event pricing has a one-time start event and a company-result event. The Actor's pricing panel shows the applicable current rates for your plan. Failed/incomplete diagnostic rows have no item event. Ambiguous, unresolved, and checked-not-available dispositions are completed research results and have an item event.

Estimate a run as one start charge plus the applicable company-result rate multiplied by completed results. This is an estimate, not a guaranteed invoice; refunds, fraud, disputes, taxes, corrections or clawbacks may affect charges or publisher payouts. Store discount tiers follow qualifying aggregate monthly Store spend, not volume within this Actor alone. Direct search and page requests are included in our event price; you need no external API key. There is no paid proxy, residential, managed-search or browser fallback.

### Limits and troubleshooting

The Actor processes companies sequentially with bounded requests and transient retries. It follows only observed same-host contact/about links and refuses non-global network destinations, credentials in URLs, and cross-domain website redirects. Each HTTP connection validates all DNS answers and connects using the validated resolution; redirects are checked again. Special, multicast, reserved and mixed public/non-global answers are rejected. It does not use a browser, log in, or attempt to solve website challenges.

Large batches may exceed the configured run timeout. Increase the timeout or split inputs; missing rows from interrupted runs are not not-available findings.

If a domain is ambiguous, provide the website after manual verification. If results are incomplete, review diagnostics and retry later or provide a reachable public page. Increasing the page limit follows more observed links but cannot make JavaScript-only contacts visible.

### Integrations

Export the default dataset as JSON, CSV, Excel, XML, or RSS through Apify. Join results to your original spreadsheet by row order and company name. Keep evidence URLs in a review column and filter to contact-found statuses before using contact values.

Use Make, Zapier, webhooks, or the Apify API to send completed data to your CRM or warehouse. Scheduled runs create fresh snapshots; this Actor does not compare runs or send change alerts itself.

### API usage

Use your own Apify token, never a third-party enrichment credential.

```bash
curl -X POST 'https://api.apify.com/v2/acts/automation-lab~company-name-contact-resolver/runs' \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"companies":[{"name":"Apify"}]}'
```

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/company-name-contact-resolver')
  .call({ companies: [{ name: 'Apify' }] });
const { items } = await client.dataset(run.defaultDatasetId).listItems({ limit: 20 });
```

```python
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/company-name-contact-resolver').call(
    run_input={'companies': [{'name': 'Apify'}]})
items = client.dataset(run['defaultDatasetId']).list_items(limit=20).items
```

### MCP setup

For Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/company-name-contact-resolver"
```

For Claude Desktop, Cursor, and VS Code, use the equivalent HTTP server configuration supported by your client:

```json
{"mcpServers":{"apify":{"type":"http","url":"https://mcp.apify.com?tools=automation-lab/company-name-contact-resolver"}}}
```

Example prompt: “Look up Apify's public general contact and include its source page; flag ambiguous results for review.” Authorize execution separately from read-only tool discovery.

Discover actual tool names and schemas with `tools/list`. Actor selection also exposes run/storage helper tools. Start once and retain the returned run ID; it is metadata, not contact data. If nonterminal, check that same run with bounded 2/4/8-second backoff, capped at 10 seconds, and a 120-second total deadline. Set the client request timeout above the selected server wait plus transport margin. A client timeout is not a reason to restart the Actor.

After success, fetch untransformed dataset JSON in pages of 20, at most 100 source rows and 64 KiB of serialized content admitted to model context, whichever occurs first. Enforce byte limits host-side; if the client cannot do that, do not claim a hard byte guarantee. Report partial results and continuation offset. Keep full exports outside model context. At a deadline report pending with its run ID; terminal failures are failures and any rows are partial.

### Legality, responsible use and privacy

Use public business channels only for lawful, authorized research. A published address is not consent to unsolicited marketing. Respect applicable privacy, anti-spam, and source-access rules. No custom end-user terms are added; Apify's standard terms apply. This independent utility is not affiliated with Brave or any company searched.

No AI model is used during lookup or to generate contact results. Names and country hints are sent to Brave Search's public search service. Known websites and bounded linked pages are fetched directly. Results and input are stored in your Apify run storage according to your account's retention/deletion settings; delete runs and datasets when no longer needed. There is no cross-run cache or persistent browser session.

Failed operations send sanitized diagnostic input, exceptions and actor/build/run IDs to our private GlitchTip service for repair. Secret fields and URL queries are removed; reports are retained for 30 days. Routine logs contain status/counts, not email addresses or raw pages. Role inboxes are business contact data and should still be handled responsibly.

### FAQ

**Are emails verified?** No. These are displayed general inboxes, not SMTP or MX verification results.

**Can I supply websites?** Yes, as company objects with `name` and `website`; search is bypassed.

**Why no contact for a known company?** Contacts may be JavaScript-only, obfuscated, off-domain, or outside the checked links. The disposition explains whether the check completed.

**Can I monitor changes?** Schedule runs and compare snapshots in your own pipeline; no built-in comparison or alert delivery is included.

**Where can I get help?** Open an issue on this Actor's Apify Issues tab with a safe input and run link. Do not include secrets.

### Related Actors

- [Company Domain Finder](https://apify.com/automation-lab/company-domain-finder) for domain-only name resolution.
- [Website Contact Finder](https://apify.com/automation-lab/website-contact-finder) for broader contact extraction from known sites.
- [Bulk Email MX Verifier](https://apify.com/automation-lab/email-mx-verifier) for a separate mail-domain check after extraction.

# Changelog

This Actor's version history is a separate document: https://apify.com/automation-lab/company-name-contact-resolver/changelog.md

# Actor input Schema

## `companies` (type: `array`):

1–1000 company objects with name, optional country search hint and optional website. Website bypasses search and is treated as your supplied identity, not independently verified. Rows retain input order and duplicates. Only publicly reachable HTTP(S) websites are accepted.

## `maxPagesPerCompany` (type: `integer`):

Maximum attempted website pages per company, including the homepage. Default 4; range 1–10. Follows only observed same-host contact/about links. Search requests are separate. Zero and unlimited are unsupported; this does not promise exhaustive website coverage.

## Actor input object example

```json
{
  "companies": [
    {
      "name": "Apify",
      "website": "https://apify.com"
    }
  ],
  "maxPagesPerCompany": 4
}
```

# Actor output Schema

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

Default dataset with contact value, source page, candidates and lookup status.

# API

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

## JavaScript example

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

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

// Prepare Actor input
const input = {
    "companies": [
        {
            "name": "Apify",
            "website": "https://apify.com"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/company-name-contact-resolver").call(input);

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

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

```

## Python example

```python
from apify_client import ApifyClient

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

# Prepare the Actor input
run_input = { "companies": [{
            "name": "Apify",
            "website": "https://apify.com",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/company-name-contact-resolver").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "companies": [
    {
      "name": "Apify",
      "website": "https://apify.com"
    }
  ]
}' |
apify call automation-lab/company-name-contact-resolver --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/company-name-contact-resolver"
        }
    }
}
```

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

## OpenAPI specification

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