CSV & Excel Business Contact Enricher avatar

CSV & Excel Business Contact Enricher

Pricing

from $7.56 / 1,000 enriched companies

Go to Apify Store
CSV & Excel Business Contact Enricher

CSV & Excel Business Contact Enricher

Enrich CSV and Excel company lists with published emails, phone numbers and source evidence. Preserve original cells, export XLSX/CSV, and resume unfinished work with a job name.

Pricing

from $7.56 / 1,000 enriched companies

Rating

0.0

(0)

Developer

Inus Grobler

Inus Grobler

Maintained by Community

Actor stats

0

Bookmarked

10

Total users

3

Monthly active users

9 days ago

Last modified

Share

Business Spreadsheet Enricher: Emails, Phones & Websites

Turn a CSV or Excel company list into an evidence-backed business contact dataset. This business data enrichment and company contact scraper finds official websites, then collects public emails, phone numbers, named contacts, addresses, company descriptions, published industries, and social profiles.

No contact database, enrichment provider, search API, subscription, or generated email pattern is used. Every collected value comes directly from a public company website and includes source URLs.

Quick start

  1. Open the Input tab.
  2. Upload a CSV/XLSX file, or enter a few companies manually.
  3. Click Start.
  4. Download ENRICHED.xlsx or ENRICHED.csv from the Output tab.

For the fastest and most accurate results, include a website column. If you only have company names, add city and country where possible to improve matching.

What you can do

  • Complete missing fields in CRM and prospecting spreadsheets.
  • Verify company websites before outreach.
  • Collect public sales, support, careers, press, and staff contact routes.
  • Preserve the original rows while appending enrichment columns.
  • Download the completed file as XLSX or CSV.
  • Review confidence scores and source evidence before importing results.

Use cases

  • CRM cleanup: append official domains and published contact routes before account assignment.
  • Sales operations: enrich conference, partner, and target-account spreadsheets in bulk.
  • Lead research: collect evidence-linked public company details without buying an enrichment API subscription.
  • Market mapping: standardize company websites, locations, industries, and social profiles for analysis.
  • Data quality review: separate verified, ambiguous, unavailable, and blocked rows before import.

Input

Choose one input method:

  1. Upload a .csv or .xlsx file in Upload a CSV or Excel file.
  2. Enter a short JSON list in Or enter companies manually.

Each row must contain either a company name or a website. Company name, city, region, country, company number, and website columns are detected automatically. Use Column mapping when your spreadsheet uses custom headers.

The simplest spreadsheet looks like this:

companyName,website,city,country
Apify,https://apify.com,Prague,CZ
Mozilla,https://www.mozilla.org,,US

Important settings:

SettingWhat it doesDefault
Business details to collectSelect emails, phones, contacts, address, description, industry, and social profiles.All details
Companies to processLimits the number of spreadsheet rows processed.1
Pages per companyControls how many useful pages are checked on each website.5
Total request budgetPrevents unexpectedly large or expensive runs.10
JavaScript renderingOptional browser fallback for JavaScript-only sites.Off

Example:

{
"companies": [
{
"companyName": "Apify",
"website": "https://apify.com"
}
]
}

The Actor never overwrites a non-empty input cell. It fills or appends enrichment columns and keeps rows in their original order.

Continue a larger list safely

Add an optional jobName, for example crm-october, to create a resumable job. Repeat the same input data and enrichment settings with that name to process the next unfinished rows. With a job name, maxRows is the maximum new rows for this run; the existing default remains one. Jobs support up to 1,000 input rows. Use separate job names for separate files and refreshes, and avoid overlapping runs of one job.

Confirmed rows are recovered from durable checkpoints and included in the current Dataset and exports without another enrichment event. Within-job duplicate reuse remains free. Set checkpointEveryRows (default 5) to control how often partial CSV/XLSX files are refreshed; row checkpoints are saved after every confirmed delivery. RUN_SUMMARY.json states export rows, remaining rows, resumed rows, and the stop reason. The memory-dependent run-start event applies to each run. Platform usage follows the active Pricing tab: it is included when the new inclusive pricing activates.

A changed file, column mapping, requested enrichment fields, or collection settings requires a new job name. A lost dataset-write response is reconciled with its original Dataset when possible. If confirmation is unavailable, the job stops with job_delivery_uncertain rather than automatically repeating a potentially paid write. Inspect the original run before starting a replacement job. Named job storage belongs to your Apify account and retains the input-derived results until you remove that storage. Do not put confidential customer data in a public issue.

Output

Every input row produces a dataset record with:

  • match status and confidence;
  • verified official website and domain;
  • public emails and phone numbers;
  • named contacts exactly as published by the company;
  • address, description, and published industry;
  • LinkedIn, Facebook, Instagram, X, YouTube, TikTok, and GitHub links;
  • source URLs and field-level evidence;
  • warnings or errors when a site cannot be accessed safely.

