ATS Job Board Scraper & Alerts: Greenhouse, Lever, Ashby
Pricing
from $1.50 / 1,000 job scrapeds
ATS Job Board Scraper & Alerts: Greenhouse, Lever, Ashby
Scrape Greenhouse, Lever, Ashby, SmartRecruiters and Workable jobs. Use the new-jobs-only task to export additions since your saved baseline without paying for unchanged job rows. Filter company watchlists or track all hiring changes with optional Slack and Discord alerts.
Pricing
from $1.50 / 1,000 job scrapeds
Rating
0.0
(0)
Developer
harvestlab
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
1
Monthly active users
3 hours ago
Last modified
Features
Share
This ATS job board scraper and hiring monitor tracks public postings on Greenhouse, Lever, Ashby, SmartRecruiters, and Workable. Give it the company boards you follow; get job titles, locations, source IDs and posting links in CSV or JSON. Save a watchlist to compare later runs, filter relevant roles, and export only newly observed jobs. You can also track all hiring changes and send alerts to Slack, Discord, or your own webhook.
Built for recruiters following target companies, teams researching hiring activity, and job-feed operators maintaining a selected set of boards. It reads those boards when you run it; company names alone do not search a global jobs database.
Use the small starter below to inspect job fields, or copy Monitor New Jobs Only for recurring additions. Its first complete run saves history without exporting old jobs; unchanged repeats incur only the source scan fee: $0.01 per board at base pricing, or $0.006 on Business/Gold+. No summary event is charged in new-only mode. Job-board access needs no ATS account or AI provider key. AI is optional and off by default. A successful one-board starter with three jobs and one summary has a base-price event subtotal of $0.0475, or $0.0285 with the Gold/Business discount. The default full-inventory mode also charges for returned open jobs and useful summaries; choose the output mode that fits your workflow.
ATS Job Board Scraper: First Run
Paste this input into the Actor or use it through the API or an AI agent:
{"atsBoardUrls": ["https://boards.greenhouse.io/stripe"],"companyNames": ["Stripe"],"maxCompanies": 1,"maxJobsPerCompany": 3,"includeDescriptions": false,"watchMode": false,"enableAiAnalysis": false,"proxyConfiguration": {"useApifyProxy": false}}
Open the dataset's Jobs view to inspect titles, locations and posting links, plus department and other fields where the source supplies them. A three-job starter is a sample; it cannot establish that omitted roles have closed. API callers must provide at least one board URL, company domain, ATS slug, or supported query. The Console prefill is an example and does not silently select Stripe for an empty API request.
Ready-to-Run Tasks
- Monitor New Jobs Only saves a complete baseline, then returns only matching job additions. Its dataset contains job rows only. Updated, closed, reopened and unchanged postings are excluded.
- Scrape Greenhouse, Lever & Ashby jobs returns a small multi-board export with the Jobs view. Use it to evaluate field mapping before expanding your target list.
- Monitor company hiring signals uses a named watchlist and a larger job cap for repeat comparisons. Copy it into your account, choose your targets, and create an Apify Schedule for that task.
Tasks are reusable inputs. Copying one does not create a schedule, subscribe a Slack channel, or write to a CRM. All three examples keep AI and proxies off and contain no webhook credentials.
Greenhouse, Lever, Ashby, SmartRecruiters and Workable inputs
Put any combination of these public board formats in atsBoardUrls to get a common job-output format:
| ATS source | Example public board |
|---|---|
| Greenhouse | https://boards.greenhouse.io/stripe |
| Lever | https://jobs.lever.co/palantir |
| Ashby | https://jobs.ashbyhq.com/ashby |
| SmartRecruiters | https://jobs.smartrecruiters.com/boschgroup |
| Workable | https://apply.workable.com/huggingface/ |
These example boards returned usable postings in bounded deployed checks on November 4, 2026. Availability and field completeness can change. Each job retains source_ats, ats_slug, job_id and its posting URL so your integration can identify and update the same source record.
Monitor New Jobs Only
Choose jobOutputMode: "new" with watch mode and a stable watchlistId when your workflow needs additions rather than another copy of the whole board. The public new-jobs task starts with one Duolingo board; replace it with your target before your first run.
{"atsBoardUrls": ["https://boards.greenhouse.io/duolingo"],"companyNames": ["Duolingo"],"maxCompanies": 1,"maxJobsPerCompany": 1000,"includeDescriptions": false,"watchMode": true,"watchlistId": "new-jobs-watchlist","resetBaseline": false,"jobOutputMode": "new","maxOutputJobs": 0,"titleKeywords": [],"excludeTitleKeywords": [],"locations": [],"remoteOnly": false,"notifyOnlyChanges": true,"enableAiAnalysis": false,"proxyConfiguration": {"useApifyProxy": false}}
- Establish history. The first complete run saves the board inventory and returns an empty dataset. Check the Run Summary for complete coverage and saved state. Existing postings are not relabeled as new.
- Repeat the same watchlist. Later complete comparisons return only matching jobs first observed since the previous saved baseline. An unchanged board produces no dataset rows and no job or summary event.
- Export or schedule it. Export JSON/CSV directly without removing summary or diagnostic rows. Copying a task does not create a schedule; add an Apify Schedule to your copied task when you are ready.
With the native watchlist used by the public task, the dataset excludes updated, closed and reopened postings. Each returned job retains its source ID, posting URL and change evidence. “New” means newly observed against the retained baseline history, not a guaranteed source publication date. A previously observed job does not become new when you broaden a title or location filter. Manual previousJobsDatasetId comparisons have the history limitation described below.
This mode still reads and compares the full source inventory before selecting output. A native watchlist retains complete comparison history after a successful run, within the storage limits below. It never infers additions from a partial, failed, unreadable or incompatible comparison. A fresh or explicitly reset baseline is quiet. If the output or charge limit prevents complete delivery, the native baseline is retained so omitted additions can be returned on a later successful run. Held, capped, charge-limited or concurrent runs can re-emit already exported jobs on a retry. Avoid overlapping runs and deduplicate by change_event_id.
Operational company summaries, coverage and diagnostics remain available in the run's key-value store; they are not mixed into the dataset or charged as hiring-summary events. Inspect Run Summary, Company Observations and Diagnostics when the dataset is empty. Optional AI is off in this task. If enabled separately, a completed brief is saved as AI_BRIEF and its usual AI event applies. Optional notification settings are independent of jobOutputMode: a configured receiver can still receive matching updated, closed or reopened events. The public task contains no receiver.
A successfully fetched board costs $0.01 / $0.008 / $0.007 / $0.006 on Free / Starter / Scale / Business plans, including a fetched but incomplete response. Emitted new jobs cost $2.50 / $2 / $1.75 / $1.50 per 1,000, respectively. With AI and proxies off, 30 unchanged one-board checks total $0.30 / $0.24 / $0.21 / $0.18 in events. A run with one new job totals $0.0125 at base, or $0.0075 on Business/Gold+. Platform usage is included in the Actor's current pricing. These are arithmetic examples, not a fixed monthly subscription; extra boards, additions or optional services increase cost.
Company Watchlists and Hiring Alerts
Use watchMode: true and a stable watchlistId. The first suitable run establishes a baseline; subsequent runs use that saved state without requiring you to paste a new dataset ID each time.
- Copy the monitoring task, replace its example board with your target, and run it once.
- Check that its summary says
snapshot_complete: trueand its run summary reports saved state. - Add title or location filters if you need a narrower export. Add a receiver only if you want notifications.
- Create an Apify Schedule for your copied task. Run it again to check the comparison before relying on alerts.
{"atsBoardUrls": ["https://boards.greenhouse.io/duolingo"],"companyNames": ["Duolingo"],"maxCompanies": 1,"maxJobsPerCompany": 1000,"includeDescriptions": false,"watchMode": true,"watchlistId": "duolingo-hiring","resetBaseline": false,"titleKeywords": [],"excludeTitleKeywords": [],"locations": [],"remoteOnly": false,"notifyOnlyChanges": true,"enableAiAnalysis": false,"proxyConfiguration": {"useApifyProxy": false}}
Choose a cap above the board's observed job count. A board at the cap is not complete, even when every returned row looks valid. Failed, capped, malformed, or otherwise incomplete sources cannot prove closures and do not replace that target's previous complete baseline. Other complete targets can still advance. Read the diagnostic and coverage fields before treating a zero count as an empty board.
maxOutputJobs adds a global cap after filters and the selected output mode (0 means no additional output cap, up to 10,000 when set). In full-inventory or changes mode, the cap can include closed-job markers. If it truncates output, a diagnostic makes that explicit, the native baseline does not advance, and notifications are suppressed. In full-inventory and changes modes, free job_change evidence is limited to those returned jobs. New-only output keeps change evidence on each job without adding companion rows. RUN_SUMMARY.output_truncated and total_matching_jobs explain the limit. Increasing the output cap resumes comparison from the retained baseline. Choose a limit that can accommodate the complete filtered monitoring output.
Keep the same watchlist ID for one monitoring workflow. Use a different ID for a separate target list. Keep source limits and description settings consistent to preserve a compatible baseline. resetBaseline: true intentionally starts a fresh comparison baseline; return it to false for the next scheduled run. State belongs to the calling account and Actor. A saved baseline is limited to 2,000 job records in total across boards, including retained closed-job markers, and 8 MB. An oversized snapshot is diagnosed and leaves good history in place; the Actor does not silently truncate it. Recovery reads up to the 20 newest saved generations. Old storage records are not deleted automatically. Export datasets you need to retain, monitor storage diagnostics, and manage retention in your account. Avoid overlapping runs of the same watchlist; set a schedule interval longer than the expected run duration.
For an external workflow that already manages baseline IDs, use previousJobsDatasetId with watch mode instead. Select an accessible dataset from a prior run of this Actor. A fixed dataset ID always compares with that same historical snapshot; it does not become a rolling baseline by itself. Newness depends on the history retained in that supplied dataset. Rotating to newer exports can lose older closed-job markers, so a later reopening can be classified and charged as a new addition. Use a stable native watchlistId to retain closed-job history across runs and exclude those reopenings from new-only output; the public Monitor New Jobs Only task uses this native state. The resource picker requests read access to the selected dataset only. The Actor does not require full account permissions.
Filter Roles for Your Workflow
Use titleKeywords to include relevant roles, excludeTitleKeywords to remove unwanted titles, locations to narrow location text, and remoteOnly to require an explicitly remote posting. Include terms match any case-insensitive title substring; exclusions take precedence. Location terms match any case-insensitive substring in the location or country text. Title, location, and remote filters combine, so a job must satisfy each configured dimension. Filtering happens after source comparison and baseline storage; a filtered-out role is not recorded as closed.
Each list entry is one literal substring, including any commas. For example, locations: ["Paris, France"] matches that phrase; use separate entries such as ["Paris", "London"] for alternatives. Entries within a list are OR-matched.
Useful workflows include engineering openings for recruiting research, sales roles for account prioritization, and remote roles for a job-market feed. A matching posting is a public job opening, not proof that a company is buying a product or expanding its workforce. Filters select output from the full comparison and are not part of the saved extraction scope. Changing filters alone does not reset native history or turn excluded roles into closures. Keep the target list, source cap, and description setting consistent for a compatible comparison.
Example: monitor engineering jobs at one company
In the complete Duolingo watchlist input above, set "titleKeywords": ["engineer"]. On November 4, 2026, that deployed workflow returned 15 matching roles from a 55-job board, while retaining all 55 jobs for future comparisons. Switching back to an unfiltered run returned the full inventory without manufacturing closures. These are dated owner acceptance results; the source inventory will change.
At the listed base prices, that filtered run's events total $0.0775: one source scan, 15 jobs and one summary. The 55-job full export totals $0.1775. Filters reduce returned job events while the summary still describes the whole observed board. Source access and baseline completeness are checked before filtering.
remoteOnly requires explicit work-arrangement evidence. A city alone does not establish onsite work, and text about distributed systems or hybrid cloud does not establish remote or hybrid employment. Ambiguous arrangements remain unknown and are excluded by the remote-only filter.
Data and Exports
The Output tab includes Run Summary, Company Observations, Diagnostics, AI Status and Brief, and notification records. Completed runs provide these records in every output mode, so you can inspect a quiet run without following missing links. Company Observations and Diagnostics can be empty arrays. If AI is off, its record explains that no analysis was requested; this status is not an AI brief and does not trigger an AI event. Storage copies add no separate Actor event. Existing dataset events still follow the pricing rules below.
With the default jobOutputMode: "all", the dataset can contain the five record types below. jobOutputMode: "changes" limits job rows to proven changes while retaining companion evidence, summaries and diagnostics. Select record_type when exporting either mixed format programmatically; a dataset view is a convenient set of columns, not a substitute for filtering mixed rows. With jobOutputMode: "new", the dataset contains only newly observed job rows; operational summaries and diagnostics are in the key-value store instead.
| Record type | Contents | Typical use |
|---|---|---|
job | Posting identity, company, ATS source, title, location, department, remote status, posting URL, available compensation, timestamps, and change classification | CSV export, job feed, account enrichment |
job_change | Proven new, changed, closed, or reopened posting event with a stable event_id and before/after evidence | Alert deduplication and change feeds |
hiring_summary | Unfiltered observed board counts, changes, role mix, locations, comparison and coverage information | Watchlists and company-level reporting |
diagnostic | Source or input problem, status, and a concrete next step | Investigate missing or incomplete output |
ai_hiring_brief | Optional narrative brief with provider/model metadata | Reviewable weekly account notes |
Coverage fields include observed_jobs / observed_open_jobs, source_total_jobs, and snapshot_complete. The source total is available only when the source supplies a trustworthy count; it stays null otherwise. comparison_status distinguishes snapshot, compared, partial, baseline_unavailable, and baseline_incompatible; a multi-board summary can be mixed. observed_at, baseline_at, and target_observations show when each source was compared.
Proven changes include change_event_id, changed_fields, and change_details with before/after values. Separate job_change rows expose the stable event_id, target and posting identities, comparison timestamps, and before/after content hashes. They distinguish new, changed, closed, and reopened events. A closed posting also remains a job row with change_type: "closed" so an export can update its saved inventory; neither that closure row nor the separate event evidence is charged as a scraped job. A first baseline uses change_type: "snapshot"; a partial or unavailable comparison uses unknown. Unknown new_jobs, changed_jobs, or closed_jobs counts remain null rather than being reported as zero.
total_open_jobs, observed_jobs, and observed_open_jobs count the unfiltered open roles observed on the scanned boards before job-output filters. A capped board is still only a sample. These are job counts, not company headcount. Company summaries retain this board-wide scope even when title, location, or remote filters return no job rows. returned_jobs counts matching open rows in your output; returned_change_events counts matching proven new, changed, closed, and reopened events. These returned counts let you distinguish the filtered export from board-wide hiring activity. hiring_activity_label reports hiring or no_observed_jobs. hiring_trend reports growing, contracting, or stable only when complete comparable snapshots support a change calculation; otherwise it is unknown. net_job_change is proven new jobs minus proven closed jobs across the unfiltered comparable boards, not a change in employee headcount.
For existing integrations, hiring_velocity_label now mirrors hiring_trend; the older count-derived quiet, active, expanding, and surging values are no longer emitted. Use total_open_jobs if you need the observed count and hiring_trend for a baseline-backed trend. Initial snapshots are no longer labeled as newly opened jobs.
Job rows include job_id, source_ats, ats_slug, url, company, company_domain, title, department, team, location, remote_status, country, employment_type, seniority, available salary fields, currency, detected skills and functions, source posting/update timestamps, first_seen, last_seen, and change_type. Enable includeDescriptions for cleaned description text. Salary, department, country, employment type and posting dates depend on the source; they are not guaranteed fields. Missing values remain missing. A changed event can reflect a source timestamp update rather than a rewritten role: inspect changed_fields before assigning business significance.
In full-inventory and changes modes, use the Jobs view for postings, Changes for event evidence, Summaries for company rollups, and Diagnostics for actionable warnings. In new-only mode, use the Jobs view and open the run's separate summary and diagnostic outputs for operational evidence. Download JSON or CSV through Apify's dataset export, or fetch the default dataset through the API and filter record_type in your integration.
Illustrative summary from a complete, compatible comparison:
{"record_type": "hiring_summary","company": "Example Company","observed_jobs": 42,"source_total_jobs": 42,"snapshot_complete": true,"comparison_status": "compared","new_jobs": 3,"changed_jobs": 2,"closed_jobs": 1,"net_job_change": 2,"hiring_activity_label": "hiring","hiring_trend": "growing"}
This example describes a job-board comparison, not evidence of workforce growth or commercial intent.
Slack, Discord, and Generic Webhooks
Add a final receiver URL in alertWebhookUrl, then choose notificationFormat:
| Format | Receiver |
|---|---|
generic | Your JSON-capable workflow endpoint, such as a webhook you configure in Make, n8n, Zapier, or a custom application |
slack | A Slack incoming webhook owned by your workspace |
discord | A Discord channel webhook you control |
The URL is a secret input. Do not put a real receiver URL into a public task or shared JSON example. Redirects are refused; use the final receiving address. In watch mode, notifyOnlyChanges: true sends only filtered, proven changes. The first baseline and unchanged comparisons stay quiet. Set it to false to receive complete snapshot or unchanged summaries. Incomplete, unreadable, incompatible, or conflicting comparisons do not generate watch alerts. Without watch mode, a configured endpoint receives snapshot summaries for compatibility with existing integrations; a capped snapshot is explicitly partial and makes no change claim. Slack payloads use plain text and Discord messages disable mentions. The Actor attempts bounded retries for rate limits, server errors, and safe connection failures. A read, write, or overall timeout is ambiguous: the receiver may have accepted the request even when the Actor could not confirm it. Delivery is at least once; receivers should deduplicate by the stable event_id where possible. Manual replay after an ambiguous attempt can duplicate a notification.
For example, add the following to your watchlist input after replacing the placeholder with your own working receiver:
{"alertWebhookUrl": "REPLACE_WITH_YOUR_FINAL_SLACK_WEBHOOK_URL","notificationFormat": "slack","notifyOnlyChanges": true}
This is a configuration fragment, not a runnable starter. Notifications need a receiver you have configured. Dataset success does not by itself prove that a Slack channel, Discord channel, or downstream business workflow accepted the delivery.
The run stores RUN_SUMMARY, the canonical NOTIFICATION payload when generated, and NOTIFICATION_DELIVERY evidence when delivery is attempted. Delivery evidence includes status, attempts, HTTP status when received, a sanitized error class, and delivery_ambiguous; it excludes the receiver URL and raw exception text.
To retry a retained notification without scraping the boards again, select the original run's key-value store in replayNotificationStoreId and provide your current secret receiver URL and format. The Actor verifies that the store belongs to a run of this Actor. Replay reads the retained payload and preserves its event identity; it does not rerun extraction. Receiver-side deduplication is still needed. If the prior store has expired or its notification record is missing, create a new monitoring run rather than inventing a delivery.
Input Reference
Company labels are positional: match companyNames to your board URLs, then
atsSlugs, then an optional query. Missing labels are not copied from the
first company. In a JSON array, use an empty string to leave a position blank;
names such as "Stripe, Inc." remain one label. Without a label, job rows use
the source-provided company when available, otherwise the field stays empty;
company summaries can identify the board by its slug. Company domains supplied
alongside direct targets follow the same positions. Extra domains can be used
for careers-page discovery; for domain-only input, pair each label with its
domain at the same array position. ATS board URLs supplied in companyDomains
remain board targets; their hosting address is never treated as the employer's
domain. Blank source-array entries keep their positions and produce a diagnostic
without shifting later labels. If a domain-source entry conflicts with a direct
target or query at the same position, or a discovery query is combined with
standalone domain targets, the Actor stops before scanning or charging. Put ATS
boards together in atsBoardUrls/atsSlugs, or discovery domains together in
companyDomains, pair their labels, and clear the conflicting query.
| Input | Default | Meaning |
|---|---|---|
atsBoardUrls | empty | Direct public board URLs; recommended for dependable target selection |
companyNames | empty | Optional display labels paired with your board/domain/slug inputs; not a company-name search engine |
companyDomains | empty | Best-effort discovery of supported careers links on public company pages |
atsSlugs | empty | Explicit source:slug, for example greenhouse:stripe or lever:palantir |
maxCompanies | 25 | Board target limit, 1–500 |
maxJobsPerCompany | 100 | Per-board source cap, 1–1000; use a complete snapshot for closure detection |
maxOutputJobs | 0 | Global cap after filters and output mode, 0–10,000; 0 means no additional output cap |
jobOutputMode | all | all: matching inventory; changes: proven changes with summaries; new: only newly observed job rows, with free operational summaries in storage |
includeDescriptions | true | Include available cleaned descriptions; Console starter prefills false |
watchMode | false | Enable comparison against native watchlist state or the selected previous dataset |
watchlistId | empty | Stable name for automatic state in the calling account |
resetBaseline | false | Intentionally start a new baseline instead of comparing this run |
previousJobsDatasetId | empty | Read-only prior-run dataset selection for explicit-baseline workflows |
titleKeywords / excludeTitleKeywords | empty | Include/exclude matching title terms |
locations / remoteOnly | empty / false | Location-text filter and explicit-remote filter |
alertWebhookUrl | empty | Secret final HTTP(S) receiver address |
notificationFormat | generic | Generic JSON, Slack, or Discord payload |
notifyOnlyChanges | true | In watch mode, send only proven matching changes; non-watch snapshot delivery is preserved |
replayNotificationStoreId | empty | Read saved delivery from a prior run instead of scraping again |
enableAiAnalysis | false | Generate a brief using your selected provider credentials |
llmProvider | openrouter | OpenRouter, Anthropic, Google, OpenAI, or Ollama |
llmModel | provider default | Optional model override |
proxyConfiguration | off | Optional routing for source requests; most public feeds work without it |
Provider credentials are secret inputs (openrouterApiKey, anthropicApiKey, googleApiKey, openaiApiKey) or the corresponding provider environment variables. ollamaBaseUrl is also treated as a secret because a custom address can contain private credentials. Ollama needs a reachable address; the runtime localhost fallback is useful only when an Ollama service runs in the same environment. Do not enable AI until the selected provider is configured.
Hidden compatibility aliases remain available: urls, domains, companies, maxItems, and query. Prefer the documented canonical inputs in new integrations. For API or MCP use, start with the exact first-run JSON; it contains no placeholder IDs, secret URLs, or unconfigured AI services.
Pricing and Run Budgets
| Event | Base price | Eligible output |
|---|---|---|
company-scanned | $0.01 | A successfully read supported ATS source |
job-scraped | $0.0025 | A persisted open job row |
hiring-summary-generated | $0.03 | A persisted company summary with observed open jobs or proven closures; not charged in new-only mode |
ai-analysis-completed | $0.05 | A completed, persisted optional AI brief |
skyfire-bundle-500-companies | $5.00 | Legacy event retained in the pricing schedule; it does not replace normal event accounting |
Store subscription discounts
Apify applies the price for your subscription plan: 20% off on Starter/Bronze, 30% on Scale/Silver, and 40% on Business/Gold and above. These are subscription tiers, not quantity thresholds within a run. Free/base prices stay unchanged, and the legacy $5 bundle stays flat.
| Event | Free/base | Starter / Bronze | Scale / Silver | Business / Gold+ |
|---|---|---|---|---|
| Company scanned | $0.01 | $0.008 | $0.007 | $0.006 |
| Job scraped | $0.0025 | $0.002 | $0.00175 | $0.0015 |
| Hiring summary | $0.03 | $0.024 | $0.021 | $0.018 |
| Optional AI brief | $0.05 | $0.04 | $0.035 | $0.03 |
| Legacy bundle | $5 | $5 | $5 | $5 |
Platinum and Diamond use the Gold price. The primary job event costs $2.50 / $2 / $1.75 / $1.50 per 1,000 jobs across these columns. Scans and optional AI are additional events; paid summaries apply to full-inventory and changes modes, not new-only output. Check the current Store Pricing table for your plan.
In the default full-inventory mode, the tested 55-job, one-board watchlist costs $0.1775 / $0.142 / $0.12425 / $0.1065 in event fees across these tiers. Its 15-role engineering-filter variant costs $0.0775 / $0.062 / $0.05425 / $0.0465. In that mode, unchanged matching jobs remain billable on repeat runs; discounts do not change event eligibility. In new-only mode, unchanged jobs are not emitted or charged, and operational summaries are free.
For full-inventory output at base prices, one board with 3 jobs and 1 summary has a $0.0475 event subtotal. Five boards with 100 total jobs and five summaries total $0.45. Twenty-five boards with 1,000 total jobs and 25 summaries total $3.50. Running that last example daily for 30 days totals $105 in events before optional AI and any separately billed services. These are arithmetic examples, not observed usage or an estimate for an unknown board.
Every output mode still charges for successfully fetched sources, including a response later found incomplete. In full-inventory mode, unchanged runs also return and charge for eligible open-job rows and useful summaries. Changes mode omits unchanged job rows but can still charge for useful summaries. New-only mode charges only the scan and emitted new-job events, plus optional completed AI if you enable it. Notification filtering alone does not change dataset billing. A useful board-wide company summary in full-inventory or changes mode can qualify even when no job rows match your output filters. Diagnostics, job_change evidence rows, closed-job comparison rows, failed source fetches, and summaries with neither open jobs nor proven closures do not qualify for the corresponding data events. A selected AI provider or proxy can have separate costs; consult the current Store pricing and your service plan.
Set an Apify run charge limit appropriate to the expected board size and alert frequency. A limit that aborts a complete scan prevents dependable closure checks. Inspect one complete accepted baseline before scheduling a large watchlist. Start weekly for a broad market map or daily for a smaller list whose changes you act on.
Sources, Reliability, and Troubleshooting
Supported public boards are Greenhouse, Lever, Ashby, SmartRecruiters, and Workable. Workday, iCIMS, private recruiter dashboards, applicant data, and authentication-required boards are outside this Actor's scope. Direct board URLs are more dependable than discovery from a company domain.
A missing job is marked closed only when the current source snapshot is complete and comparable with an earlier baseline. Source-integrity checks reject false completeness from malformed records, missing native job IDs/titles, unexplained normalization losses, repeated pagination, or inconsistent totals. Raising a cap fixes truncation; it does not fix an invalid source response.
When a run returns no jobs, inspect the Run Summary and Diagnostics before interpreting it. In new-only mode, these are separate key-value-store outputs, and an empty dataset is expected for the first baseline or an unchanged repeat. A source may be empty, unsupported, temporarily unavailable, or only partially read. Zero matching jobs after filtering can be valid; a failed request is not an empty hiring inventory. If a custom careers page cannot be discovered, paste its supported ATS board URL directly.
Public job postings can omit salary, descriptions, country, or posting dates. Location and remote labels depend on the information the board exposes. AI briefs summarize observed data and need review before business use. The Actor makes no claim about a company's future headcount, buying intent, or hiring success.
Hiring Monitor FAQ
How do I scrape Greenhouse, Lever or Ashby jobs into one CSV?
Add the public board URLs to atsBoardUrls, run the Actor, and export the dataset's Jobs view. When using the dataset API directly, select rows with record_type: "job"; summaries, changes and diagnostics have different record types. The three-source public task is a small working example.
Can I search every company hiring for a role?
This Actor monitors the boards you specify and can attempt discovery from company domains. It does not provide a global indexed job search. Use a broader jobs-search product when you do not already have a target company list. companyNames supplies display labels, not global company discovery.
Can I get change-only alerts without losing the full inventory?
Yes. Enable watch mode, reuse a watchlistId, configure your receiver, and keep notifyOnlyChanges: true. The first complete run saves a baseline without claiming all existing jobs are new. Subsequent complete comparisons can report new, changed, closed and reopened postings. The default dataset still includes eligible matching open jobs, which remain billable. Choose jobOutputMode: "new" for a jobs-only additions export with no unchanged-job or summary charges. Choose changes to export all proven change types with summaries. These output settings do not narrow the separate notification contract.
Why is my new-jobs-only dataset empty?
The first complete run establishes history, and later unchanged boards produce no rows. Check RUN_SUMMARY for comparison and saved-state status and inspect the separate diagnostics. A failed or incomplete scan also cannot establish new jobs; an empty dataset alone does not prove the scan was healthy. Do not reset the baseline on every run.
How often does the job posting monitor check for changes?
It checks when you run it. Use an Apify Schedule for daily or weekly comparisons and allow each run to finish before the next starts. This is scheduled observation, not an instant alert at the moment a company edits a posting. Each summary includes observation and comparison times.
Does a missing job prove that a vacancy was filled?
No. A complete comparable board can establish that a posting disappeared, which the Actor labels closed. It cannot tell whether the company filled, cancelled or moved the vacancy. A failed or partial fetch does not prove closure. Read change details before using a signal in a business decision.
Legal and Compliance
Use public job data according to the source's terms and your organization's policies. Keep receiver secrets private, choose sensible retention, and route job-market data only to approved destinations.