Hiring Signals Monitor
Pricing
from $2.00 / 1,000 job records
Hiring Signals Monitor
Monitor a list of companies' career pages through their ATS APIs (Greenhouse, Lever, Ashby, Workday, Workable, SmartRecruiters and more) and get every open role normalized, plus change events: new roles, removed roles, hiring surges and new functions.
Pricing
from $2.00 / 1,000 job records
Rating
0.0
(0)
Developer
Al Moutasem Nabil
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Watch a list of companies and know the moment their hiring changes. Give the Actor company career pages; it reads each one through the applicant tracking system's public API (Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Workday and more), normalizes every open role, and on repeat runs reports exactly what changed: new roles, removed roles, hiring surges and new functions a company started hiring for.
Hiring is a buying signal for sales teams, a business-development signal for recruiting agencies and a strategy signal for investors and competitors. Job-board scrapers give you a pile of postings. This Actor gives you a diff over the accounts you care about, ready for Slack, email or your CRM.
Who is it for
- B2B sales teams watching target accounts: a company that just opened five sales roles in Riyadh is expanding there; a company that started hiring data engineers is a new buyer for data tooling.
- Recruiting agencies spotting clients who are hiring for a function they never hired for before, or whose open roles keep growing.
- Investors and analysts tracking portfolio companies and competitors: headcount plans, geographic expansion, senior leadership hires.
- Competitive intelligence teams: which teams a rival is building, which they are closing.
- Job seekers watching a shortlist of dream companies for the exact role to appear.
What makes it different
- Company-list monitoring with change detection. A compact snapshot per watch list is kept between runs; every run emits
job_added,job_removed,job_updated,hiring_surge,new_functionandcompany_errorevents. - ATS integrations, not guesswork. Fifteen dedicated integrations read the same public JSON/XML feeds or server-rendered job lists the career pages themselves use, so data is fresh, complete and stable. Generic HTML parsing is only a fallback for career sites on no supported ATS.
- Auto-detection. Paste a careers URL or even just the company website; the Actor finds the ATS by URL pattern, by scanning the page for embedded ATS references, or by verifying a guessed board id. No configuration per company.
- Normalized records. Function (13 classes) and seniority (10 levels) from rule-based classification, ISO country codes, remote/hybrid/onsite, salary when the ATS exposes it. No LLM, so classification adds zero cost per record.
- Per-company isolation, explicit failures. One unreachable ATS becomes a free
company_errorrow that carries the reason (and, in change mode, the previous job count), and never fails the run. A company with no matching roles gets a freeno_open_rolesrow, and a quiet change-mode run gets oneno_changesrow, so an empty result always says why. - No personal data. Recruiter and hiring-manager fields are never copied into the output; emails and phone numbers are redacted from descriptions.
Supported ATS
| ATS | Data source | Detection |
|---|---|---|
| Greenhouse | Job Board API | boards.greenhouse.io/{token}, job-boards.greenhouse.io/{token}, embed scripts |
| Lever | Postings API | jobs.lever.co/{company} |
| Ashby | Posting API (with compensation) | jobs.ashbyhq.com/{board} |
| Workable | Widget API | apply.workable.com/{subdomain} |
| SmartRecruiters | Posting API (paginated) | careers.smartrecruiters.com/{Company} |
| Recruitee | Offers API | {company}.recruitee.com |
| Personio | Public XML feed | {company}.jobs.personio.de |
| BambooHR | Careers list JSON | {company}.bamboohr.com/careers |
| Breezy HR | Public JSON | {company}.breezy.hr |
| Workday | CXS jobs endpoint (paginated) | {tenant}.wd{N}.myworkdayjobs.com/{site} |
| Teamtailor | RSS feed | {company}.teamtailor.com or custom career domains |
| Rippling | Job board API (paginated) | ats.rippling.com/{slug}/jobs |
| Jobvite | Server-rendered job list | jobs.jobvite.com/{company} |
| iCIMS | Server-rendered job search (paginated) | {portal}.icims.com |
| JazzHR | Server-rendered job list | {company}.applytojob.com |
| Anything else | JSON-LD JobPosting or job links on the page (confidence: "low") | fallback |
Input
| Field | Type | Default | Description |
|---|---|---|---|
companies | array | required | Careers URLs as strings, or objects { name, careersUrl, website, ats, atsIdentifier }. |
trackingId | string | – | Name of the watch list; snapshots are stored under it. Required in change mode. |
emitChangesOnly | boolean | false | Output change events instead of every open role. |
emitBaselineAsAdded | boolean | false | On the first run for a trackingId, emit every role as job_added instead of a silent baseline. |
surgeThreshold | integer | 5 | New roles at one company in one run that trigger hiring_surge. |
includeDescription | boolean | false | Add the plain-text description (extra requests on SmartRecruiters and Workday). |
filters | object | – | functions[], countries[] (ISO-2), seniority[], titleKeywords[], excludeTitleKeywords[]. |
maxJobsPerCompany | integer | 0 | Cap per company (0 = unlimited). |
maxConcurrency | integer | 10 | Companies checked in parallel. |
proxyConfiguration | object | Apify datacenter | Proxies for the requests. |
Snapshot mode (every open role, once). This is the Console prefill: two Gulf fintechs, 10 roles each, a few seconds per run:
{"companies": [{"name": "Tamara","careersUrl": "https://boards.greenhouse.io/tamara","website": "https://tamara.co"},{"name": "Ziina","careersUrl": "https://jobs.ashbyhq.com/ziina","website": "https://ziina.com"}],"maxJobsPerCompany": 10,"proxyConfiguration": {"useApifyProxy": true}}
Add filters (for example { "countries": ["AE", "SA"], "functions": ["engineering", "sales"] }) and more companies, and clear maxJobsPerCompany, for real monitoring.
Change mode (schedule this daily):
{"companies": ["https://boards.greenhouse.io/tamara","https://jobs.ashbyhq.com/ziina","https://jobs.lever.co/nium"],"trackingId": "gulf-fintech-accounts","emitChangesOnly": true,"surgeThreshold": 5}
The first run under a new trackingId records the baseline and emits one free no_changes row saying so (set emitBaselineAsAdded to get every role as job_added instead). Every later run emits only what changed.
Output
Snapshot mode: one item per open role. A real record from a Gulf fintech on Greenhouse:
{"company": "Tamara","companyWebsite": "https://tamara.co","ats": "greenhouse","atsIdentifier": "tamara","jobId": "4683204101","title": "Application Support Engineer","url": "https://job-boards.eu.greenhouse.io/tamara/jobs/4683204101","department": null,"team": null,"location": {"raw": "Saudi Arabia","city": null,"region": null,"country": "SA","remote": "unknown"},"function": "engineering","seniority": "mid","employmentType": null,"postedAt": "2025-11-13T15:49:52.000Z","salary": null,"firstSeenAt": "2026-09-05T17:05:54.732Z","lastSeenAt": "2026-09-05T17:05:54.732Z","confidence": "high"}
Change mode: one item per change event. These are real items from the proof run (the snapshot was edited by hand to remove roles, so the next run reports them as added):
hiring_surge, when a company added at least surgeThreshold roles in one run:
{"type": "hiring_surge","company": "Tamara","companyWebsite": "https://tamara.co","ats": "greenhouse","trackingId": "proof-run","observedAt": "2026-09-05T17:06:07.168Z","count": 6,"threshold": 5,"titles": ["AML Transaction Monitoring Ops - Builders Program - (Emirati National)","Application Support Engineer","Associate Accountant - Builders Program - (Emirati National)","Associate Data Analyst - Builders Program - (Emirati National)","Associate Data Scientist - Builders Program - (Emirati National)","Collections Advisor"]}
new_function, when a company now has roles in a function it had none in before:
{"type": "new_function","company": "Tamara","companyWebsite": "https://tamara.co","ats": "greenhouse","trackingId": "proof-run","observedAt": "2026-09-05T17:06:07.168Z","function": "data","count": 2,"titles": ["Associate Data Analyst - Builders Program - (Emirati National)","Associate Data Scientist - Builders Program - (Emirati National)"]}
job_added (the full normalized job is attached; job_removed attaches the compact snapshot entry instead):
{"type": "job_added","company": "Ziina","companyWebsite": "https://ziina.com","ats": "ashby","trackingId": "proof-run","observedAt": "2026-09-05T17:06:07.168Z","job": {"jobId": "b52d240f-2ccb-4aea-800b-623e9ca8ae09","title": "Backend Engineer, Payments Platform","url": "https://jobs.ashbyhq.com/ziina/b52d240f-2ccb-4aea-800b-623e9ca8ae09","department": "Engineering","team": "Payments Platform","location": {"raw": "Dubai","city": "Dubai","region": null,"country": "AE","remote": "onsite"},"function": "engineering","seniority": "mid","employmentType": "FullTime","postedAt": "2026-08-12T05:44:50.125Z","firstSeenAt": "2026-09-05T17:06:07.168Z","confidence": "high"}}
job_updated, with the fields that changed:
{"type": "job_updated","company": "Salla","companyWebsite": "https://salla.sa","ats": "workable","trackingId": "proof-run","observedAt": "2026-09-05T17:06:07.168Z","job": {"jobId": "B656D5F0F3","title": "Accountant (Shipping or Logistic)","url": "https://apply.workable.com/j/B656D5F0F3","location": {"raw": "Makkah, Makkah Province, Saudi Arabia","city": "Makkah","region": "Makkah Province","country": "SA","remote": "unknown"},"function": "finance","seniority": "mid"},"before": {"title": "OLD TITLE Accountant (Shipping or Logistic)","location": "Makkah, Makkah Province, Saudi Arabia","seniority": "mid","function": "finance"},"after": {"title": "Accountant (Shipping or Logistic)","location": "Makkah, Makkah Province, Saudi Arabia","seniority": "mid","function": "finance"}}
job_removed:
{"type": "job_removed","company": "Lucidya","companyWebsite": "https://lucidya.com","ats": "workable","trackingId": "proof-run","observedAt": "2026-09-05T17:06:07.168Z","job": {"title": "Ghost role","location": "Riyadh","function": "other","seniority": "mid","hash": "ffff","firstSeenAt": "2026-01-01T00:00:00.000Z","jobId": "FAKE-REMOVED-1"}}
company_error, never charged, with the previous count so silence is not mistaken for "no jobs":
{"type": "company_error","company": "Broken Co","companyWebsite": null,"ats": "greenhouse","trackingId": "proof-run","observedAt": "2026-09-05T17:06:07.168Z","error": "HTTP 404 for https://boards-api.greenhouse.io/v1/boards/this-board-does-not-exist-123/jobs","count": 0,"previousObservedAt": null}
The key-value store record SUMMARY lists every company with detected ATS, detection method, job count, request count, duration, fallback flag and error, plus the charged events, so you can see the cost of each run.
Sample output
Real items from the example input above (snapshot mode), verified on the Apify platform in September 2026. Long text and lists are shortened for this page; field names and values are otherwise exactly as the Actor returns them.
[{"company": "Tamara","companyWebsite": "https://tamara.co","ats": "greenhouse","atsIdentifier": "tamara","jobId": "4969403101","title": "Accountant","url": "https://job-boards.eu.greenhouse.io/tamara/jobs/4969403101","department": null,"team": null,"location": {"raw": "Dubai, United Arab Emirates","city": "Dubai","region": null,"country": "AE","remote": "unknown"},"function": "finance","seniority": "mid","employmentType": null,"postedAt": "2026-09-09T08:48:17.000Z","salary": null,"firstSeenAt": "2026-09-13T02:07:07.890Z","lastSeenAt": "2026-09-13T02:07:07.890Z","confidence": "high"},{"company": "Ziina","companyWebsite": "https://ziina.com","ats": "ashby","atsIdentifier": "ziina","jobId": "b52d240f-2ccb-4aea-800b-623e9ca8ae09","title": "Backend Engineer, Payments Platform","url": "https://jobs.ashbyhq.com/ziina/b52d240f-2ccb-4aea-800b-623e9ca8ae09","department": "Engineering","team": "Payments Platform","location": {"raw": "Dubai","city": "Dubai","region": null,"country": "AE","remote": "onsite"},"function": "engineering","seniority": "mid","employmentType": "FullTime","postedAt": "2026-08-12T05:44:50.125Z","salary": null,"firstSeenAt": "2026-09-13T02:07:07.890Z","lastSeenAt": "2026-09-13T02:07:07.890Z","confidence": "high"},{"company": "Tamara","companyWebsite": "https://tamara.co","ats": "greenhouse","atsIdentifier": "tamara","jobId": "4849511101","title": "Associate Accountant - Builders Program - (Emirati National)","url": "https://job-boards.eu.greenhouse.io/tamara/jobs/4849511101","department": null,"team": null,"location": {"raw": "Dubai, United Arab Emirates","city": "Dubai","region": null,"country": "AE","remote": "unknown"},"function": "finance","seniority": "junior","employmentType": null,"postedAt": "2026-04-27T09:38:25.000Z","salary": null,"firstSeenAt": "2026-09-13T02:07:07.890Z","lastSeenAt": "2026-09-13T02:07:07.890Z","confidence": "high"}]
How to schedule and get notified
- Open the Actor, fill in the change-mode input above with your
trackingId, and click Save as task. - On the task, open Schedules and create one (daily at 07:00 is typical).
- Open Integrations on the task and add Slack, Email, Webhook, Make or Zapier with the event Run succeeded. Point the integration at the run's dataset; in change mode the dataset contains only the change events, and a run where nothing changed contains a single free
no_changesrow (filter ontypeif you only want real changes). - For your own pipeline, call the API directly:
curl -X POST "https://api.apify.com/v2/acts/<username>~hiring-signals-monitor/run-sync-get-dataset-items?token=<token>" \-H "Content-Type: application/json" \-d '{ "companies": ["https://jobs.lever.co/nium"], "trackingId": "demo", "emitChangesOnly": true }'
State lives in the named key-value store hiring-signals-state in your account, one record per trackingId. Delete the record to reset a watch list.
Pricing
Pay-per-event: you pay for signals, not for pages. Detection requests, pagination, retries and failed companies are never charged.
| Event | Price | When |
|---|---|---|
| Company checked | $0.005 | Per company whose roles were fetched successfully. |
| Job record | $0.002 | Snapshot mode: per open role stored. |
| Change detected | $0.01 | Change mode: per change event stored (company_error is free). |
Worked example, 50 companies monitored daily with about 8 changes per day: 50 × $0.005 + 8 × $0.01 = $0.33 per run, about $10 per month. A weekly snapshot of 20 companies with 1,500 open roles costs $3.10 per run. Apify platform usage (compute, a few seconds per run) is billed separately by your plan.
Related
../review-intelligence collects public Trustpilot, App Store and Google Play reviews for a company or app, with AI themes and negative-review alerts.
Watching whole job boards rather than named employers? ../mena-jobs-aggregator aggregates Bayt, GulfTalent, NaukriGulf and Akhtaboot into one deduplicated feed.
Limitations
- Change detection is relative to the filtered set: changing
filtersbetween runs produces added/removed events. - Workday exposes posting dates as "Posted 3 Days Ago"; dates older than 30 days are
null. - Generic (non-ATS) career pages yield title and URL only, with
confidence: "low"; location and posting date depend on JSON-LD being present. - Jobvite, iCIMS and JazzHR job lists carry title, location and (iCIMS) posting date only; department is available on Jobvite, and
includeDescriptiondoes not add descriptions for these three. hiring_surgeandnew_functionare computed per run, so a company that posts 20 roles across four days never triggers a surge withsurgeThreshold: 5per day; lower the threshold or run less often.- Salary is reported only when the ATS exposes it (Ashby, Lever, Recruitee, Breezy, JSON-LD).
FAQ
Does it need my ATS credentials? No. Every integration uses the public endpoints the career pages call themselves.
What happens when a career page is down? You get one company_error event with the error, the previous job count and the previous observation time. The snapshot for that company is left untouched, so nothing is reported as removed.
Can a job "move" between ids? Some ATSs re-issue ids. A role with the same title, location, function and seniority under a new id is treated as the same role and keeps its firstSeenAt.
How many requests does a run make? One or two per company for most ATSs (Greenhouse, Ashby, Workable, Recruitee, Breezy, Personio, Teamtailor return everything in one call; Lever, SmartRecruiters and Workday paginate in 100/100/20). Detection from a website costs two to three extra requests the first time.
Can I run it for one company from my own code? Yes, pass a single-element companies array; trackingId can be per customer or per account list.
Related
Watching a specific page rather than a feed? ../page-change-monitor reports exactly what changed on any URL, with a diff and an optional AI summary.
Legal note
The Actor reads publicly available job postings through public endpoints, honours robots.txt for the HTML fallback, uses polite concurrency and stores no personal data: the recruiter and hiring-manager fields some ATS APIs return are never copied into the output, and email addresses and phone numbers are redacted from job descriptions. Use the data in line with the ATS and career-site terms and the laws that apply to you.