# Company Data Enrichment Tool — ZoomInfo Alternative (`khadinakbar/zoominfo-alternative`) Actor

Enrich company domains with source-cited public website data. Preserve CRM IDs while collecting identity, firmographic signals, published business contacts, technologies, source routes, and timestamps for account review.

- **URL**: https://apify.com/khadinakbar/zoominfo-alternative.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** Lead generation, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $50.00 / 1,000 source-cited company enrichments

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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 Data Enrichment Tool — ZoomInfo Alternative

Enrich company domains with source-cited public website data. Preserve CRM IDs while collecting identity, firmographic signals, published business contacts, technologies, source routes, and timestamps for account review. For account operations, each dataset row is one company website enrichment record that preserves the supplied CRM identity.

### Workflow: put the results to work

Send the domains and CRM keys from an existing account list. Inspect public identity and firmographic signals with their source pages, then join accepted observations back to the original records. Keep website-derived facts distinct from inferred company attributes.

### What data you receive

One result row per supplied company domain. Unavailable values remain `null` or `[]`, preserving a precise review boundary.

| Field | Meaning |
| --- | --- |
| `companyName` and `description` | Public website metadata or organization-markup signal, with its source URL. |
| `organizationType`, `foundedYear`, `address`, and `logoUrl` | Values observed in public Schema.org organization markup. They are never estimated. |
| `industrySignals` | Small text signals observed in fetched public metadata; not a definitive classification. |
| `publishedEmails` and `publishedPhones` | Values visibly published on the fetched company site. No pattern generation or mailbox validation. |
| `linkedinCompanyUrl` and `otherSocialUrls` | Links visibly published by the company site; those destination profiles are not fetched. |
| `technologySignals` | Named public asset/script signatures observed in fetched HTML, not a full stack inventory. |
| `sourceUrls`, `fieldSources`, `fetchRoutes`, and `collectedAt` | The public pages supporting the record, whether direct or Apify Unblocker access produced it, and when evidence was collected. |
| `collectionOutcome` and `warnings` | Explicit `ENRICHED`, `VALID_EMPTY`, `INVALID_INPUT`, or `UPSTREAM_FAILED` state. |

### Quick start

```json
{
  "companies": [
    { "domain": "example.com", "companyName": "Example Ltd", "externalId": "crm-001" }
  ],
  "maxCompanies": 25,
  "maxPagesPerCompany": 3,
  "includePublishedContacts": true,
  "includeTechnologySignals": true,
  "requestTimeoutSecs": 20,
  "useApifyUnblockerFallback": true,
  "preferApifyUnblocker": false
}
```

The Actor inspects the homepage and, when requested, the fixed public `/about` and `/contact` routes. By default it uses direct HTTPS first, retries only transient failures once, and can make one Apify Unblocker attempt after a classified block or transient failure. Set `preferApifyUnblocker` only for a domain already known to block cloud traffic; if that preferred attempt is temporarily unavailable, the Actor makes one direct recovery attempt. Every redirect is revalidated as a public HTTP(S) destination and response HTML is size-capped. This bounded approach keeps the source set concise and reviewable.

Example output shape:

```json
{
  "externalId": "crm-001",
  "inputDomain": "example.com",
  "normalizedDomain": "example.com",
  "companyName": "Example Ltd",
  "description": "A public company description.",
  "foundedYear": "2012",
  "address": "123 Example Street, New York, NY",
  "publishedEmails": ["hello@example.com"],
  "technologySignals": ["HubSpot"],
  "sourceUrls": ["https://example.com/", "https://example.com/contact"],
  "fetchRoutes": ["direct"],
  "collectionOutcome": "ENRICHED",
  "collectedAt": "<ISO-8601 timestamp>"
}
```

### How this bounded workflow compares with ZoomInfo

This independent Actor can replace the narrow company-website research/export step after you have selected the accounts. ZoomInfo serves buyers who want a broader sales suite with proprietary company/contact data, buyer-intent and visitor signals, CRM integrations, team workflows, verification operations, and outreach features.

