# Company Hiring Signals: Hiring Score, No LinkedIn Data (`conserving_celerytop/company-hiring-signals`) Actor

$0.045 per company. One row of hiring signals for each company you give: a 0 to 100 hiring score, open jobs, jobs posted in the last 7 and 30 days, job age, top teams and locations, leadership and first hires. Read live from its career page. A domain in, one row out, for Clay or a sheet. No login.

- **URL**: https://apify.com/conserving\_celerytop/company-hiring-signals.md
- **Developed by:** [Don Mangu](https://apify.com/conserving_celerytop) (community)
- **Categories:** Jobs, Lead generation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $50.00 / 1,000 companies

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

**Company Hiring Signals gives you one row of hiring signals for each company you name, read live from its career page when you run it.** You get a 0 to 100 hiring score, open jobs, jobs posted in the last 7 and 30 days, how old the open jobs are, the top departments and locations, the job function and seniority mix, and open leadership and first-hire roles. $0.045 per company, whatever the size of its job board. No API key or login. No personal data.

Every field is a number or plain text, with no lists or nested objects, so one company in gives one row out. That fits a Clay column, a Google Sheet or a CSV file. Give a company website such as `stripe.com`, a job board link, or a plain company name.

- **Sales and RevOps teams** score an account list by how actively each company hires, and find accounts that just opened sales, data or leadership roles.
- **Recruiters and agencies** see which target companies are growing and in which teams and places.
- **Investors and analysts** track hiring at portfolio and peer companies week by week.

**Try it now.** Click **Try for free** and create a free Apify account, no credit card needed. The form is filled in with stripe.com (Greenhouse), ramp.com (Ashby), notion.so (Ashby), figma.com (Greenhouse) and linear.app (Ashby). Click **Start** to get 5 rows for $0.225 in a few seconds.

### Use it in Clay: a domain in, one row out

1. In Clay, connect your Apify account once in **Settings > Connections** (Apify, with your Apify API token).

2. In your table, click **Add enrichment**, search for **Run Apify Actor** and pick `conserving_celerytop/company-hiring-signals`.

3. Enter the input with your domain column inserted where `/Domain` is. Keep the key in quotes, not the column token:

   ```
   {"companies": [/Domain]}
   ```

4. Run one row first and check it. Then click the result cell, hover over a field such as `hiringScore`, and click **Add as column**.

The result is the run's dataset: one row for that domain. A company is charged once per run, also when its board is empty or not found, so keep Clay's **Autoupdate** off until one row works. Clay counts the call as an action on your own Apify key, with no Clay data credits.

For one call per table instead of one per row, paste up to 500 domains into **Companies** in Apify Console, or send them through the Apify API, and import the dataset.

### What you get

One row per company, in this order. An example row from a run on 2026-09-26:

```json
{
  "rowType": "company",
  "company": "notion.so",
  "companyName": null,
  "companyDomain": "notion.so",
  "ats": "ashby",
  "boardUrl": "https://jobs.ashbyhq.com/notion",
  "matchedBy": "name",
  "companyStatus": "ok",
  "hiringScore": 98,
  "openJobs": 128,
  "jobsPostedLast7Days": 9,
  "jobsPostedLast30Days": 26,
  "newestPostedAt": "2026-09-25T13:40:48.475Z",
  "oldestOpenJobDays": 427,
  "medianJobAgeDays": 52,
  "topDepartmentsText": "Sales (41); Engineering (16); Outcomes Architect (14); People (11); Marketing (10)",
  "topLocationsText": "San Francisco, California (59); New York, New York (16); Dublin, Ireland (15); Tokyo, Japan (15); Paris, France (6)",
  "jobFunctionMix": "sales 27%, engineering 20%, customer_success 13%, marketing 9%, people_hr 8%, operations 7%, it_security 5%, finance 3%, design 2%, data 2%, education 2%, legal 2%, other 1%, product 1%",
  "seniorityMix": "lead_manager 22%, entry 3%, intern 3%, director 2%, senior 1%",
  "remoteShare": 0,
  "salaryCoverage": 0,
  "leadershipRolesText": "Head of Demand Engine; Head of Early Career Recruiting",
  "firstHireRolesText": "",
  "toolsNamed": null,
  "newJobs": null,
  "closedJobs": null,
  "previousCheckAt": null,
  "charged": true,
  "chargedEvent": "company-lookup",
  "warning": null,
  "error": null,
  "fetchedAt": "2026-09-26T16:49:18.595Z"
}
```

| Field | What it holds |
|---|---|
| `company` | The entry as you gave it |
| `companyName` | The company name the job board gives, when it gives one |
| `companyDomain` | The website you gave, else the domain most of its job links use |
| `ats` | The job board system, such as greenhouse, lever or ashby |
| `boardUrl` | The job board the numbers come from |
| `matchedBy` | How the board was found: link, website, directory, name or name variant |
| `companyStatus` | Read this first. `ok` means jobs were read. See [Statuses and charges](#statuses-and-charges) |
| `hiringScore` | 0 to 100, see [How the hiring score works](#how-the-hiring-score-works) |
| `openJobs` | Open jobs that pass your filters |
| `jobsPostedLast7Days` | Of those, jobs posted in the last 7 days |
| `jobsPostedLast30Days` | Of those, jobs posted in the last 30 days |
| `newestPostedAt` | Posting date of the newest job |
| `oldestOpenJobDays` | Days since the oldest open job was posted |
| `medianJobAgeDays` | Median days since the open jobs were posted |
| `topDepartmentsText` | Up to 5 departments with the most jobs, with counts |
| `topLocationsText` | Up to 5 locations with the most jobs, with counts |
| `jobFunctionMix` | Share of open jobs per job function, such as sales or engineering |
| `seniorityMix` | Share of open jobs per level read from the title. Titles with no level are not counted, so the shares can add up to less than 100% |
| `remoteShare` | Share of jobs that can be done fully remote, 0 to 1 |
| `salaryCoverage` | Share of jobs with a published salary, 0 to 1 |
| `leadershipRolesText` | Up to 5 open director, VP and C-level titles, newest first |
| `firstHireRolesText` | Up to 5 first or founding hire titles, newest first |
| `toolsNamed` | With **Include job description**: up to 15 tools the job posts name most, such as Python, Snowflake or Salesforce |
| `newJobs` | With **New and closed jobs**: how many jobs are new since the previous check |
| `closedJobs` | With **New and closed jobs**: how many jobs closed since the previous check |
| `previousCheckAt` | With **New and closed jobs**: time of the previous check |
| `charged` | true when this company was charged in this run |
| `chargedEvent` | The event charged: `company-lookup` or `new-jobs-check` |
| `warning` | What to double check, such as a plain name that may belong to another company |
| `error` | Why there are no numbers, when something went wrong |
| `fetchedAt` | When the lookup started |

A list is joined into one text, such as "Sales (41); Engineering (16)". An empty text means there are none, and null means the value is not known. The dataset view **Hiring signals** shows these columns, all but `chargedEvent` and `fetchedAt`. The COMPANIES record in the key-value store also has each company's status with `companyTotalOpenJobs` (all open jobs, before filters) and `companyMatchedJobs`.

### How the hiring score works

`hiringScore` adds three parts, 100 points at most:

| Part | Points | Full points at |
|---|---|---|
| Open jobs (`openJobs`) | 40 | 100 open jobs |
| Jobs posted in the last 30 days (`jobsPostedLast30Days`) | 40 | 30 jobs |
| Jobs posted in the last 7 days (`jobsPostedLast7Days`) | 20 | 10 jobs |

Each part is `points x min(1, log(1 + count) / log(1 + full))`, and the sum is rounded. The log makes the first jobs count most, so a small company that just started hiring does not score zero next to a large one:

- 1 open job, posted this week: 20.
- 10 open jobs, 3 of them posted this month and 1 this week: 43.
- 30 open jobs, 4 posted this month and none this week: 49.
- 100 or more open jobs, 30 or more posted this month and 10 or more this week: 100.

The counts use only the jobs that pass your filters, so with **Department** set to sales it is a score of sales hiring. It is null when the board gives no posting dates (HiringThing, Trakstar Hire, and Freshteam without **Include job description**) or the company could not be read.

### Input

The simplest input is a list of companies:

```json
{"companies": ["stripe.com", "ramp.com", "notion.so", "figma.com", "linear.app"]}
```

Every field:

```json
{
  "companies": ["stripe.com", "https://jobs.lever.co/palantir", "linear"],
  "companyLists": ["ai-companies"],
  "excludeCompanies": ["openai.com"],
  "department": "sales",
  "location": "United States",
  "postedSince": "90 days",
  "includeDescription": false,
  "onlyNewJobs": false,
  "monitorName": "default"
}
```

- **Companies** (`companies`): up to 500 per run. A website works when it links to its job board, a job board link always works, and a plain name works for many companies. A name can belong to another company with the same name: `warning` then says so.
- **Ready-made company lists** (`companyLists`): `ai-companies` (179), `tech-companies` (311), `remote-first` (90), `europe-tech` (65) and `startups` (250). Each company in a list costs the same as one you type.
- **Exclude companies** (`excludeCompanies`): names, websites or board links to leave out, not read and not charged.
- **Department**, **Location** and **Posted since** (`department`, `location`, `postedSince`): count only the jobs that match. The score and every count then describe those jobs.
- **Include job description** (`includeDescription`): adds `toolsNamed`, and first hires that only the job text mentions.
- **New and closed jobs since my last check** and **Monitor name** (`onlyNewJobs`, `monitorName`): see below.

### How much does it cost?

$0.045 per company, less on paid Apify plans, whatever the number of jobs on its board.

| Event | Price | When |
|---|---|---|
| Company (`company-lookup`) | $0.045 per company; $0.0428 on Starter, $0.0405 on Scale, $0.036 on Business | One row of signals, also when the board is empty, not found or fails |
| Repeat monitor check (`new-jobs-check`) | $0.002 per started 1,000 open jobs | A later check with **New and closed jobs** instead of `company-lookup` |
| Description block (`job-details`) | $0.01 per started 200 jobs | Only with **Include job description**, on JazzHR, Paylocity, Freshteam, JOIN, Polymer, Workday, Eightfold, ClearCompany, GoHire and HiringThing portals. Other boards include descriptions at no extra cost |

Invalid entries, boards we do not read, websites we cannot open and duplicates are free. 1,000 companies cost $45, or $36 on the Business plan. Apify's free plan gives $5 of credit a month, which covers about 110 companies. In a normal run, Apify platform usage is included.

### Weekly signals on a schedule

Turn on **New and closed jobs since my last check** and save the run as a task with a weekly or daily schedule. Each row then also has `newJobs` and `closedJobs` since the previous check, and `previousCheckAt`. The first check of a company costs $0.045, and each later check $0.002 per started 1,000 open jobs on its board. What you received is saved in your own Apify account, per **Monitor name** and set of filters, so use one monitor name per Clay table or list.

### Statuses and charges

| `companyStatus` | Meaning | Charged |
|---|---|---|
| `ok` | Jobs were read and match your filters | Yes |
| `no_matching_jobs` | Open jobs exist, but none match your filters | Yes |
| `no_open_jobs` | The board has no open jobs | Yes |
| `not_found` | No board was found under this name or link | Yes |
| `source_error` | The board failed or sent unreadable data | Yes |
| `no_job_board_found` | We read the website but found no job board | Yes |
| `website_unavailable` | We could not open the website | No |
| `unsupported_job_board` | A board we do not read, or a site that opts out. `error` says why | No |
| `invalid_input` | Not a link, website or name | No |
| `duplicate` | Another entry was the same board | No |
| `skipped_time_limit` | Time ran out before this company was read | No |
| `skipped_spending_limit` | Your spending limit could not cover this company | No |
| `internal_error` | Something failed on our side. `error` says what | Only if it happened after we read the job board |

Every company gets its row, also when it has no numbers, so your table keeps one row per company.

### FAQ

#### Is it legal to collect this data?

It reads only job postings that companies publish on public job boards for applicants, with no login, and it follows robots.txt on company websites and on Workday and Eightfold sites. It returns counts and job titles, never names, emails or phone numbers of people. It skips sites whose terms do not clearly allow this use. We cannot give legal advice, so check that your use follows the laws and terms that apply to you.

#### What are the limits?

Up to 500 companies per run, and up to 1,000 entries in **Exclude companies**. It reads 22 job boards, including Greenhouse, Lever, Ashby, Workday, Workable, Personio, Teamtailor and Recruitee. A company that posts jobs only on LinkedIn or Indeed, or on a board we do not read, has no numbers here. A website must link to its job board, else the name is tried, which can match another company with the same name. Boards without posting dates give null for the date fields and the score.

#### How fresh are the numbers?

As fresh as the company's job board when you run it. Each run reads the boards again, and `fetchedAt` says when.

#### How is this different from ATS Jobs API?

[ATS Jobs API](https://apify.com/conserving_celerytop/live-career-page-jobs-api) is the same reader with every option. It returns one row per job, or a summary with lists and objects per company, and it has more filters. Use it when you need the jobs themselves. This Actor returns only the flat hiring signals row, with a short form, for tables and CRMs.

#### Why is a company not found?

Its website may not link to its job board, or its name on the board differs. Paste the job board link instead, such as `https://jobs.ashbyhq.com/linear`. Open any job on the company's careers page to find it.

### Legal and trademarks

This Actor is not affiliated with or endorsed by Greenhouse, Lever, Ashby, Workday, Eightfold, Clay or any other company named here. Their names are trademarks of their owners. An employer or job board that wants us to stop reading its site can open an issue, and we add it to our blocklist.

### Support

Found a problem or need another field? Open an issue on the **Issues** tab. For the jobs themselves, use [ATS Jobs API](https://apify.com/conserving_celerytop/live-career-page-jobs-api).

# Actor input Schema

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

One company per line, up to 500. A company website such as stripe.com works when the site links to its job board, a job board link such as jobs.lever.co/palantir always works, and a plain name works for many companies. Each company gets one row of hiring signals for $0.06, however many jobs it has, also when no board is found.

## `companyLists` (type: `array`):

Add ready-made lists of companies, instead of or next to your own list. Each company in a list gets one row for $0.06. A company in two lists, or in a list and in Companies, is read and charged once. At most 500 companies per run in all. API value: a list such as \["ai-companies"].

## `excludeCompanies` (type: `array`):

Companies to leave out, such as your own customers or companies you already track: names, websites or job board links, up to 1,000. Most useful with Ready-made company lists. A company left out is not read and not charged. Leave empty to keep every company.

## `department` (type: `string`):

Count only jobs whose department, team or department path contains this text, ignoring case, for example sales. The hiring score and every count then describe those jobs. For several, put one per line. In API input, put a line break between values, as in "sales\nmarketing". Leave empty for all departments.

## `location` (type: `string`):

Count only jobs in this place, such as London, California or Germany. A country name or code keeps jobs in that country, and a US state or Canadian province keeps its region. For several, put one per line. In API input, put a line break between values. Leave empty for all places.

## `postedSince` (type: `string`):

Count only jobs posted on or after this date: a date as YYYY-MM-DD, such as 2026-09-01, or a period such as 90 days. Jobs whose board gives no posting date are then left out. Leave empty for all dates.

## `includeDescription` (type: `boolean`):

true: also read each job's description, to add toolsNamed (the tools the job posts name most, such as Python or Salesforce) and first hires that only the job text mentions. Free on most boards. $0.01 per started 200 jobs on JazzHR, Paylocity, Freshteam, JOIN, Polymer, Workday, Eightfold, ClearCompany, GoHire and HiringThing portals. Default false.

## `onlyNewJobs` (type: `boolean`):

true: each row also gets newJobs and closedJobs since your previous check of that company, and previousCheckAt. The first check of a company costs $0.06. A later check costs $0.002 per started 1,000 open jobs on its board. Use it with a weekly or daily schedule. What you received is saved in your own Apify account, per Monitor name and set of filters. Default false.

## `monitorName` (type: `string`):

Only used with New and closed jobs. Name of the saved state of your previous check, so separate tables or lists do not mix, for example clay-accounts. Letters, numbers, - and \_ only, up to 40 characters. Default: default.

## Actor input object example

```json
{
  "companies": [
    "stripe.com",
    "https://jobs.ashbyhq.com/linear",
    "notion"
  ],
  "excludeCompanies": [
    "openai",
    "stripe.com"
  ],
  "department": "engineering",
  "location": "London",
  "postedSince": "7 days",
  "includeDescription": false,
  "onlyNewJobs": false,
  "monitorName": "default"
}
```

# Actor output Schema

## `signals` (type: `string`):

Dataset items, one per company: company, companyDomain, companyStatus, hiringScore, openJobs, jobs posted in the last 7 and 30 days, newest posting, oldest and median job age, top departments and locations, job function and seniority mix, remote and salary shares, leadership and first-hire roles, tools with descriptions, and new and closed jobs with New and closed jobs.

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

JSON array, one object per company in input order: companyStatus, charged, chargedEvent, companyName, matchedBy, inputDomain and boardUrl, companyTotalOpenJobs (all open jobs, before filters), companyMatchedJobs, error and warning.

# 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": [
        "stripe.com",
        "ramp.com",
        "notion.so",
        "figma.com",
        "linear.app"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("conserving_celerytop/company-hiring-signals").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": [
        "stripe.com",
        "ramp.com",
        "notion.so",
        "figma.com",
        "linear.app",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("conserving_celerytop/company-hiring-signals").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": [
    "stripe.com",
    "ramp.com",
    "notion.so",
    "figma.com",
    "linear.app"
  ]
}' |
apify call conserving_celerytop/company-hiring-signals --silent --output-dataset

```

## MCP server setup

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

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/EtMMzaaVeV9XkyMgI/builds/6QW8tdTtcoT0oC3Ua/openapi.json
