# Hiring Intent Contacts: Companies Hiring Now + Emails (`cleanrowdata/hiring-intent-contacts`) Actor

Companies hiring right now from 17,000+ career sites, enriched with public website emails (contact@, sales@, hello@…). Pay only when a company has ≥1 usable contact. No paid databases.

- **URL**: https://apify.com/cleanrowdata/hiring-intent-contacts.md
- **Developed by:** [Clean Row Data](https://apify.com/cleanrowdata) (community)
- **Categories:** Lead generation, Jobs, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $21.00 / 1,000 company with contacts

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

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

## What's an Apify Actor?

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

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

## How to integrate an Actor?

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

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

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

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

# README

### Hiring Intent Contacts: companies hiring now + public emails

**Turn hiring signals into outreach-ready leads.** For each company that is hiring right now (from CleanRow's hourly index of **17,000+ career sites**), this Actor scrapes the company's own website for public emails — `contact@`, `sales@`, `hello@`, `careers@`, `info@` and other role inboxes — and returns one row per company with **≥1 usable contact**.

Chain it after [Hiring Signals API](https://apify.com/cleanrowdata/hiring-signals-api) or paste domains directly. **No paid contact databases, no paid proxies, no phone APIs.** v0 = public website contacts only. Pattern + SMTP personal emails are on the roadmap (v0.1).

**Price: $30 per 1,000 companies with a contact** ($0.03 each). **Misses are free.** Platform compute is billed as usual by Apify.

#### Why this exists

Hiring is buying intent. A company that just opened 5 sales roles needs tools, agencies and talent — but a company row without an email is still a research chore. This Actor closes that gap with emails the company already publishes.

#### What you get

| Field | Meaning |
|---|---|
| `company`, `domain`, `ats`, `careers_url` | Who they are and where they hire |
| `hiring_signal`, `new_jobs`, `sample_jobs` | Evidence for personalized outreach |
| `contacts[]` | `{email, type: "public_site", source_url}` |
| `contact_count` | How many emails we kept (capped) |

#### Quick start

**A) Hiring filters (same shape as Hiring Signals API):**

```json
{
  "timeRange": "7d",
  "jobFunctions": ["sales"],
  "locationSearch": ["United States"],
  "minNewJobs": 2,
  "limit": 10,
  "maxContactsPerCompany": 3
}
```

**B) Paste domains you already have:**

```json
{
  "companyDomains": ["stripe.com", "notion.so", "shopify.com"],
  "maxContactsPerCompany": 3
}
```

#### Pricing (pay per event)

| Event | Price | When |
|---|---|---|
| `company_with_contact` | **$0.03** | Company row pushed with ≥1 usable public email |
| Misses (no email / no domain) | **$0** | Not pushed (default) |
| `apify-actor-start` | Apify default | Run start |

#### Quality notes (v0)

- Sources: homepage, `/contact`, `/about`, `/careers` and a few variants.
- Filters freewebmail (gmail/yahoo/…) and noreply / newsletter addresses.
- Prefers role inboxes useful for sales outreach.
- Polite concurrency, identifiable User-Agent, junk TLD skipped.
- **Confirmed domains only.** The website must be confirmed before we scrape it: the company's ATS board links or redirects to it (Greenhouse/Ashby/Lever), or the site links back to the company's ATS board, or its title matches the full company name. Unconfirmed → no email (misses are free). Emails are kept only on the confirmed domain; template/placeholder addresses (example.com, mysite.com, noreply, Sentry/Wix) are dropped. Recruiter titles don't count as matching roles unless you search for recruiters.
- **`limit` = companies returned.** The Actor keeps checking matching companies until it has `limit` rows with a contact (or runs out of matches), so `limit: 5` returns up to 5. The run summary says why it stopped.
- **Sales means B2B sales.** In-store retail roles (sales associate, cashier, stylist, keyholder, store manager) are the separate `retail` function; pick it (or put the title in `titleSearch`) to include them.

#### Integrations (n8n, Make, Zapier, Clay, AI agents)

Every integration calls the same Apify API, so the price is the same everywhere (pay per company with a contact; misses are free).

- **Any HTTP client / Clay HTTP API column**: `POST https://api.apify.com/v2/acts/cleanrowdata~hiring-intent-contacts/run-sync-get-dataset-items` with header `Authorization: Bearer <APIFY_TOKEN>` and a JSON body like:
  ```json
  {"companyDomains": ["{{domain}}"], "maxContactsPerCompany": 3}
  ```
  The response is the dataset rows. In Clay, call it from an HTTP API column and use it as one step of a waterfall.
- **n8n**: use the Apify node (verified community node) to run Actor `cleanrowdata/hiring-intent-contacts`, or an HTTP Request node with the call above.
- **Make**: Apify *Run an Actor* module, then *Get Dataset Items*. **Zapier**: Apify *Run Actor* action, then *Fetch dataset items*.
- **AI agents (Claude, Cursor, ChatGPT and others) via the Apify MCP server**: connect `https://mcp.apify.com?tools=cleanrowdata/hiring-intent-contacts` and ask, e.g. "Find US companies hiring sales roles this week and their public contact emails".

#### Chain with other CleanRow Actors

1. [Hiring Signals API](https://apify.com/cleanrowdata/hiring-signals-api) → companies hiring now
2. **This Actor** → add public emails
3. [Work Email Finder](https://apify.com/cleanrowdata/work-email-finder) → personal work emails from name + domain (v0 SMTP)

If this saved you time, a quick review on the Store helps a lot, and feature requests go in the Issues tab; we usually ship them within days.

#### Legal / compliance

Only collects emails publicly published on the company's own site. You are responsible for lawful outreach (CAN-SPAM, CASL, GDPR, etc.).

# Changelog

This Actor's version history is a separate document: https://apify.com/cleanrowdata/hiring-intent-contacts/changelog.md

# Actor input Schema

## `timeRange` (type: `string`):

Used when discovering companies from the hiring index (ignored if companyDomains is set).

## `jobFunctions` (type: `array`):

Only companies hiring these functions (from the CleanRow index). Empty = all. In-store retail roles (sales associate, cashier, stylist, keyholder, store manager) count as Retail, not Sales.

## `locationSearch` (type: `array`):

Only jobs whose location contains any of these. E.g. United States, Remote.

## `minNewJobs` (type: `integer`):

Only companies with at least this many new matching jobs in the window.

## `limit` (type: `integer`):

Maximum companies returned (and charged for). The Actor keeps checking matching companies until it has this many with a contact or runs out of matches. Misses are free.

## `maxContactsPerCompany` (type: `integer`):

Cap on public emails kept per company (role inboxes preferred).

## `companyDomains` (type: `array`):

If set, scrape these domains directly instead of querying the hiring index. E.g. stripe.com, notion.so.

## `companyNames` (type: `array`):

Optional display names aligned by index with companyDomains.

## `titleSearch` (type: `array`):

Hiring-index filter: only jobs whose title contains any of these.

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

Hiring-index filter on company / board name.

## `ats` (type: `array`):

Limit hiring discovery to these ATS boards.

## `excludeStaffingAgencies` (type: `boolean`):

Skip companies that look like staffing / recruiting agencies.

## `concurrency` (type: `integer`):

Parallel website fetches. Keep low to stay polite.

## `sampleJobsPerCompany` (type: `integer`):

Newest matching jobs included as evidence for outreach (free).

## `hiringSignalsDatasetId` (type: `string`):

Optional: Apify dataset ID from a prior cleanrowdata/hiring-signals-api run. Uses company / careers_url / ats from those rows (skips rediscovery). Prefer this over re-running the same filters when you already have a signals export.

## Actor input object example

```json
{
  "timeRange": "7d",
  "jobFunctions": [
    "sales"
  ],
  "locationSearch": [
    "United States"
  ],
  "minNewJobs": 2,
  "limit": 10,
  "maxContactsPerCompany": 3,
  "excludeStaffingAgencies": true,
  "concurrency": 6,
  "sampleJobsPerCompany": 3
}
```

# Actor output Schema

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

One row per company that has ≥1 public-site email.

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

Contacts found, misses, fetch stats, index freshness.

# 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 = {
    "timeRange": "7d",
    "jobFunctions": [
        "sales"
    ],
    "locationSearch": [
        "United States"
    ],
    "minNewJobs": 2,
    "limit": 10,
    "maxContactsPerCompany": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("cleanrowdata/hiring-intent-contacts").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 = {
    "timeRange": "7d",
    "jobFunctions": ["sales"],
    "locationSearch": ["United States"],
    "minNewJobs": 2,
    "limit": 10,
    "maxContactsPerCompany": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("cleanrowdata/hiring-intent-contacts").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 '{
  "timeRange": "7d",
  "jobFunctions": [
    "sales"
  ],
  "locationSearch": [
    "United States"
  ],
  "minNewJobs": 2,
  "limit": 10,
  "maxContactsPerCompany": 3
}' |
apify call cleanrowdata/hiring-intent-contacts --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,cleanrowdata/hiring-intent-contacts"
        }
    }
}
```

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/jDVPyWu3MZUiFsMgy/builds/YVCeMAgBQKFr2FDaY/openapi.json