| Decision | This Actor | ZoomInfo | Best fit |
| --- | --- | --- | --- |
| Starting point | A caller-supplied company domain | Broad sales-intelligence suite | Use this Actor when your account list already exists. |
| Sources | Public pages fetched from the company’s own website | Broader product data and signals | Use this Actor when page-level provenance matters. |
| Output contract | Structured fields, source URLs, timestamps, explicit nulls, and warnings | Broader product functionality | Use ZoomInfo for suite-level data and workflows. |
| Effective efficiency | One bounded, reviewable record per supplied domain with field-level provenance | The broader suite supports a wider product workflow | Compare usable records and active operator time for the same selected-domain job. |
| Integration context | API and dataset readback are part of the planned private release check | Product integrations depend on the selected ZoomInfo plan | Select the route whose verified integration matches your workflow. |
| Billing context | Pay per event plus platform usage; see the Pricing tab for current rates. | Same-job pricing requires current plan terms | Compare only the same records, volume, and current plan terms. |

ZoomInfo is a trademark of its owner. This independent Actor is not affiliated with, associated with, or endorsed by ZoomInfo.

### When not to use this Actor

Do not use this Actor when the job starts with a person name, job title, market segment, private contact request, buyer-intent query, or outreach campaign instead of a known company domain. Those jobs are outside this Actor’s contract. Use it when the selected account list and authorized public-website research boundary are already clear.

