# Company Enrichment API — Domain to Company Profile (`insight.solutions/company-enrichment-api`) Actor

Give it domains, URLs or email addresses and get one company profile per domain, read from the company's own website and its own DNS: name, legal name, HQ, founded year, logo, socials, role-based emails and phones, technology stack, mail/DNS/registrar/TLS and the ATS it hires through. No API key.

- **URL**: https://apify.com/insight.solutions/company-enrichment-api.md
- **Developed by:** [Insight Solutions](https://apify.com/insight.solutions) (community)
- **Categories:** Lead generation, Business, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.10 / 1,000 company enricheds

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Company Enrichment API — Domain to Company Profile

Send a list of domains, URLs or email addresses. Get one company profile per
domain — **read from the company's own website and its own DNS, never from a
third party's database.**

That sentence has a corollary, and it is the reason to use this Actor rather than
one that sounds more confident: **anything the company does not publish comes
back `null`, never a guess.** No inferred headcount, no revenue band, no guessed
mailbox pattern, no name scraped off a team page. Every field that *is* filled
carries the rule and the page URL it came from, in a `fieldSources` column you
can audit row by row.

Five column groups on every row:

1. **Identity and firmographics** — name, legal name, description, tagline, logo,
   HQ and every office address the site publishes, founded year, employee band,
   industry, languages, company type.
2. **Published contacts** — role-based emails, phones, social profiles, the
   contact/imprint/privacy/press page URLs, contact-form presence, VAT ID,
   `security.txt`.
3. **Technology stack** — 232 signatures over the pages already fetched: CMS,
   e-commerce platform, JS framework, analytics, ad pixels, chat widget, payment
   providers, CDN, hosting, security vendor.
4. **Infrastructure** — mail provider from MX, DNS operator from NS, SPF and
   domain-verification TXT records, registrar and domain age from RDAP, TLS
   issuer and expiry. *This is the part of the row that never fails to render: a
   company that publishes nothing about itself still has a mail provider, a
   registrar and a certificate.*
5. **Hiring** — the applicant tracking system the company recruits through, its
   board slug, and the open-role count.

**$3.50 per 1,000 companies.** Free-mail domains, dead domains, bot walls,
`robots.txt` refusals, sites that published nothing nameable and domains the run
never reached are all free.

### At a glance

**Input** — this is the Store prefill; paste it and run:

```json
{
  "domains": ["stripe.com", "basecamp.com", "apify.com"],
  "includeContacts": true,
  "includeTechStack": true,
  "includeInfrastructure": true,
  "includeHiring": true,
  "maxPagesPerSite": 6
}
```

**Output** — one row per domain; the fields you will use most are `companyName`,
`primaryEmail`, `technologyNames`, `emailProvider` and `atsPlatform` (full list
under *Output reference*). Anything that could not be fetched comes back as a
free diagnostic row (`ok: false`, `errorType`, `error`) instead of a charge.

**Price** — $3.50 per 1,000 companies (+ $0.001 per run); volume tiers are SILVER
$2.80 and GOLD $2.10 per 1,000, and free-mail domains, dead domains, bot walls,
`robots.txt` refusals, sites that published nothing nameable and domains the run
never reached cost nothing. Pay-per-event, no API key, no browser, limited
permissions — works over the Apify MCP server (`mcp.apify.com`) and with agentic
(x402) payments.

**From code** —
`client.actor("insight.solutions/company-enrichment-api").call(run_input={…})`
with `apify-client`, or
`POST https://api.apify.com/v2/acts/insight.solutions~company-enrichment-api/run-sync-get-dataset-items`.

***

### What you get

One row per input domain. This is `apify.com` from the offline test suite,
trimmed to the interesting columns:

```json
{
  "ok": true,
  "rowType": "company",
  "input": "apify.com",
  "domain": "apify.com",
  "resolvedDomain": "apify.com",
  "websiteUrl": "https://apify.com/",

  "companyName": "Apify",
  "legalName": "Apify Technologies s.r.o.",
  "companyType": "Czech company",
  "description": "Thousands of tools to automate your business. Get real-time web data, track competitors, generate leads, and integrate your apps and AI agents.",
  "tagline": "68,948 tools for your AI",
  "logoUrl": "https://apify.com/img/apify-logo/apify-symbol-200x200.svg",
  "foundedYear": 2015,
  "foundedYearEvidence": "jsonld.Organization.foundingDate",
  "employeeCount": null,
  "employeeBand": null,
  "industry": "Web data and scraping",
  "industrySource": "keyword-table",
  "industryEvidence": "keyword: web data",

  "emails": [
    { "address": "support@apify.com", "type": "role", "foundOn": "https://apify.com/" },
    { "address": "hello@apify.com",   "type": "role", "foundOn": "https://apify.com/contact" }
  ],
  "primaryEmail": "support@apify.com",
  "phones": null,
  "linkedinUrl": "https://linkedin.com/company/apify",
  "socials": {
    "linkedin": "https://linkedin.com/company/apify",
    "twitter": "https://twitter.com/apify",
    "github": "https://github.com/apify",
    "tiktok": "https://tiktok.com/@apifytech",
    "discord": "https://discord.com/invite/jyEM2PRvMU",
    "g2": "https://g2.com/products/apify",
    "glassdoor": "https://glassdoor.com/Overview/Working-at-Apify-EI_IE3100324.11,16.htm",
    "wikipedia": "https://wikipedia.org/wiki/Apify",
    "wikidata": "https://wikidata.org/wiki/Q112502991",
    "facebook": null, "instagram": null, "youtube": null, "bluesky": null,
    "threads": null, "reddit": null, "crunchbase": null, "producthunt": null
  },
  "hqAddress": "Na Příkopě 959/27, Prague, 11000, CZ",
  "hqCity": "Prague",
  "hqCountry": "CZ",
  "country": "CZ",
  "vatId": "CZ04788290",
  "contactPageUrl": "https://apify.com/contact",
  "careersUrl": "https://apify.com/jobs",
  "docsUrl": "https://docs.apify.com/",

  "technologyNames": ["Next.js", "React", "Node.js", "Google Tag Manager", "HubSpot", "Intercom", "OneTrust", "Nginx"],
  "jsFramework": "Next.js",
  "analytics": ["Google Tag Manager"],
  "hasCookieBanner": true,

  "emailProvider": "Google Workspace",
  "acceptsEmail": true,
  "dnsProvider": "Amazon Route 53",
  "spfIncludes": ["_spf.google.com", "mailgun.org", "amazonses.com"],
  "verifications": ["Google", "Zapier", "OpenAI", "Mixpanel"],
  "registrar": "Amazon Registrar, Inc.",
  "domainCreatedAt": "2009-06-02T17:14:10.000Z",
  "domainAgeYears": 17.3,
  "tlsIssuer": "Amazon — Amazon RSA 2048 M02",
  "hsts": false,

  "atsPlatform": "ashby",
  "atsBoardSlug": "apify",
  "atsBoardUrl": "https://jobs.ashbyhq.com/apify",
  "openJobs": 17,
  "hiringSignal": true,

  "pagesFetched": [
    { "url": "https://apify.com/",        "status": 200, "role": "home",    "bytes": 491881 },
    { "url": "https://apify.com/contact", "status": 200, "role": "contact", "bytes": 332264 },
    { "url": "https://apify.com/about",   "status": 200, "role": "about",   "bytes": 482783 },
    { "url": "https://apify.com/jobs",    "status": 200, "role": "careers", "bytes": 425302 }
  ],
  "sources": ["jsonld", "opengraph", "footer", "text", "tech", "dns", "rdap", "tls", "ats", "links"],
  "fieldSources": {
    "companyName":  { "rule": "jsonld.Organization.name",      "url": "https://apify.com/" },
    "legalName":    { "rule": "jsonld.Organization.legalName", "url": "https://apify.com/" },
    "foundedYear":  { "rule": "jsonld.Organization.foundingDate", "url": "https://apify.com/" },
    "emailProvider":{ "rule": "dns.MX", "url": "https://dns.google/resolve?name=apify.com&type=MX" },
    "atsPlatform":  { "rule": "ats.marker", "url": "https://apify.com/jobs" }
  },
  "confidence": 0.94,
  "partial": false,
  "scrapedAt": "2026-09-15T04:12:00.000Z"
}
```

Note `employeeCount: null`. Apify's home page says "more than 15,000 **members**"
— a community, for a company of about a hundred people. A tool that filled the
column from that sentence would be wrong by two orders of magnitude, so this one
leaves it empty. That is the whole design in one field.

***

### Quick start

1. Paste your domains into **Domains**. A bare domain, a full URL or an email
   address all work.
2. Run it.
3. Export the dataset as JSON, CSV or Excel, or read it from the API.

The defaults are the right defaults: six pages per site, all five column groups
on, five companies in parallel, the Apify datacenter proxy.

***

### Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `domains` | array | *(required)* | One entry per company: `stripe.com`, `https://www.stripe.com/about` or `sales@stripe.com`. The registrable domain identifies the company, so the same company written three ways is fetched and billed **once** |
| `includeContacts` | boolean | `true` | Emails, phones, socials, page URLs, VAT, `security.txt` |
| `includeTechStack` | boolean | `true` | 232 signatures over pages already fetched — CPU, not requests |
| `includeInfrastructure` | boolean | `true` | DNS (MX, NS, TXT, A), RDAP, TLS |
| `includeHiring` | boolean | `true` | ATS detection is free; the open-role count costs one request |
| `domain` | string | — | A single-entry convenience for integrations that cannot send an array |
| `maxPagesPerSite` | integer 1–12 | `6` | HTML pages per company, home page included. `robots.txt` is outside it; `security.txt` gets one extra allowance |
| `includePersonalEmails` | boolean | `false` | Read the **Privacy** section first |
| `contactPathHints` | array | `[]` | Extra paths to prefer during discovery, e.g. `["/impressum", "/unternehmen"]` |
| `minConfidence` | number 0–1 | `0` | Rows below this become **free** diagnostics and are not charged |
| `maxConcurrency` | integer 1–20 | `5` | Companies in flight; each gets its own proxy session |
| `maxRunSecs` | integer 30–3600 | `240` | Wall-clock budget. Domains not reached are never charged |
| `proxyConfiguration` | object | `{ "useApifyProxy": true }` | Apify **datacenter** proxy |

**None of the `include*` toggles changes the price.** A row is a row.

***

### Output reference

Every row carries every column, `null` where it does not apply, so a mixed export
of live sites, dead domains and free-mail addresses is still one rectangular
table. `rowType` is `company` or `diagnostic`.

#### Identity

`domain` · `resolvedDomain` · `redirectedToDifferentDomain` · `websiteUrl` ·
`canonicalUrl` · `companyName` · `legalName` · `legalNameEvidence` ·
`description` · `tagline` · `taglineSource` · `logoUrl` · `faviconUrl` ·
`companyType` · `copyrightYear` · `copyrightStartYear`

`resolvedDomain` is not decoration. Ask for `notion.so` and the site answers at
`www.notion.com`; every subsequent decision uses the resolved domain, because
guessing paths on the domain you typed would 404 on every one.

`copyrightStartYear` is **never** promoted to `foundedYear`. Moz's footer says
2021 and Moz was founded in 2004.

#### Firmographics

`foundedYear` · `foundedYearEvidence` · `employeeCount` · `employeeBand` ·
`employeesEvidence` · `industry` · `industryEvidence` · `industrySource`

The three `*Evidence` columns exist because these are the three fields most worth
distrusting. Read the evidence before you act on the number.

A founding year read from prose has to survive three tests: the sentence must not
be about a city, a university, a church or a building (all of which get founded
in years); it must either name the company or begin "We", "Founded" or
"Established"; and the year must be between 1800 and today. The first live run
filed one company as founded in 1979 on the strength of a sentence about the town
its office is in — hence the rules, and hence the evidence column.

#### Contacts and location

`emails` · `emailsCount` · `primaryEmail` · `phones` · `phoneEvidence` ·
`socials` · `linkedinUrl` · `contactPageUrl` · `contactPageConfirmed` ·
`hasContactForm` · `newsletterSignup` · `hasLoginPortal` · `isEcommerce` ·
`appLinks` · `vatId` · `imprintUrl` · `privacyUrl` · `termsUrl` · `aboutUrl` ·
`pressUrl` · `blogUrl` · `docsUrl` · `statusUrl` · `supportUrl` · `teamUrl` ·
`securityTxtUrl` · `securityContact` · `securityPolicyUrl` ·
`securityTxtExpires` · `hqAddress` · `hqCity` · `hqRegion` · `hqPostalCode` ·
`hqCountry` · `hqEvidence` · `officeLocations` · `country` · `languages`

Every `*Url` column is **linked, not guessed**. A subdomain counts:
`press.stripe.com`, `docs.apify.com`, `legal.hubspot.com` are all real answers
this Actor finds and a same-host-only crawler misses.

A different *domain* does not count. When a link leaves the company's own
registrable domain — `basecamp.com/privacy` answering at
`37signals.com/policies/privacy` — the URL column still holds the link that was
followed and `pagesFetched` still records where it landed, but **nothing that
page says about itself becomes a fact about this company**: not its name, not its
description, not its structured data, and not its email addresses. A home page
that redirects across a domain boundary is the opposite case and is recorded as
`redirectedToDifferentDomain`, because there the destination *is* the company.

`officeLocations` carries every distinct postal address in the site's structured
data, capped at 25. Stripe publishes 24 — and marks none of them as its
headquarters, which is why `hqAddress` for stripe.com is `null` and `hqEvidence`
reads `ambiguous: 24 office locations`. **An HQ is `Organization.address`, or a
`location` that calls itself the headquarters, or a company's single office.
Otherwise there is no HQ column, because picking the first of twenty-four
addresses is picking one at random.**

`country` then falls back through its own ladder — the HQ's country, the ccTLD,
the phone's calling code, `og:locale`, the site's own `hreflang` set,
`<html lang>`, and last the legal form of the company's name — and
`countryEvidence` names the rung that answered, so an inference never looks like
a fact.

#### Technology

`technologies` · `technologyNames` · `technologyCategories` · `cms` ·
`ecommercePlatform` · `jsFramework` · `hosting` · `analytics` · `advertising` ·
`cdn` · `security` · `chatWidget` · `paymentProviders` · `hasCookieBanner` ·
`externalDomains`

Detection reads only pages already fetched, so it costs no extra requests. It is
merged from pages on the **same host** as the entry page: a company's legal or
docs subdomain is routinely a different stack, and stamping it on the row would
be wrong.

#### Infrastructure

`emailProvider` · `mxRecords` · `acceptsEmail` · `dnsProvider` · `nameservers` ·
`spf` · `spfIncludes` · `verifications` · `registrar` · `registrarIanaId` ·
`domainCreatedAt` · `domainExpiresAt` · `domainAgeYears` · `dnssec` ·
`registrationStatus` · `registrationNote` · `tlsIssuer` · `tlsValidTo` ·
`tlsDaysUntilExpiry` · `tlsSans` · `httpStatus` · `server` · `hsts` · `cdnHint`

`verifications` is the cheapest "what does this company actually use" signal
there is: a company publishes `zapier-domain-verification-challenge=…` only
because somebody there connected Zapier to their domain.

#### Hiring

`careersUrl` · `atsPlatform` · `atsPlatformLabel` · `atsBoardSlug` ·
`atsBoardUrl` · `openJobs` · `hiringSignal`

Eleven platforms are detected: Greenhouse, Lever, Ashby, Workable, Recruitee,
SmartRecruiters, Personio, Teamtailor, Breezy, JazzHR and Workday. Nine of them
also return `openJobs`. Workday is named but not counted, because its list needs
a POST with paging and this Actor will not hold a second protocol for one
number; JazzHR publishes no public list endpoint at all.

#### Provenance

`pagesFetched` · `pagesFetchedCount` · `sources` · `fieldSources` ·
`confidence` · `partial`

`confidence` is `0.60 × weighted field coverage + 0.25 × best identity source +
0.15 × pages that answered`. It measures **how much the company published**, not
whether the values are true. A field whose column group you switched off is
removed from the denominator rather than counted as missing, so turning a group
off never makes the same row look worse.

#### Diagnostic rows, all free

`invalid-input` · `freemail` · `not-found` · `unreachable` · `blocked` ·
`robots-disallowed` · `not-html` · `no-data` · `low-confidence` · `timeout` ·
`budget-stopped`

***

### What fills, and what usually does not

Six real company websites were captured to build and test this Actor —
`stripe.com`, `notion.so`, `basecamp.com`, `apify.com`, `moz.com`,
`hubspot.com`. Here is the coverage, as numbers rather than adjectives:

| Field | Fills on |
|---|---|
| `companyName` | **6 / 6** |
| `description` | **6 / 6** |
| `logoUrl` | **6 / 6** |
| `legalName` | **6 / 6** |
| `country` | **6 / 6** |
| social profiles | **4 / 6** |
| HQ address | 3 / 6 |
| `foundedYear` | 3 / 6 |
| a role-based email | 2 / 6 |
| a phone number | **1 / 6** |
| an ATS | 1 / 6 |
| **`employeeCount`** | **0 / 6** |

Three of those deserve saying out loud.

**`employeeCount` is empty on all six.** It is a headline field on several
competing listings. Real company websites mostly do not publish a headcount, and
the ones that publish a number usually publish a community or customer count that
a careless parser turns into one. Ours returns `null` and tells you why.

**Social recall is 4 in 6 on well-known companies.** Notion and Basecamp render
*zero* social links in their server HTML — not a parsing failure, there is
genuinely nothing there. If socials are the reason you are buying, budget for
about two thirds.

**Phones are 1 in 6.** Across six sites and thirteen captured pages there is not
one `tel:` link and not one structured `telephone` value. The only number
anywhere is Stripe's footer line, and it survives because it carries its own
country code. See **Limitations** for the rule.

**An HQ address fills on 3 of 6, not 4.** One of the six publishes two dozen
office addresses and says which is the head office for none of them. `country`
still fills for it, and every address is still in `officeLocations` — but the
`hqAddress` column stays empty rather than naming whichever one happened to be
first.

***

### What you are never charged for

- a free-mail domain (`gmail.com`, `qq.com`, `web.de` — about 140 of them)
- a domain that does not exist, or that resolves and serves nothing
- a site behind a bot wall that revealed nothing
- a site whose `robots.txt` asks us not to read its home page
- an IP address, a bare word, or anything else that is not a domain
- a site that answered and published nothing this Actor could name a company from
- a row scoring below the `minConfidence` you set
- domains the run never reached, because of your time budget or your spend cap
- **every run that returns nothing at all** — it finishes FAILED and bills
  nothing, start fee included

***

### Pricing

| Event | What it is | Price |
|---|---|---|
| `company` | One company profile returned | **$0.0035** — $3.50 per 1,000 |
| `actor-start` | Charged once per run, and only after the first profile is in the dataset | $0.001 |

Volume tiers: SILVER $0.0028, GOLD $0.0021 per profile.

Charging is charge-after-push, always: the row is in your dataset before the
charge is recorded. `ACTOR_MAX_TOTAL_CHARGE_USD` is respected proactively — when
the remaining budget cannot cover another profile the run stops fetching,
finishes **SUCCEEDED** and says so in the status message.

***

### Use it from an AI agent, or from code

One JSON object in, one flat array out — the shape agent runtimes want. The Actor
runs with **limited permissions**, uses **pay-per-event** pricing and never
enters Standby, so it works over the Apify MCP server and with x402 agentic
payments. The **Integrations** tab pushes results to Slack, a webhook, Zapier,
Make, Google Sheets, Snowflake or BigQuery.

```bash
curl -X POST "https://api.apify.com/v2/acts/insight.solutions~company-enrichment-api/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"domains":["stripe.com","basecamp.com","apify.com"],"maxPagesPerSite":6}'
```

```python
## pip install apify-client
from apify_client import ApifyClient

client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("insight.solutions/company-enrichment-api").call(run_input={
    "domains": ["stripe.com", "sales@notion.so", "https://www.hubspot.com/"],
    "maxPagesPerSite": 6,
    "includeInfrastructure": True,
    "minConfidence": 0.5,
    "maxConcurrency": 5,
})

for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row.get("ok") and row["rowType"] == "company":
        print(row["companyName"], row["country"], row["industry"],
              row["emailProvider"], row["primaryEmail"], row["confidence"],
              sep=" | ")
    else:
        print("skipped", row["input"], row["errorType"], row["error"], sep=" | ")
```

Set `minConfidence` when you would rather have a short, dense list than a long
one: rows below it arrive in full as free diagnostics, so you can still see what
was rejected without paying for it.

***

### FAQ

**Where does the data come from?**
The company's own website — its home page and up to five pages it links to — and
its own DNS, RDAP registration and TLS certificate. No third-party enrichment
database, no data broker, no cached profile of unknown age. If the company
changed its address yesterday, this Actor reads yesterday's address.

**Why is a field empty when another tool fills it?**
Because the company did not publish it. This Actor will not invent a headcount
from an office count, a revenue band from a headcount, or an email address from a
name pattern. An empty column is information; a fabricated one is a liability.

**Why is there no revenue column?**
A private company's revenue is not something its website publishes. A band
derived from a guessed employee count is a guess squared, and it would be the
least reliable column in the dataset while looking like the most valuable one.
It is absent on purpose.

**Why no CEO or founder name?**
See **Privacy**. This Actor is company-level only, by design.

**What does `confidence` actually measure?**
Coverage and source quality — how much of the profile the company published and
how good the best source was. It says nothing about whether a value is correct.
For that, read `fieldSources` and the `*Evidence` columns.

**Can I send email addresses instead of domains?**
Yes. `sales@acme.com` becomes `acme.com`. The address itself is discarded and
never appears in the output. A *consumer* mail domain gets a free diagnostic
instead, because `gmail.com` is not a company.

**How many requests does one company cost me?**
At the defaults: one `robots.txt`, up to six pages, one `security.txt`, four DNS
lookups, one RDAP call, one TLS socket and at most one ATS board fetch. Fourteen
HTTP requests worst case, and you pay one flat price whatever that comes to.

**Does it re-fetch a domain I already ran?**
Every run is fresh. There is no cache, because a cached company profile is the
thing this Actor exists as an alternative to.

***

### Limitations

- **Phone numbers without a country code are dropped.** A number is kept when it
  comes from a `tel:` link or structured data, or when the visible text carries a
  leading `+` (or `00`). A national-format number like `(020) 7946 0958` is not
  kept: without a validation library, the regex that would catch it also catches
  order numbers, prices, dates and postcodes, and a wrong phone number in a lead
  list is worse than an empty column.
- **`robots.txt` is honoured, and a refusal costs the whole domain.** A site that
  disallows its home page produces a free `robots-disallowed` row. A disallowed
  sub-page is skipped silently and the profile is built from the rest.
- **JavaScript is not executed.** There is no browser. A site that renders its
  address, its footer or its social links only in the client will give up less
  than one that ships them in the HTML. Most do ship them; the captures are
  honest about the ones that do not.
- **The employee-count and founding-year patterns are best-effort.** They read
  prose, and prose is ambiguous. Both carry an evidence column for exactly that
  reason, and the founding-year rule refuses any sentence that is not visibly
  about the company.
- **A company with many offices and no stated headquarters gets no HQ.**
  Schema.org has no "this one is the head office" marker that sites reliably
  use, so when a company lists several and labels none, `hqAddress` and its four
  sub-fields are null and `hqEvidence` says how many there were.
- **Structured data is only as good as the company's.** Four of the six captured
  sites publish an `Organization` node; one publishes none at all. When it is
  absent, Open Graph and the footer carry the row, and `confidence` drops to say
  so.
- **`hosting` and `cdnHint` are hints and are labelled as such.** Cloudflare
  running a domain's DNS does not prove Cloudflare is proxying its traffic.
- **The upstream format may change.** Websites are rewritten, structured data is
  removed, `robots.txt` is tightened. When a rule stops matching, the column goes
  `null` rather than guessing — which is also how you will notice.

***

### Privacy

**This Actor is company-level only.** That is a product decision, a compliance
position and a selling point, and all three are deliberate.

1. **No names of individuals, ever.** No CEO, no founder, no managing director,
   no "decision makers", no team-page roster. The structured-data walker skips
   `Person`-typed nodes entirely and passes no inheritance to their children — so
   when `stripe.com` publishes its two founders by name inside the same graph as
   the company's own details, neither name reaches the output. A unit test pins
   that against the captured page.
2. **Emails are an allowlist, not a name detector.** An address survives only
   when its local part is a recognised business role or generic business word
   (`info@`, `sales@`, `careers@`, `support@`; trailing digits ignored, so
   `sales2@` still matches). A given name anywhere in the local part beats a role
   word, so `anna.sales@` is treated as a person's and dropped. Everything
   unrecognised is treated as personal and dropped.
   **Worked example: `basecamp.com` publishes exactly one address,
   `jason@basecamp.com`, and this Actor returns zero emails for it.** That is the
   correct answer.
3. **Phones are business numbers as published on the site.** Team pages are
   fetched only for the founding-year and headcount patterns; no contact is ever
   read from one.
4. **No email verification of any kind.** No SMTP probe, no third-party
   verification API, no catch-all test. `acceptsEmail` is derived from the
   presence of MX records, which is a DNS fact about a domain — not a test of
   anybody's mailbox.
5. **No guessed addresses.** There is no `emailPattern` column and no
   `firstname.lastname@` inference. An address the company did not publish does
   not appear.
6. **RDAP is already redacted at source.** ICANN policy and the GDPR mean most
   registries redact the registrant entirely, and this Actor does not return a
   registrant field at all. The registrar's published abuse mailbox is a
   different thing and is not a natural person's address.
7. **`robots.txt` is honoured on every page**, and a refusal is reported rather
   than worked around.
8. **You are the controller of what happens next.** If you export this data, join
   it to personal data, or contact anyone on the strength of it, the GDPR and
   CCPA obligations are yours. Turning `includePersonalEmails` on makes that
   immediate and explicit.

***

### Our other Actors

Every Insight Solutions Actor is pay-per-result with no browser, no login and no API key, and every one of them returns free diagnostic rows instead of billing for failures. Prices are per 1,000 results.

**Video, audio & social**

- [YouTube Transcript API](https://apify.com/insight.solutions/youtube-transcript-api) — captions as timed segments, text, SRT or VTT, with language fallback and translation.
- [YouTube Comments API](https://apify.com/insight.solutions/youtube-comments-api) — comments and replies with likes, pinned and hearted flags, newest or top sort.
- [YouTube Channel API](https://apify.com/insight.solutions/youtube-channel-api) — a channel's videos, Shorts and live streams, plus YouTube search.
- [Podcast Search, Episodes & Charts API](https://apify.com/insight.solutions/podcast-api) — Apple Podcasts search, charts and full episode feeds.
- [Bluesky Scraper](https://apify.com/insight.solutions/bluesky-scraper) — profiles, posts, followers and follows from the public AT Protocol API.
- [Telegram Channel Scraper](https://apify.com/insight.solutions/telegram-channel-scraper) — posts, views and channel stats from public Telegram channels.
- [Substack Scraper](https://apify.com/insight.solutions/substack-scraper) — posts with full free text, comments and publication profiles.
- [Hacker News API](https://apify.com/insight.solutions/hacker-news-api) — stories, comments, users, front page and a structured "Who is hiring?" parser from the official HN APIs.

**News, documents & the web**

- [Google News Search, Topics & Real Article URLs](https://apify.com/insight.solutions/google-news-api) — news search and topic feeds with the publisher's real URL decoded.
- [Website to Markdown — Content Extractor for LLMs & RAG](https://apify.com/insight.solutions/website-content-extractor) — any site as clean Markdown, text and heading-aware chunks.
- [Internet Archive API](https://apify.com/insight.solutions/internet-archive-api) — archive.org search, item metadata, files and reviews.
- [Wayback Machine Toolkit](https://apify.com/insight.solutions/wayback-toolkit) — archived URL inventories, snapshots and text diffs between dates.
- [Website Technology Detector](https://apify.com/insight.solutions/website-tech-detector) — the tech stack behind any site, with the evidence for each detection.
- [Domain Intelligence API](https://apify.com/insight.solutions/domain-intelligence-api) — DNS, RDAP registration, TLS certificate and HTTP facts in one row per domain.
- [SEO Page Audit](https://apify.com/insight.solutions/seo-page-audit) — sitemap crawl with on-page checks, structured data and broken-link reports.
- [Keyword Suggestions API](https://apify.com/insight.solutions/keyword-suggestions-api) — Google, YouTube, Bing, Amazon and eBay autocomplete with alphabet and question expansions.
- [Website Contact Extractor](https://apify.com/insight.solutions/website-contact-extractor) — emails, phone numbers and social profiles from any list of websites.
- [Web Search Results API](https://apify.com/insight.solutions/web-search-api) — Bing and DuckDuckGo organic results with snippets, no key, no browser.

**Business, finance & jobs**

- [Congress & Insider Trades API](https://apify.com/insight.solutions/congress-insider-trades-api) — STOCK Act periodic transaction reports and SEC Form 4 insider trades in one schema.
- [Federal Contracts, Grants & Lobbying API](https://apify.com/insight.solutions/federal-contracts-grants-api) — SAM.gov opportunities, USAspending awards, Grants.gov notices and Senate lobbying filings in one schema.
- [SEC EDGAR API](https://apify.com/insight.solutions/sec-edgar-api) — filings, XBRL financials and full-text search by ticker or CIK.
- [Clinical Trials & FDA API](https://apify.com/insight.solutions/clinical-trials-fda-api) — ClinicalTrials.gov studies plus openFDA recalls, labels, approvals, 510(k)s and adverse-event reports.
- [Product & Vehicle Recalls API](https://apify.com/insight.solutions/product-recalls-api) — CPSC, NHTSA, FDA and USDA recalls, vehicle complaints and ratings, plus a VIN decoder.
- [Y Combinator Companies, Batches & Founders](https://apify.com/insight.solutions/yc-companies-directory) — the YC directory with founders and social links, filterable by batch, industry and hiring status.
- [Career Site Jobs API](https://apify.com/insight.solutions/ats-jobs-api) — jobs straight from Greenhouse, Lever, Ashby, Workable and 10+ other ATS career sites.
- [New Job Postings Monitor](https://apify.com/insight.solutions/job-postings-monitor) — new, closed and changed postings on the career sites you watch.
- [Remote Jobs API](https://apify.com/insight.solutions/remote-jobs-api) — RemoteOK, Remotive, We Work Remotely, Himalayas, Jobicy and more in one schema, deduplicated.
- [Shopify Products API](https://apify.com/insight.solutions/shopify-products-api) — any Shopify store's catalogue, variants, prices and stock signals.
- [Shopify Store Monitor](https://apify.com/insight.solutions/shopify-store-monitor) — price drops, sales, restocks, sell-outs and new products on any Shopify store, one row per change.

**Apps & games**

- [App Store & Google Play Reviews API](https://apify.com/insight.solutions/app-reviews-api) — reviews from both stores with ratings, versions and developer replies.
- [App Store Top Charts & App Search API](https://apify.com/insight.solutions/app-charts-api) — Apple top charts by country and genre, plus app search and details.
- [App Store Keyword Rank Tracker](https://apify.com/insight.solutions/app-store-keyword-rank-tracker) — where any app ranks for any keyword on the App Store and Google Play, with rank changes and ASO suggestions.
- [Steam Reviews API](https://apify.com/insight.solutions/steam-reviews-api) — Steam reviews with playtime, helpfulness and game details.
- [Steam Game Data API](https://apify.com/insight.solutions/steam-store-stats-api) — prices, tags, review scores, live player counts and top charts.

# Actor input Schema

## `domains` (type: `array`):

One entry per company. A bare domain (`stripe.com`), a URL (`https://www.stripe.com/about`) or an email address (`sales@stripe.com`) all work — the registrable domain is what identifies the company, and the same company written three ways is fetched and billed once. Free-mail domains, IP addresses and anything that is not a domain get a free diagnostic row instead of a charge.

## `includeContacts` (type: `boolean`):

Role-based emails, phone numbers, social profiles, the contact/imprint/privacy/press page URLs, VAT ID and `security.txt`. Read only from the pages already fetched.

## `includeTechStack` (type: `boolean`):

232 signatures over the pages already fetched: CMS, e-commerce platform, JS framework, analytics, ad pixels, chat widget, payment providers, CDN, hosting and security vendor. Costs CPU, not requests.

## `includeInfrastructure` (type: `boolean`):

Four DNS lookups (MX, NS, TXT, A), the RDAP registration record and the TLS certificate. This is the column group that never fails to render: a company that publishes nothing about itself still has a mail provider, a registrar and a certificate.

## `includeHiring` (type: `boolean`):

Which applicant tracking system the company recruits through, its board slug and, for nine of the eleven platforms, the number of open roles. Detection is free — it reads pages already fetched; only the role count costs one request.

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

A convenience for integrations that cannot send an array, such as a webhook or a spreadsheet cell. Whatever you put here is added to `domains`, so leave it empty when you are already sending a list.

## `maxPagesPerSite` (type: `integer`):

HTML pages fetched per company, including the home page. Discovery takes at most one page per role — contact, imprint, about, careers, team, press, legal, privacy, security — plus two others, best first. `/robots.txt` is outside this budget because it is a policy fetch, and `/.well-known/security.txt` gets one extra allowance.

## `includePersonalEmails` (type: `boolean`):

OFF by default, and read the privacy section of the README before turning it on. With it off, an address survives only when its local part is a recognised business role or generic word (`info@`, `sales@`, `careers@`); anything else — including a name that also carries a role word, like `anna.sales@` — is treated as a natural person's and dropped. With it on you become the controller of personal data under the GDPR and the CCPA.

## `contactPathHints` (type: `array`):

Paths to rank first during discovery, for a market whose conventions differ from the defaults — for example `["/impressum", "/unternehmen"]` for German sites. An exact path match scores above every built-in role.

## `minConfidence` (type: `number`):

A profile whose `confidence` is below this is returned as a **free** diagnostic row carrying the same columns, and is not charged for. At the default of 0 nothing changes. Set it high enough to reject everything and the run finishes FAILED with nothing billed.

## `maxConcurrency` (type: `integer`):

How many companies are enriched at once. Each gets its own proxy session, so one site that refuses a request does not burn the exit IP the others are using.

## `maxRunSecs` (type: `integer`):

Wall-clock budget for the whole run. Domains the run never reaches get a free `timeout` diagnostic and are never charged for.

## `proxyConfiguration` (type: `object`):

Apify **datacenter** proxy by default, which is what every captured test fixture was taken through and what every one of those sites answered on. Switch to residential only if a target refuses datacenter addresses — it costs considerably more per gigabyte and the per-row price assumes datacenter.

## Actor input object example

```json
{
  "domains": [
    "stripe.com",
    "basecamp.com",
    "apify.com"
  ],
  "includeContacts": true,
  "includeTechStack": true,
  "includeInfrastructure": true,
  "includeHiring": true,
  "maxPagesPerSite": 6,
  "includePersonalEmails": false,
  "contactPathHints": [],
  "minConfidence": 0,
  "maxConcurrency": 3,
  "maxRunSecs": 240,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

One row per domain, read from the company's own website and its own DNS. Delivered as JSON items in the default dataset.

# 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 = {
    "domains": [
        "stripe.com",
        "basecamp.com",
        "apify.com"
    ],
    "includeContacts": true,
    "includeTechStack": true,
    "includeInfrastructure": true,
    "includeHiring": true,
    "maxPagesPerSite": 6,
    "includePersonalEmails": false,
    "contactPathHints": [],
    "minConfidence": 0,
    "maxConcurrency": 3,
    "maxRunSecs": 240,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("insight.solutions/company-enrichment-api").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 = {
    "domains": [
        "stripe.com",
        "basecamp.com",
        "apify.com",
    ],
    "includeContacts": True,
    "includeTechStack": True,
    "includeInfrastructure": True,
    "includeHiring": True,
    "maxPagesPerSite": 6,
    "includePersonalEmails": False,
    "contactPathHints": [],
    "minConfidence": 0,
    "maxConcurrency": 3,
    "maxRunSecs": 240,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("insight.solutions/company-enrichment-api").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 '{
  "domains": [
    "stripe.com",
    "basecamp.com",
    "apify.com"
  ],
  "includeContacts": true,
  "includeTechStack": true,
  "includeInfrastructure": true,
  "includeHiring": true,
  "maxPagesPerSite": 6,
  "includePersonalEmails": false,
  "contactPathHints": [],
  "minConfidence": 0,
  "maxConcurrency": 3,
  "maxRunSecs": 240,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call insight.solutions/company-enrichment-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,insight.solutions/company-enrichment-api"
        }
    }
}
```

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/zexadjr48AlPlBEsi/builds/WvSeWRvgMN2CpAghm/openapi.json