The run also provides:

  • ENRICHED.xlsx — completed Excel workbook;
  • ENRICHED.csv — completed CSV export;
  • RUN_SUMMARY.json — sanitized processing and quality totals.

Example dataset item:

Selected fields from the documented output; other required export fields are omitted here for readability. Use the output schema for the complete record contract.

{
"rowNumber": 2,
"status": "enriched",
"matchStatus": "provided_domain_accessible",
"matchConfidence": 1,
"inputCompanyName": "Apify",
"officialWebsite": "https://apify.com/",
"domain": "apify.com",
"emails": ["support@apify.com"],
"phones": [],
"address": "Na Příkopě 959/27, Prague, 11000, CZ",
"sourceUrls": ["https://apify.com/", "https://apify.com/about"],
"warnings": [],
"errors": []
}

Result statuses

  • enriched: verified company with one or more requested fields.
  • partial: verified website, but limited enrichment was available.
  • needs_review: plausible candidates existed but confidence was insufficient.
  • not_found: no suitable official website was found.
  • blocked: robots rules or access controls prevented collection.
  • invalid_input: the row lacked a usable company name and website.

The Actor deliberately abstains when a match is ambiguous. This protects your spreadsheet from confident-looking but incorrect company data.

Direct-scraping methodology

Unknown websites are discovered from public HTML search results and verified against company name and location evidence. A website supplied in the input is treated as customer-provided and checked for public accessibility, not independently proven to belong to the named company. The Actor then visits a bounded number of same-site About, Contact, Team, Legal, and Imprint pages. It respects robots rules and does not bypass CAPTCHAs, login walls, paywalls, or access controls.

Named contacts are returned only when visibly published by the company. The Actor does not infer employee details, generate email patterns, or scrape private profiles.

Placeholder addresses, monitoring ingestion tokens, escaped markup fragments, and example-form values are excluded from email output. Social fields contain profile or company-page URLs rather than individual posts, videos, embeds, repositories, or issue forms. To keep spreadsheet cells reviewable, phone output is limited to the first ten distinct published numbers per company and reports a truncation warning when more were found.

Cost controls

Runs are economical by default: direct HTTP scraping is used, JavaScript browser rendering is off, concurrency is 2, and one row is processed for a cheap first-run sample. Raise the row and request limits together for larger lists. The 1024 MB default completed the measured 10-row workload faster and with fewer compute units than the memory-constrained 512 MB configuration.

Every run also has independent hard ceilings:

  • Total request budget counts robots checks, discovery requests, redirects, and website pages across the whole run. The default is 10 for the one-company trial. The measured 10-company test used 43 requests, so set about 50 requests when trying a similar batch.
  • Maximum browser renders limits the more expensive browser fallback. The default is 0; browser use requires explicitly selecting Automatic fallback and raising this limit.
  • Maximum processing time stops new network work after 10 minutes by default.
  • Memory-aware concurrency limits 512 MB runs to one company at a time and 1024 MB HTTP-only runs to four at once. This prevents transient memory spikes while allowing the default tier to finish bulk work efficiently.
  • Apify's Actor timeout remains a final 15-minute platform-level backstop.

When a ceiling is reached, completed data is retained and remaining affected rows are returned as partial results with a budget warning. RUN_SUMMARY.json reports the requested and effective concurrency, allocated memory, configured request and browser limits, actual usage, and deadline.

On pay-per-event runs, the Actor also checks the customer's Apify spending limit before starting each new unique company. It stops cleanly when the remaining event budget is exhausted, retains already completed output, and reports customer_charge_limit_reached in RUN_SUMMARY.json. Only successfully enriched unique companies emit the enriched-company event; duplicates and unsuccessful rows remain free.

For the lowest and most predictable usage cost, supply known company websites, keep JavaScript rendering disabled, test a small sample first, and increase limits only when the sample output justifies it.

Python example

import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
actor = client.actor("thescrapelab/business-spreadsheet-enricher")
run = actor.call(run_input={
"companies": [
{
"companyName": "Apify",
"website": "https://apify.com",
}
]
})
if run is None:
raise RuntimeError("Actor call returned no run or storage metadata")
dataset = client.dataset((run["defaultDatasetId"] if isinstance(run, dict) else run.default_dataset_id))
for item in dataset.iterate_items():
print(item["officialWebsite"], item["emails"], item["sourceUrls"])

Pricing

Before the inclusive pricing activates, the introductory price is $0.001 per successfully enriched unique company plus platform usage. When the new pricing activates, legacy enrichment costs $0.013 per unique enriched company, and crmContacts costs $0.020 per contact-ready company. Platform usage is included in both modes after activation. The memory-dependent run-start event is additional. Check the Pricing tab for active prices and any effective date. There is no subscription or monthly minimum.

