Hiring Signals Monitor - New Jobs & Surges (ATS) avatar

Hiring Signals Monitor - New Jobs & Surges (ATS)

Pricing

from $2.40 / 1,000 company hiring summaries

Go to Apify Store
Hiring Signals Monitor - New Jobs & Surges (ATS)

Hiring Signals Monitor - New Jobs & Surges (ATS)

Greenhouse and Lever scraper that tracks which companies are hiring. Reads public Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee and Teamtailor boards, remembers every job and reports new jobs, closed jobs and hiring surges between runs.

Pricing

from $2.40 / 1,000 company hiring summaries

Rating

0.0

(0)

Developer

Andrew Boiko

Andrew Boiko

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 hours ago

Last modified

Categories

Share

Hiring Signals Monitor - New Jobs & Hiring Surges from Public Job Boards

Know which companies are ramping up hiring - before everyone else does. Hiring Signals Monitor reads the public job boards of the applicant tracking systems (ATS) that most growing companies use (Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Teamtailor), remembers every job it has seen, and on each run tells you:

  • how many jobs a company has open right now, by department and location,
  • which jobs are new since the last run (and which were closed),
  • whether hiring is trending up, flat or down, and whether the company is in a hiring surge.

Hiring is one of the most reliable buying signals in B2B: a company opening 10 sales roles is expanding the sales team; one opening a DevOps lead is about to buy infrastructure tooling. Schedule the actor daily or weekly and plug the results into your CRM, Slack or spreadsheet.

Who is it for?

  • Sales and SDR teams - find accounts that are growing and the moment a relevant role opens.
  • Recruiters and staffing agencies - spot companies that just started hiring in your niche.
  • Investors and analysts - track headcount-growth proxies for a watch list of startups.
  • Competitive intelligence - see where competitors are investing (engineering vs. sales vs. support).
  • Job seekers - get alerts for new openings at the companies you care about.

What you get

Two kinds of rows in one dataset, told apart by rowType:

  1. company-summary - one per company: open jobs, top departments/locations, new and closed since last run, trend, surge flag.
  2. new-job - one per newly detected job: title, department, location, link, posted date (when the board publishes it) and the time we first saw it.

Input

FieldTypeDescription
companieslistDomains (stripe.com), careers/board URLs, or explicit boards as ats:slug such as greenhouse:stripe. Objects {name, domain, ats, slug} are accepted through the API.
keywordslistOnly count/report jobs whose title or department contains one of these words.
surgeThresholdintegerNew jobs since last run needed to flag a surge (default 5).
includeBaselinebooleanAlso output a new-job row for every job on the first run (default off; charged per row).
monitorNamestringName of the saved state. Use one stable name per watch list.
probeSlugGuessesbooleanFor domains without a visible board link, try board names derived from the domain (default on).
maxCompaniesintegerSafety limit per run (default 500, max 2000).
includeFailedbooleanAdd free error rows for companies that could not be read.

Output example

{
"rowType": "company-summary",
"id": "greenhouse:acme:summary:2026-10-14T08:00:03.120Z",
"companyName": "Acme",
"domain": "acme.com",
"ats": "greenhouse",
"slug": "acme",
"boardUrl": "https://boards.greenhouse.io/acme",
"detectionMethod": "page-link",
"detectionConfidence": "high",
"openJobs": 42,
"totalOpenJobs": 42,
"previousOpenJobs": 35,
"byDepartment": [{ "name": "Engineering", "count": 18 }, { "name": "Sales", "count": 9 }],
"byLocation": [{ "name": "Remote - Europe", "count": 11 }, { "name": "San Francisco, CA", "count": 8 }],
"newSinceLast": 9,
"closedSinceLast": 2,
"hiringTrend": "up",
"surge": true,
"isBaseline": false,
"scannedAt": "2026-10-14T08:00:03.120Z",
"source": "Greenhouse Job Board API"
}
{
"rowType": "new-job",
"id": "greenhouse:acme:4101",
"companyName": "Acme",
"jobId": "4101",
"title": "Staff Engineer",
"department": "Engineering",
"location": "Remote",
"url": "https://boards.greenhouse.io/acme/jobs/4101",
"postedAt": null,
"firstSeenAt": "2026-10-14T08:00:03.120Z",
"isBaseline": false
}

The run also writes an OUTPUT record (counts, charged events, skipped companies with reasons, warnings) and a short RESULTS_MD summary to the key-value store.

Pricing

Pay only for results, per event:

EventPriceWhen
company-summary$0.003One per company whose job board was found and read successfully
new-job$0.002One per newly detected job after the baseline run

