# Company Enrichment – Firmographics, Socials & Hiring (`pinkish_armada/company-enrichment`) Actor

Turn company domains into clean rows: name, description, address, company emails and phones (role-based only), social pages, VAT/ABN/company IDs, and a live hiring signal from Greenhouse, Lever, Ashby & more. No personal data. $3 per 1k.

- **URL**: https://apify.com/pinkish_armada/company-enrichment.md
- **Developed by:** [Phuc Tiet](https://apify.com/pinkish_armada) (community)
- **Categories:** Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 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.

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

## Company Enrichment from Domain: website firmographics, contacts, socials & hiring signal

**Give it a list of company domains and get one clean row per company**, built from the company's **own website** and its **public job board**:

- 🏢 **Company:** name, legal name, description, logo URL, language, founding year, employee count (when published)
- 📍 **Location:** full address, street, city, region, postcode, country and country code (from schema.org data, or the country TLD)
- ✉️ **Company contacts:** **role-based emails only** (`info@`, `sales@`, `support@`, `press@`…), company phone numbers, contact page URL
- 🔗 **Social pages:** LinkedIn company page, X/Twitter, Facebook, Instagram, YouTube, TikTok, GitHub, Crunchbase
- 🧾 **Registration IDs** printed on the site: **VAT**, **ABN/ACN** (Australia), **NZBN**, **UK company number**, German **HRB/HRA**, French **SIREN**, Dutch **KvK**, Indian **CIN**
- 💼 **Hiring signal:** is the company hiring, which **ATS** it uses (Greenhouse, Lever, Ashby, SmartRecruiters, Workable), the job-board URL and the **number of open jobs**, read live from the ATS's public API
- 📄 Useful URLs: contact, about, careers, imprint/legal and privacy pages

It's ideal for **lead enrichment, CRM hygiene, account research, sales prioritisation** (hiring = budget), market mapping and AI agents that need facts about a company.

### Why this one?

- **No personal data by design.** Only company-level information. Emails that look personal (`jane.doe@`) are discarded, never stored. LinkedIn **personal** profiles (`/in/…`) are ignored. No people's names are collected. That keeps you on the safe side of GDPR and the Australian Privacy Act.
- **Hiring signal included.** No other enrichment Actor tells you how many jobs a company has open right now, with the job-board link. Pair it with **[ATS Jobs Scraper](https://apify.com/pinkish_armada/ats-jobs-scraper)** to pull the actual job posts.
- **Polite and fast.** Up to 4 pages per domain (homepage + contact, imprint, about/careers), plain HTTP (no browser), robots.txt respected, timeouts and retries.
- **Cheap: $3 per 1,000 companies.** Unreachable, blocked and invalid domains are **free**.

### How to use

1. Paste domains (or website URLs, or work emails; only the domain is used) into **Company domains or websites**.
2. Click **Start**.
3. Export as CSV, Excel or JSON, or connect to your CRM with Make, Zapier, n8n or the Apify API.

#### Input example

```json
{
  "domains": ["stripe.com", "buffer.com", "aussiebroadband.com.au", "hetzner.com"],
  "detectHiring": true,
  "maxPagesPerDomain": 4
}
```

#### Output example

```json
{
  "input": "hetzner.com",
  "domain": "hetzner.com",
  "website": "https://www.hetzner.com/",
  "status": "ok",
  "companyName": "Hetzner Online GmbH",
  "description": "Dedicated Server, Cloud, Storage & Hosting ...",
  "logoUrl": "https://www.hetzner.com/...png",
  "language": "en",
  "country": "Germany",
  "countryCode": "DE",
  "primaryEmail": "info@hetzner.com",
  "emails": ["info@hetzner.com"],
  "primaryPhone": "004998315050",
  "phones": ["004998315050"],
  "linkedinUrl": "https://www.linkedin.com/company/hetzner-online",
  "registrationIds": { "vat": "DE812871812", "commercialRegister": "HRB 6089" },
  "contactPageUrl": "https://www.hetzner.com/...",
  "imprintPageUrl": "https://www.hetzner.com/legal/legal-notice",
  "isHiring": true,
  "hiringPlatform": "greenhouse",
  "hiringBoardUrl": "https://job-boards.greenhouse.io/...",
  "openJobsCount": 12,
  "hiringDetectedVia": "website",
  "hiringMatchConfidence": "high",
  "pagesScanned": ["https://www.hetzner.com/", "..."],
  "scrapedAt": "2026-10-07T00:00:00.000Z"
}
```

(Values are illustrative. Each field is `null` when the website doesn't publish it.)

Dataset views: **Companies** (overview), **Contacts & social**, **Hiring signal**, **All fields**.

### Output fields

| Field | Description |
|---|---|
| `domain`, `website`, `status`, `error` | Domain after redirects (e.g. `notion.so` → `notion.com`; compare with `input` to spot rebrands and parked domains), final homepage URL, `ok` / `unreachable` / `blocked_by_robots` / `invalid_input` |
| `companyName`, `legalName`, `description`, `logoUrl`, `language`, `foundingYear`, `employees` | Company profile from schema.org JSON-LD, Open Graph and meta tags |
| `addressFull`, `street`, `city`, `region`, `postalCode`, `country`, `countryCode` | Published address (country falls back to the ccTLD, e.g. `.com.au` → Australia) |
| `primaryEmail`, `emails` | Role-based company mailboxes on the company's own domain |
| `primaryPhone`, `phones` | Numbers published as `tel:` links or in schema.org data |
| `linkedinUrl` … `crunchbaseUrl` | Company social profiles |
| `registrationIds` | VAT, ABN, ACN, NZBN, UK company number, HRB/HRA, SIREN, KvK, CIN, when printed on the site |
| `contactPageUrl`, `aboutPageUrl`, `careersPageUrl`, `imprintPageUrl`, `privacyPolicyUrl` | Key pages |
| `isHiring`, `openJobsCount`, `hiringPlatform`, `hiringBoardUrl`, `hiringDetectedVia`, `hiringMatchConfidence` | Live hiring signal from the public ATS API. `hiringDetectedVia`: `website` (board linked on the company's site), `name-match-verified` (board with the same company name that links back to this domain), `name-match` (same company name, no contrary evidence; confidence `medium`), `careers-page-only` (careers page found but no supported ATS) |
| `pagesScanned`, `scrapedAt` | Audit trail |

### Pricing

**$3.00 per 1,000 companies enriched** ($0.003 each, pay per event), plus Apify's tiny per-run start fee. You're charged only for domains whose homepage was fetched. Unreachable, robots.txt-blocked and invalid inputs appear in the dataset with an error and are free. Set a maximum cost per run and the Actor stops cleanly at the limit.

### FAQ

**Where does the data come from?** Only the company's own public web pages (respecting robots.txt) and the public job-board APIs of Greenhouse, Lever, Ashby, SmartRecruiters and Workable. No LinkedIn scraping (we only read the LinkedIn link the company puts on its own site), no data brokers.

**Why no names or personal emails?** By design. Many enrichment tools harvest employees' personal data, which creates legal risk for you. This Actor sticks to company-level facts. It's best for account-level enrichment; use your own compliant process for contact-level data.

**Why is a field empty?** The website doesn't publish it, or the page is rendered only by JavaScript (this Actor doesn't run a browser, which keeps it fast and cheap).

**How accurate is the hiring signal?** When the job board is linked from the website, it's exact. Otherwise a board is only accepted when the ATS reports the same company name **and** has open jobs, and boards whose job links point to a different company's website are rejected (e.g. a "Ghost" board belonging to another company named Ghost). `hiringMatchConfidence` tells you which case you got. `careers-page-only` means the company has a careers page but uses an ATS we don't read (e.g. Workday) or a custom page.

**Related tools:** [ATS Jobs Scraper](https://apify.com/pinkish_armada/ats-jobs-scraper) (pull the actual job posts), [Website Tech Stack Detector](https://apify.com/pinkish_armada/tech-stack-detector) (technologies), [Domain Lookup](https://apify.com/pinkish_armada/domain-intel) (WHOIS/RDAP, DNS, SPF/DMARC, SSL).

# Actor input Schema

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

One per line: <code>stripe.com</code>, <code>https://www.example.com.au</code>, or a work email (only its domain is used; the address itself is never stored).

## `detectHiring` (type: `boolean`):

Find the company's job board (Greenhouse, Lever, Ashby, SmartRecruiters, Workable) from its website or careers page and return the number of open jobs via the platform's public API.

## `guessHiringBoardByName` (type: `boolean`):

If no job board is linked on the site, look up a board with the same name. A guessed board is only accepted when the ATS confirms the company name, which avoids false matches.

## `maxPagesPerDomain` (type: `integer`):

Homepage plus contact, imprint/legal, about and careers pages (whichever exist). More pages find more contact details; 1 = homepage only (fastest).

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

Domains processed in parallel.

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

Per request; one retry on network errors.

## Actor input object example

```json
{
  "domains": [
    "stripe.com",
    "buffer.com",
    "aussiebroadband.com.au",
    "hetzner.com"
  ],
  "detectHiring": true,
  "guessHiringBoardByName": true,
  "maxPagesPerDomain": 4,
  "maxConcurrency": 10,
  "requestTimeoutSecs": 20
}
```

# Actor output Schema

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

Enriched companies (failed/invalid inputs are listed with status and error, not charged).

## `summary` (type: `string`):

Counts of enriched, failed and invalid inputs and hiring companies.

# 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",
        "buffer.com",
        "aussiebroadband.com.au",
        "hetzner.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("pinkish_armada/company-enrichment").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",
        "buffer.com",
        "aussiebroadband.com.au",
        "hetzner.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("pinkish_armada/company-enrichment").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",
    "buffer.com",
    "aussiebroadband.com.au",
    "hetzner.com"
  ]
}' |
apify call pinkish_armada/company-enrichment --silent --output-dataset

```

## MCP server setup

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

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/VWryVZsdNSlNiOun1/builds/QiLNKFwWdoFuZq93p/openapi.json