### API usage

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('khadinakbar/zoominfo-alternative').call({
  companies: [{ domain: 'example.com', externalId: 'crm-001' }],
  maxCompanies: 1
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### AI-agent prompt

> Enrich these caller-selected company domains from their own public websites. Return the terminal run outcome, every dataset row, source URLs, field sources, collection time, and warnings. Keep an empty public contact field empty and preserve its explicit result state.

An agent should read `OUTPUT` and `RUN_SUMMARY` after the dataset, preserve `externalId` as its join key, and branch on `COMPLETE`, `PARTIAL`, `VALID_EMPTY`, `INVALID_INPUT`, `UPSTREAM_FAILED`, or `CONFIG_ERROR`. It should retain warnings instead of treating an empty contact field as a failure. Apify MCP setup is available at [mcp.apify.com](https://mcp.apify.com); client-specific compatibility requires a separate verified invocation.

### Limitations and troubleshooting

- A domain can publish little structured metadata even when its pages are reachable; review `VALID_EMPTY`, empty fields, and `sourceUrls` rather than inferring missing data.
- A temporary site block, timeout, DNS failure, or unavailable `/about` route appears in `warnings`. The Actor retries transient direct failures once and, when enabled, makes one Apify Unblocker recovery attempt.
- If platform usage is the priority, disable `useApifyUnblockerFallback`. If a domain is already known to block cloud traffic, keep fallback enabled and set `preferApifyUnblocker`; inspect `fetchRoutes` plus `RUN_SUMMARY.routes` either way.
- Login-only pages, arbitrary crawling, browser-rendered content, private profiles, email guessing, contact verification, and outreach are outside this bounded workflow.

### Provenance and freshness

Every completed record carries `sourceUrls`, per-field sources, transport route, and `collectedAt`. Release evidence for the exact private build is maintained separately from public marketing copy and includes cloud datasets, terminal records, and charge reconciliation. Website observations are point-in-time evidence, so use `collectedAt` and rerun when freshness matters.

### Best results

- Supply canonical company domains as the strongest starting input for website evidence.
- Keep `maxPagesPerCompany` at the default three pages to preserve a clear source boundary.
- Keep Apify Unblocker enabled when reachability matters; turn it off when minimizing platform usage is more important than recovering blocked pages.
- Use `fieldSources` and `collectedAt` when reviewing a CRM update or a stale field.
- Treat published contacts as public website observations within your authorized review process.

### Builder's note

I built this Actor around provenance over volume. Every website-derived result names the public pages that support it, and an unavailable field stays explicit. My goal is to make the output easy to review and refresh as a website-evidence record.

### Responsible use

Use company data you are authorized to process. Respect applicable privacy laws, website terms, opt-outs, and your organization’s communication policy. This Actor collects a bounded set of public company pages for research and review.

### Pricing and run costs

This Actor uses **Pay per event plus Apify platform usage**. The [Pricing tab](https://apify.com/khadinakbar/zoominfo-alternative/pricing) lists the current event rates and billing terms.

| Event | Billing unit | When it applies |
|---|---|---|
| `apify-actor-start` | Actor Start | Charged when the Actor starts running. Number of events charged depends on Actor memory (one event per GB, minimum one event). |
| `company-enriched` | Source-cited company enrichment | Charged after one supplied company domain has at least one public page fetched and one complete, schema-valid result record persisted. Invalid inputs and fully unavailable website routes are not charged. |

Run cost combines the charged events and Apify platform usage. Review the run charge limit and requested result count before starting.

# Actor input Schema

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

One to 100 companies already selected by you, each with a public website domain such as example.com. Optional companyName and externalId are carried into the result to make CRM matching auditable. This is not a free-text people search, a request to discover contacts, or an authorization to send outreach.

## `maxCompanies` (type: `integer`):

Hard cap on distinct valid company domains processed in this run. Defaults to 25 and accepts 1 to 100, limiting maximum company-enriched event charges to $0.05 per processed company plus platform usage. This is a company-list cap, not a web crawl depth setting.

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

How many standard public pages to inspect for each supplied domain: the homepage, then optional /about and /contact routes. Defaults to 3 and accepts 1 to 3, keeping collection bounded and source URLs reviewable. This does not crawl the public web, customer portals, or login-protected pages.

## `includePublishedContacts` (type: `boolean`):

Return business emails and telephone links visibly published on the company pages that were fetched. Defaults to true and preserves the exact source URLs for review. It does not guess email patterns, unmask protected data, validate mailbox ownership, or return private contact data.

## `includeTechnologySignals` (type: `boolean`):

Return a small list of named technologies whose public asset or script signatures were observed in fetched HTML. Defaults to true and labels each result as an observed website signal rather than a complete technology inventory. It does not infer subscriptions, spending, or buyer intent.

## `requestTimeoutSecs` (type: `integer`):

Maximum wait for each direct or fallback public-page request. Defaults to 20 seconds and accepts 5 to 60. Transient direct failures receive one bounded retry; this setting does not extend the overall Actor timeout.

## `useApifyUnblockerFallback` (type: `boolean`):

After direct requests are clearly blocked or transiently unavailable, try the same public page once through Apify Unblocker. Defaults to true for higher reachability. Unblocker is Apify platform usage paid by the caller, not a third-party API subscription; disable it for a direct-only control run.

## `preferApifyUnblocker` (type: `boolean`):

Send each configured public page through Apify Unblocker first. If that one attempt is temporarily unavailable, the Actor makes one direct recovery attempt. Defaults to false. Use this higher-platform-usage mode only for domains you already know block cloud traffic; it requires Use Apify Unblocker fallback to remain enabled.

## Actor input object example

```json
{
  "companies": [
    {
      "domain": "example.com",
      "companyName": "Example Ltd",
      "externalId": "crm-001"
    }
  ],
  "maxCompanies": 25,
  "maxPagesPerCompany": 3,
  "includePublishedContacts": true,
  "includeTechnologySignals": true,
  "requestTimeoutSecs": 20,
  "useApifyUnblockerFallback": true,
  "preferApifyUnblocker": false
}
```

# Actor output Schema

## `companies` (type: `string`):

One complete record per submitted company, including explicit collection outcome and source URLs.

## `compactOutput` (type: `string`):

Terminal outcome, counts, warnings, and charged company-enriched events.

## `runSummary` (type: `string`):

Detailed collection, validation, and billing diagnostics.

# 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": [
        {
            "domain": "example.com",
            "companyName": "Example Ltd",
            "externalId": "crm-001"
        }
    ],
    "maxCompanies": 25,
    "maxPagesPerCompany": 3,
    "includePublishedContacts": true,
    "includeTechnologySignals": true,
    "requestTimeoutSecs": 20,
    "useApifyUnblockerFallback": true,
    "preferApifyUnblocker": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/zoominfo-alternative").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": [{
            "domain": "example.com",
            "companyName": "Example Ltd",
            "externalId": "crm-001",
        }],
    "maxCompanies": 25,
    "maxPagesPerCompany": 3,
    "includePublishedContacts": True,
    "includeTechnologySignals": True,
    "requestTimeoutSecs": 20,
    "useApifyUnblockerFallback": True,
    "preferApifyUnblocker": False,
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/zoominfo-alternative").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": [
    {
      "domain": "example.com",
      "companyName": "Example Ltd",
      "externalId": "crm-001"
    }
  ],
  "maxCompanies": 25,
  "maxPagesPerCompany": 3,
  "includePublishedContacts": true,
  "includeTechnologySignals": true,
  "requestTimeoutSecs": 20,
  "useApifyUnblockerFallback": true,
  "preferApifyUnblocker": false
}' |
apify call khadinakbar/zoominfo-alternative --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,khadinakbar/zoominfo-alternative"
        }
    }
}

```

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/Y6fgJKtKB3iDq1wbO/builds/Kh9cGQUNR0LOgYXk6/openapi.json