Nothing is charged for companies that fail, boards that cannot be found, empty/suspicious responses, duplicates, or anything beyond the maximum cost you set for the run. Apify's free plan credit lets you try it at no cost, and volume discounts (Bronze/Silver/Gold) apply automatically. Example: watching 100 companies weekly with about 5 new jobs per company costs roughly 100 x $0.003 + 500 x $0.002 = $1.30 per run.

How it works

  1. Find the board. greenhouse:stripe goes straight to the board. For a domain, the actor reads the homepage and /careers, /jobs, /company/careers (respecting robots.txt) looking for links or embeds of a supported ATS. If nothing is visible it tries board names guessed from the domain and accepts a board only when it lists at least one job (marked detectionConfidence: low).
  2. Read the public job-board API of that ATS (no login, no scraping of job pages).
  3. Compare with the saved state (a named key-value store, hiring-signals-<hash>). First run per company = baseline, so you are not flooded with every open job. Later runs report what changed.
  4. Safety rules. State is only updated for companies that were read successfully, so a failed request can never show up as "all jobs closed". A board that suddenly returns 0 jobs after having 5 or more is treated as a glitch and ignored. Closed jobs are remembered for 45 days so a re-posted job is not reported as new.

Limits and honest caveats

  • Only the seven ATS listed above. Companies with their own careers page, Workday, iCIMS, Taleo, BambooHR, LinkedIn-only posting and similar are not covered.
  • A domain guess can be wrong: probeSlugGuesses may match a different company with the same short name. Prefer explicit ats:slug for important accounts; check detectionConfidence.
  • Job counts are what the board publishes. Confidential or internal postings, and jobs listed only on aggregators, are invisible.
  • Greenhouse's job list does not always include departments; the actor fetches the departments endpoint on a best-effort basis, so department can be null.
  • postedAt is null where the board does not publish a posting date. firstSeenAt is always available and is the time of your run that first saw the job, so its precision equals your schedule interval.
  • "Hiring surge" and "trend" are simple rules based on job counts between two runs; they are signals, not measured headcount growth.
  • Changing the list of companies without setting monitorName starts a fresh baseline (the state name is derived from the list). Set a monitorName to keep history while editing the list.

The actor reads only publicly available job-board endpoints that the ATS vendors expose for embedding job listings on company websites. It does not log in, bypass protections or collect personal data about applicants. Website pages are fetched with an honest User-Agent, low concurrency and robots.txt is honored. Job postings are the property of the respective companies; check the terms of the ATS and the company before republishing postings. You are responsible for lawful use of the output, including GDPR when you combine it with personal data.

FAQ

Does it find the job board automatically from a domain? Usually, when the company links to its board from the homepage or careers page. Otherwise it guesses. For reliable results use ats:slug.

How do I find the slug? Open the company's job board; it is the last part of the URL: boards.greenhouse.io/<slug>, jobs.lever.co/<slug>, jobs.ashbyhq.com/<slug>, apply.workable.com/<slug>, jobs.smartrecruiters.com/<slug>, <slug>.recruitee.com.

Why did the first run return no new jobs? The first run per company is a baseline by design. Enable includeBaseline if you want all current jobs once (charged per job).

What if a company removes a job and posts it again? Reopened jobs are not reported as new within 45 days.

Can I filter by role? Yes, use keywords (title or department contains any keyword). Changing keywords does not cause false "new" jobs.

What happens when I reach my maximum cost? The run stops softly, OUTPUT.stoppedReason is budget, and companies not yet reported are not charged; rerunning continues.

Can I run it hourly? Yes, but most boards change a few times a day at most; daily or weekly is typical.

Use it via API

Replace username with the actor owner.

curl -X POST "https://api.apify.com/v2/acts/username~hiring-signals-monitor/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"companies":["greenhouse:stripe","lever:palantir","notion.so"],"keywords":["engineer"],"monitorName":"my-watchlist"}'
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('username/hiring-signals-monitor').call({
companies: ['greenhouse:stripe', 'lever:palantir'],
monitorName: 'my-watchlist',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((i) => i.rowType === 'new-job'));
from apify_client import ApifyClient
client = ApifyClient("APIFY_TOKEN")
run = client.actor("username/hiring-signals-monitor").call(run_input={
"companies": ["greenhouse:stripe", "lever:palantir"],
"monitorName": "my-watchlist",
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
if item["rowType"] == "company-summary" and item["surge"]:
print(item["companyName"], item["newSinceLast"])

Integrations

Use Apify's Schedules to run the actor daily or weekly, then connect the dataset with Make, n8n or Zapier (trigger: "Actor run finished", action: get dataset items) to push new-job rows to Slack, a CRM or Google Sheets. The built-in Google Sheets integration and webhooks work as well; filter on rowType and surge.

More tools by the same author