You are not charged the enrichment event for duplicate rows, blocked pages, invalid input, low-confidence matches, or companies where no useful public details are found. Apify's small standard Actor-start event may also apply once per run.

The low launch price is intended to make real spreadsheet trials inexpensive. Pricing may be reviewed later as reliability, coverage, and operating evidence grow; any active price change follows Apify's customer-notice rules.

Responsible use and limitations

Use public contact information responsibly and follow applicable privacy, marketing, and communications laws. A public email address is not automatic consent to send unsolicited messages.

Website designs, robots policies, blocking controls, and published data change over time. Some JavaScript-heavy or protected sites may return partial or blocked results. Domain discovery is best effort; supplying a known website produces the most reliable and economical runs. Review needs_review rows instead of treating candidate domains as verified matches.

Support

If a run produces unexpected output, open the Actor's Issues tab and include the run URL plus a short description of the affected row. Do not include private spreadsheet data in a public issue.

Contact-ready CRM exports

Set workflow to crmContacts and contactRequirement to email, phone or either. Provide the usual companies list or CSV/XLSX upload; original inputs and exports remain supported. CRM_READY.csv contains unique, identity-resolved rows with the requested published contact and matching source evidence. REVIEW_NEEDED.csv contains duplicates, blocked/ambiguous results and rows without the requested contact. Both retain your original columns; added CRM columns avoid name collisions. Existing ENRICHED.csv/XLSX downloads remain available.

Before new pricing activates, the existing enriched-company event applies to contact-ready CRM rows. Once contact-ready-company is active, crmContacts uses that $0.020 event instead of the legacy event, with platform usage included. Review-only, duplicate and previously confirmed resumed rows have no new CRM event. The memory-dependent run-start event is additional. Published contacts are not a guarantee of deliverability or permission to contact.

For larger lists, keep the same jobName and input to resume. Both contact exports include previously confirmed rows, which receive no repeat enrichment event. Changing the workflow or contact requirement needs a new job name.

{"workflow":"crmContacts","contactRequirement":"email","maxRows":10,"companies":[{"companyName":"Example company","website":"https://example.com"}]}

Import-ready contacts and review outcomes

Set workflow to crmContacts and choose contactRequirement: email, phone or either. Open CRM readiness and evidence to inspect the company identity, requested contacts, readiness flag and source links. The table contains all result rows. Download CRM-ready contacts (CRM_READY.csv) for qualifying rows only, and Rows needing review (REVIEW_NEEDED.csv) for the remainder. Original spreadsheet columns remain in both files.

crmReady means a unique, identity-resolved company has the requested public email or phone supported by an official-domain source. It does not assert mailbox deliverability, a person's consent to outreach, or sales conversion. Review reasons distinguish duplicates, unresolved identity, source failures and missing requested contact evidence. A duplicate or a previously confirmed resumed row does not incur another enrichment event.

Console example:

{"workflow":"crmContacts","contactRequirement":"either","companies":[{"companyName":"Apify","website":"https://apify.com"}],"maxRows":1,"jobName":"my-company-contacts"}
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("thescrapelab/business-spreadsheet-enricher").call(run_input={
"workflow": "crmContacts", "contactRequirement": "either",
"companies": [{"companyName": "Apify", "website": "https://apify.com"}],
"maxRows": 1, "jobName": "my-company-contacts",
})
if run is None:
raise RuntimeError("Actor call returned no run or storage metadata")
for item in client.dataset((run["defaultDatasetId"] if isinstance(run, dict) else run.default_dataset_id)).iterate_items():
print(item["inputCompanyName"], item.get("crmReady"), item.get("crmReviewReasons"))
ready_csv = client.key_value_store((run["defaultKeyValueStoreId"] if isinstance(run, dict) else run.default_key_value_store_id)).get_record("CRM_READY.csv")

International company websites are supported where public pages and identity evidence can be read. Language, blocking and publication practices affect contact yield. Use the active Pricing tab and effective date to distinguish the introductory pricing from inclusive pricing. Run-start charges remain additional.

Pricing activation and spending limits

New event pricing takes effect on the date shown in the Pricing tab. During any notice period, existing pricing continues. Runs use the pricing snapshot taken at startup; a running job does not switch event prices mid-run. Completed checks may be charged when their source facts are unchanged. Set a sufficient maximum run charge for a complete billable unit plus the memory-dependent start event; smaller limits return explicit partial coverage. Existing builds pinned by API clients retain their original event routing, so use the current default build for the updated workflow.

Collection sources

Collection uses public pages, published documents or rendered page content. Optional AI features use OpenRouter. Source API fallbacks and calls to other Actors are unavailable. A source that cannot provide usable page content may fail or return explicitly incomplete coverage; an older successful run does not guarantee current availability.