# Hiring Signals: Companies Hiring by Role, Team & Location (`jtpalms/hiring-signals`) Actor

Find companies hiring right now, one row per company: open roles by team, seniority and location, roles posted in the last 7 and 30 days, pay and sample jobs. From a twice-daily index of 4,000+ company career sites. USD 8 per 1,000 companies.

- **URL**: https://apify.com/jtpalms/hiring-signals.md
- **Developed by:** [JT Palms](https://apify.com/jtpalms) (community)
- **Categories:** Lead generation, Jobs, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $6.40 / 1,000 company returneds

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 Signals: companies hiring by role, team and location

Find the companies that are hiring right now, one row per company. For each company you get its open roles grouped by team, seniority and location, how many were posted in the last 7 and 30 days, how many are leadership roles, the pay range when it is published, and links to its newest matching jobs.

The data comes from a job index rebuilt twice a day from the official public job-board APIs of company career sites: Greenhouse, Ashby, Lever, Workable, Recruitee, Personio, Breezy, Teamtailor, Gem and Pinpoint.

- **17,000+ companies and 390,000+ open roles at launch**, growing as more job boards are added.
- **USD 8 per 1,000 companies.** You pay only for companies in your results.

### What people use it for

- **Sales prospecting.** A company opening ten sales roles is buying sales tools. One hiring its first data engineers is about to buy a data stack. Filter by team, sort by recent postings, and reach them while the need is live.
- **Recruiting and staffing.** Find companies with many open roles in your specialty, and the careers page to start from.
- **Market and investment research.** Track which companies are growing which teams, and where.
- **Account prioritisation.** Run your target list through **Companies** and see who is hiring what this month.

### Sample output

A real row from a test run (Team: sales; two sample jobs; lists shortened):

```json
{
  "companyName": "Elastic",
  "companyWebsite": "elastic.co",
  "careersUrl": "https://job-boards.greenhouse.io/elastic",
  "ats": "greenhouse",
  "openJobs": 385,
  "matchingJobs": 105,
  "postedLast7Days": 21,
  "postedLast30Days": 51,
  "latestPostedAt": "2026-09-29T15:35:02.000Z",
  "leadershipRoles": 15,
  "remoteShare": 0,
  "byFunction": { "sales": 105 },
  "bySeniority": { "mid": 66, "senior": 19, "vp": 15, "staff-principal": 3, "manager": 2 },
  "topDepartments": [{ "department": "Sales - AMER West", "jobs": 12 }, { "department": "Sales - AMER MidMarket", "jobs": 8 }],
  "topLocations": [{ "location": "Barcelona, Spain", "jobs": 9 }, { "location": "United States", "jobs": 8 }],
  "jobsWithPay": 53,
  "payCurrency": "USD",
  "medianYearlyPayFrom": 113300,
  "signals": [
    "21 roles posted in the last 7 days",
    "105 of 385 open roles are in sales",
    "15 leadership roles (director and above)",
    "Pay published on 53 of 105 roles"
  ],
  "sampleJobs": [
    {
      "title": "Regional Vice President - Mid-Market East",
      "function": "sales",
      "seniority": "vp",
      "location": "Illinois, United States",
      "postedAt": "2026-09-28T17:36:30.000Z",
      "jobUrl": "https://jobs.elastic.co/jobs?gh_jid=8237605&gh_jid=8237605"
    }
  ]
}
```

What the fields mean:

- **`openJobs`** counts every open role at the company. **`matchingJobs`** counts only the roles that pass your filters, and every other count describes those.
- **`byFunction`** groups roles into teams read from the job title, with the department as a fallback: sales, customer success and support, data and AI, engineering, design, product, marketing, people and recruiting, legal, finance, healthcare, education, operations, trades and technicians, retail and hospitality, other.
- **`topCountries`** lists the countries of the matching roles, most first, read from each job's location ("Toronto, ON" counts as Canada). Place data from GeoNames (CC BY 4.0).
- **`bySeniority`** is also read from the title: intern, entry, mid, senior, lead, staff-principal, manager, director, vp, c-level. **`leadershipRoles`** counts director and above.
- **`companyWebsite`** is the company's own domain when its job links point there, or when the company was found from its website. It is empty otherwise.
- **`medianYearlyPayFrom`** is the median bottom of the published pay ranges, converted to a yearly figure, in the most common currency.
- **`openJobs7DaysAgo`**, **`openJobs30DaysAgo`**, **`netChange7Days`** and **`netChange30Days`** show how a company's open roles changed. They fill in as the index builds history (from October 2026) and stay empty until then.
- **`signals`** are plain statements of the numbers above, ready to paste into a CRM note.

### How to use it

1. Pick the **Teams hiring** you care about, for example Sales, or Data and AI. Leave it empty for all teams.
2. Narrow it if you want:
   - **Job title keywords**, for example `account executive` or `/data (engineer|scientist)/`;
   - **Countries**, for example Canada or Germany (matches "Toronto, ON" and "Munich" too);
   - **US states and Canadian provinces**, for example Texas or Ontario;
   - **Locations**, for text in the location, for example `Toronto` or `Remote`;
   - **Seniority**, **Remote only**, **Posted within (days)**, **Companies** or **Exclude companies**.
3. Set **Minimum matching roles**, for example 3 to find companies building a team rather than filling one seat.
4. Choose **Sort companies by**: most matching roles, most posted in the last 7 or 30 days, most leadership roles, most recent posting, or biggest growth in open roles.
5. Set **Max companies** and run. Export as CSV, JSON or Excel, or send it to Make, Zapier, n8n, Google Sheets or your CRM.

For a weekly prospect list, schedule it weekly with **Posted within (days)** set to 7 and sort by **Most roles posted in the last 7 days**.

### Pricing

| What | Price |
|---|---|
| Company in your results | USD 0.008 (USD 8 per 1,000). Lower on Apify's higher plans |
| Companies and roles removed by your filters | Free |

For example, a weekly list of 50 companies costs USD 0.40. Set a maximum cost per run in the run options and the actor stops cleanly when it gets there.

### Where the data comes from

Every role is read from the employer's official job board through the platform's public job-board API. These are the same feeds companies use to show jobs on their own careers pages. The index is refreshed about twice a day, and closed roles drop out on the next update.

**No personal data.** Results are about companies and their published job openings. They contain no names, emails or phone numbers of anyone.

### Limits

- **Coverage** is the companies in the index, not every company on the web. It grows as more job boards are discovered.
- **Teams and seniority** are read from job titles, so an unusual title can land in the wrong team or in "other".
- **Location** matching is text matching on the job's locations, so `Canada` finds roles whose location mentions Canada, not every city in Canada.
- **Pay** appears only when the employer publishes it.

### Related actors

- [Career Site Jobs Index: Greenhouse, Ashby, Lever & More](https://apify.com/JTPalms/ats-jobs-index): Fresh jobs from thousands of company career sites, indexed twice a day from the official public job-board APIs of Greenhouse, Ashby,...
- [Company Profile From Domain: Tech Stack, Socials & Hiring](https://apify.com/JTPalms/company-profile): Turn a list of website domains into company profiles: name, description, official social links, tech stack (CMS, ecommerce, analytics),...
- [Website Tech Stack Detector (Wappalyzer Alternative)](https://apify.com/JTPalms/tech-stack-detector): Find the technology behind any website in bulk: CMS, ecommerce platform, analytics, frameworks, CDN, hosting, payment, email and...
- [Career Page Jobs Scraper: Auto-Detects the Job Board (ATS)](https://apify.com/JTPalms/career-page-jobs): Give company websites or careers pages and get every open job.

### FAQ

**How is this different from a jobs scraper?** A jobs scraper returns jobs. This returns companies, with their hiring rolled up, so one row answers "who is building a sales team this month" without you counting jobs yourself. If you want the jobs themselves, use the Career Site Jobs Index actor from the same developer.

**Can I check a specific list of companies?** Yes. Put names or job board names in **Companies**, set **Minimum matching roles** to 1, and each company that is in the index and hiring comes back.

**Something missing or wrong?** Open an issue with the company or its careers page URL. Requests for companies to add are welcome.

# Actor input Schema

## `functions` (type: `array`):

Count only roles in these teams, read from the job title (department as fallback). Leave empty for every team.

## `keywords` (type: `array`):

Count only roles whose title matches any of these, for example account executive or data engineer. Wrap in slashes for a regular expression.

## `excludeKeywords` (type: `array`):

Skip roles whose title or department matches any of these, for example intern.

## `locations` (type: `array`):

Count only roles whose location contains any of these texts, for example Toronto, Canada, London, New York or Remote.

## `countries` (type: `array`):

Keep jobs in any of these countries, read from the job's location (Toronto, ON counts as Canada). Jobs with no clear country, such as plain 'Remote', are left out when this is set.

## `states` (type: `array`):

Keep jobs in any of these states or provinces, read from the location (San Francisco, CA counts as California; Toronto counts as Ontario).

## `remoteOnly` (type: `boolean`):

Count only roles marked remote.

## `seniority` (type: `array`):

Count only roles at these levels, read from the job title.

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

Only companies on these platforms. Leave empty for all.

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

Only companies whose name or job board name contains any of these texts, for example stripe.

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

Skip companies whose name or job board name contains any of these texts, for example your own company or staffing agencies.

## `postedWithinDays` (type: `integer`):

Count only roles posted in this many days. Leave empty for all open roles.

## `minMatchingJobs` (type: `integer`):

Return a company only if at least this many of its open roles match your filters.

## `sortBy` (type: `string`):

Which companies come first.

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

Stop after this many companies. You pay only for companies returned.

## `sampleJobs` (type: `integer`):

How many of each company's newest matching roles to include, with links.

## Actor input object example

```json
{
  "functions": [
    "sales"
  ],
  "remoteOnly": false,
  "minMatchingJobs": 3,
  "sortBy": "matchingJobs",
  "maxCompanies": 50,
  "sampleJobs": 5
}
```

# Actor output Schema

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

All output rows in the default dataset (JSON, CSV, Excel via the format parameter).

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

Counts for this run: jobs scanned and matched, companies matched and returned.

# 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 = {
    "functions": [
        "sales"
    ],
    "minMatchingJobs": 3,
    "maxCompanies": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("jtpalms/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 = {
    "functions": ["sales"],
    "minMatchingJobs": 3,
    "maxCompanies": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("jtpalms/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 '{
  "functions": [
    "sales"
  ],
  "minMatchingJobs": 3,
  "maxCompanies": 50
}' |
apify call jtpalms/hiring-signals --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jtpalms/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/Oi8uvHpjfOMZ78cdf/builds/xzapMvo2RhwdwV4DK/openapi.json
