Careers Page Scraper — ATS Jobs Scraper by Domain avatar

Careers Page Scraper — ATS Jobs Scraper by Domain

Pricing

from $3.40 / 1,000 job posting founds

Go to Apify Store
Careers Page Scraper — ATS Jobs Scraper by Domain

Careers Page Scraper — ATS Jobs Scraper by Domain

Get open jobs from a company's careers page by entering its domain. Auto-detects Greenhouse, Lever, Ashby, Workable, Workday, Rippling, Recruitee, Teamtailor, Personio and BambooHR. Every job links to its source; unmatched companies are flagged, never reported as zero jobs.

Pricing

from $3.40 / 1,000 job posting founds

Rating

5.0

(6)

Developer

Tim Zinin

Tim Zinin

Maintained by Community

Actor stats

0

Bookmarked

9

Total users

5

Monthly active users

8 hours ago

Last modified

Features

Limited permissions

Share

Watch the 7-second demo — enter a company domain, see a public job row and its source link.

Careers Page Scraper — ATS Jobs Scraper by Domain

Enter a company domain and get its public job rows. The Actor checks the company's career page for an applicant tracking system (ATS) link, then tries a carefully checked board guess where appropriate. Every job links to the original posting. Supported: Greenhouse, Lever, Ashby, Workable, Workday, Rippling, Recruitee, Teamtailor, Personio and BambooHR. You do not need to know the ATS or board slug.

Input

{"domains": ["tinybird.co", "target.com", "enertiv.com"]}

Output — selected job rows from a real run on these three domains, 12 November 2026. Open jobs change between runs:

companyDomainprovidertitleurl
tinybird.coleverTechnical Growth Leadhttps://jobs.lever.co/tinybird/a911ccc8-f028-4c4c-ad0f-2a392038a84c
target.comworkdayAnalyst Merch Payablehttps://target.wd5.myworkdayjobs.com/job/BangaloreIndia/Analyst-Merch-Payable_R0000449373
enertiv.comripplingAccount Development Managerhttps://ats.rippling.com/enertiv-jobs/jobs/1f2627a1-d994-4043-8a06-d8e66c2f902f

Rows also carry location, department, remote flag and publish date where the source provides them. If the Actor cannot identify a company's board, it returns a free unresolved row, not a false "0 jobs".

Price: $4 per 1,000 billable jobs plus $0.01 per run on the Apify Free plan at the default 512 MB memory; paid plans pay less. Status rows are free. A run with 20 billable jobs costs $0.09. Try it for free; no card is needed on the Apify Free plan. Check the live pricing panel before a larger run.

Company domain enters the scraper, which discovers a public ATS and returns source-linked jobs with coverage status

Enter one company domain; inspect the public source and the result before scaling a list.

What it does

  1. Checks the company’s own public career page for a link to a supported ATS board. This first-party link is the strongest resolution path.
  2. Where appropriate, tries a board slug derived from the domain. A guessed board is accepted only with real openings, and job rows are billed only when the board’s own owner signal supports the submitted company. Workday is never guessed from a domain.
  3. Reads the supported public job feed, normalizes jobs into one Dataset, and states when coverage is empty, incomplete or unresolved. The Actor checks company-host robots rules for Personio and BambooHR.

Who uses it

  • Sales and RevOps: see which target accounts are hiring for roles that signal a need you serve.
  • Recruiters: pull open roles at target companies without looking up each ATS board.
  • Job boards and newsletters: collect current openings from a list of employers in one schema.
  • Analysts and investors: track hiring at a set of companies on a schedule.

Export results as JSON, CSV or Excel, call the Actor through the API or MCP, or connect it to Zapier, Make or n8n.

Ten supported public ATS systems and the main result types

Ten supported systems; a board that cannot be resolved is never reported as empty.

Public ATSHow it is foundReading depth
Greenhouse, Lever, Ashby, WorkableCompany careers-page link or a carefully checked board-slug fallback.Their public board response is read without the maxJobsPerCompany input cap.
Rippling, Recruitee, Teamtailor, Personio, BambooHRCompany careers-page link or supported board-slug fallback, where available and permitted.maxJobsPerCompany caps the paginated read; an incomplete result is disclosed.
WorkdayOnly a link from the company’s own careers page; tenants cannot be safely guessed from a domain.maxJobsPerCompany caps the paginated read; a deep board takes longer.

A source may change, block access, or use a different careers system. Coverage is per submitted company and run, not a guarantee that every company on a named platform will resolve. SmartRecruiters is excluded because its central Posting API has disallowed general crawlers in the checked rules; iCIMS and custom sites are outside this Actor’s current coverage. Recruitee’s public Careers Site API currently permits the route used here, but its published plan to require a token from February 2027 may change that coverage. Check current source rules before relying on a workflow.

Results you can trust and results you should review

ResultMeaningCharge
Job row with found: trueA public job on a board attributed to the submitted company by the Actor’s evidence rule. Keep the source URL and observation time.$0.004 per job on the current FREE tier.
Job row with found: falseA real posting was delivered, but the guessed board’s ownership was rejected or could not be confirmed. It must not be treated as confirmed hiring by that company.Free.
resolved-zeroAn attributable supported board returned no current openings at observation time.Free.
unresolvedThe Actor could not identify an attributable supported board. This is not proof of zero jobs.Free.
source-error, invalid-domain, errorSource or input could not be checked reliably; inspect the reason and retry guidance.Free.
resolved-truncatedSome jobs were delivered, but the configured depth or a later source page limited completeness.Notice is free; delivered confirmed jobs may be billable.
run-noticeA run-level explanation, including a spend cap or early stop on an unresolvable list.Free.

found: true marks an attributed job that can be billed, not just "a row that looks like a job." Check isJobRow, recordType, resolutionStatus and billingEligibility when routing results into a pipeline. A run marked SUCCEEDED can still contain only unresolved or error rows; inspect the Dataset before calling it useful. An early stop can leave later domains unprocessed; the free run notice says how many.

Input

FieldWhat to enterLimit or default
domainsBare company domains or full company URLs, for example figma.com. Direct domains take priority over datasetId.Up to 100; form prefill apify.com, which returned Ashby jobs in a bounded 12 November 2026 trial.
datasetIdAn upstream Apify Dataset containing company domains. Select it with the Dataset picker to grant read access; an Integration fills it automatically from the triggering run.Optional.
maxConcurrencyCompanies resolved in parallel.1–20, default 5.
maxJobsPerCompanyDepth for Workday, Rippling, Recruitee, Teamtailor, Personio and BambooHR.1–5000, default 500.

A full URL such as https://www.figma.com/careers is normalized to the company domain; this is not yet a direct board-URL input. The Actor can read common upstream fields such as companyDomain, domain, website and url from a selected Dataset. It does not currently accept a company name alone, job filters or an “only new jobs” mode.

Examples of job rows and coverage states

The examples below are selected fields from real runs unless marked illustrative. They show the row contract; job titles, counts, URLs and source rules can change. The first figma.com example is separate from the bounded apify.com trial.

For input {"domains":["figma.com"],"maxConcurrency":1,"maxJobsPerCompany":100}, a Greenhouse board link on the company’s own site produced this job on 4 August 2026:

{
"companyDomain": "figma.com",
"provider": "greenhouse",
"providerSlug": "figma",
"jobId": "5615966004",
"title": "Enterprise Solutions Consultant (Bengaluru, India)",
"location": "Bengaluru, India",
"department": null,
"isRemote": false,
"url": "https://boards.greenhouse.io/figma/jobs/5615966004?gh_jid=5615966004",
"publishedAt": "2025-08-12T13:15:50.000Z",
"resolvedVia": "careers-page",
"found": true,
"scrapedAt": "2026-08-04T11:12:33.399Z"
}

A job found after a careful board-slug guess

The Actor derived a candidate board from datadoghq.com and found a live Greenhouse posting:

{
"companyDomain": "datadoghq.com",
"provider": "greenhouse",
"providerSlug": "datadog",
"jobId": "7984184",
"title": "Senior Partner Manager - Channels",
"location": "Tokyo, Japan",
"department": null,
"isRemote": false,
"url": "https://careers.datadoghq.com/detail/7984184/?gh_jid=7984184",
"publishedAt": "2026-06-08T00:54:12.000Z",
"resolvedVia": "slug-guess",
"found": true,
"scrapedAt": "2026-08-04T11:12:36.259Z"
}

Unresolved is different from zero

A 10 November 2026 run on the current ten-system build could not read a candidate Personio board for fidel.team because that board's robots rules disallowed the XML route. The result was unresolved, not zero jobs:

{
"companyDomain": "fidel.team",
"provider": "personio",
"providerSlug": "fidel",
"resolvedVia": "slug-guess",
"resolutionStatus": "unresolved",
"jobCount": null,
"found": false,
"error": "robots.txt disallows /xml",
"scrapedAt": "2026-11-10T08:18:45.597Z"
}

A genuinely empty attributable board returns resolved-zero with jobCount: 0. This example is illustrative, not a live capture:

{
"companyDomain": "example-hiring-freeze.com",
"provider": "lever",
"providerSlug": "example-hiring-freeze",
"resolvedVia": "careers-page",
"resolutionStatus": "resolved-zero",
"jobCount": 0,
"found": false,
"error": null,
"scrapedAt": "2026-08-04T11:20:00.000Z"
}

A disclosed depth limit

With maxJobsPerCompany: 1, a 12 November 2026 target.com Workday run delivered one job and then one free resolved-truncated notice. Workday’s reported total was not treated as trustworthy:

{
"companyDomain": "target.com",
"provider": "workday",
"providerSlug": "target.wd5.myworkdayjobs.com/targetcareers",
"resolvedVia": "careers-page",
"resolutionStatus": "resolved-truncated",
"jobCount": 1,
"declaredTotal": null,
"found": false,
"error": "job list is incomplete: delivered 1 row(s) here, but the source does not report a trustworthy total count for this company — there may be more open roles than the 1 delivered here. This Actor's job depth limit (maxJobsPerCompany=1) was reached. Raise maxJobsPerCompany on input (up to 5000) to read deeper.",
"scrapedAt": "2026-11-12T11:11:37.086Z"
}

Ownership check before billing a guessed board

airtable.com was confirmed by the board’s owner signal and billed. atlas.com found a real Ashby board owned by a different domain, so its job was delivered free. chime.com had an inconclusive company-name match, so its job was also delivered free:

{
"companyDomain": "airtable.com",
"provider": "greenhouse",
"providerSlug": "airtable",
"jobId": "8391589002",
"title": "Account Executive, SLED",
"location": "Austin, TX; Remote - US",
"department": null,
"isRemote": true,
"url": "https://job-boards.greenhouse.io/airtable/jobs/8391589002",
"publishedAt": "2026-01-26T22:00:52.000Z",
"resolvedVia": "slug-guess",
"attributionConfirmed": true,
"attributionNote": "Greenhouse's job board is named \"Airtable\", which matches the requested domain airtable.com.",
"found": true,
"scrapedAt": "2026-08-04T16:47:33.360Z"
}
{
"companyDomain": "atlas.com",
"provider": "ashby",
"providerSlug": "atlas",
"jobId": "dae00fcb-35a5-4559-8114-7553138b3ea3",
"title": "Founding Applied AI Engineer",
"location": "San Francisco",
"department": "Engineering",
"isRemote": false,
"url": "https://jobs.ashbyhq.com/atlas/dae00fcb-35a5-4559-8114-7553138b3ea3",
"publishedAt": "2026-02-24T18:52:51.098Z",
"resolvedVia": "slug-guess",
"attributionConfirmed": false,
"attributionNote": "Ashby's job board declares its own company website as atlascard.com, which does NOT match the requested domain atlas.com — this board most likely belongs to a different company.",
"found": false,
"scrapedAt": "2026-08-04T16:47:35.898Z"
}
{
"companyDomain": "chime.com",
"provider": "greenhouse",
"providerSlug": "chime",
"jobId": "8609153002",
"title": "Analyst, Investor Relations",
"location": "San Francisco, CA, USA",
"department": null,
"isRemote": false,
"url": "https://boards.greenhouse.io/chime/jobs/8609153002?gh_jid=8609153002",
"publishedAt": "2026-07-22T18:36:41.000Z",
"resolvedVia": "slug-guess",
"attributionConfirmed": null,
"attributionNote": "Greenhouse's job board is named \"Chime Financial, Inc\", which STARTS WITH the requested domain chime.com but adds a real word this Actor does not strip (a business descriptor, not legal boilerplate) — this looks like it could be your company, but a name alone does not prove it: Greenhouse does not publish this board's owner website, and a genuinely unrelated company with a similar name would read exactly the same way.",
"found": false,
"scrapedAt": "2026-08-04T17:31:05.538Z"
}

These examples show why attributionConfirmed is true, false or null. A company-name signal cannot always prove ownership; a genuine rebrand may remain unconfirmed and free. The Actor never turns an uncertain board into a paid claim.

Field guide

Field groupHow to use it
companyDomain, inputRef, entityId, observedAtKeep the input and stable row identity with observation time for later comparison.
provider, providerSlug, resolvedViaName the ATS and whether it came from the company’s own page or a candidate slug.
title, location, department, isRemote, url, publishedAtPublic job facts; url is the source link. publishedAt may be absent.
attributionConfirmed, attributionNote, billingEligibility, foundSeparate a real posting from a confirmed and billable company posting.
resolutionStatus, jobCount, declaredTotal, partialDistinguish a confirmed zero from unresolved or incomplete coverage. Workday’s unreliable declared total is not presented as fact.
confidenceScore, confidenceBand, confidenceRisks, sourceEvidence, dataGapsShow how well the available evidence supports the classification and what remains unknown. Confidence is not a sales score.
recommendedAction, safeToAutomate, failureType, retryableReview hints and operational handling. They do not authorize outreach or other external action.

The Dataset includes additional decision fields such as jobFunction, seniority, freshnessBand, negativeSignals, firstSeenAt and lastSeenAt. In a stateless run, first and last seen can both equal the observation time; this does not prove a job’s age. Read schemaVersion before strict downstream mapping and retain nulls and source evidence in exports.

Pricing and free outcomes

The current pay-per-event prices are $0.01 per start event and $0.004 per confirmed job row on the FREE tier, or $4 per 1,000 billable jobs plus start events. At the current default memory of 512 MB there is one start event; Apify's pricing rule can charge more start events at higher memory settings. No monthly seat or minimum number of jobs is required. Apify may apply account-tier discounts; the live pricing panel is the source of truth for your run.

From 19 November 2026 the pricing panel also lists two optional events, enriched-job ($0.002) and ats-detected ($0.003). They are charged only when an optional mode is switched on; a default run does not use them.

A resolved but empty board, an unrecognized ATS, an unreachable or disallowed source, invalid input, a truncation notice and a run-level notice do not create a job-result charge. A real job on a guessed board is also free if the ownership check rejects the match or cannot confirm it. A job found through the company’s own careers-page link is attributed through that first-party link. Review found and billingEligibility together; do not count free unconfirmed jobs as confirmed company hiring.

For a large board, maxJobsPerCompany limits how many paginated jobs are read per company. The limit affects both completeness and cost; a free resolved-truncated row says when more may exist. A later source-page error can also make a result partial, and raising the cap will not fix that error. When starting through the API, set maxTotalChargeUsd to the maximum charge you authorize for the run, and review how many domains and jobs remain unfinished if the cap stops it.

Run it from another workflow

Apify Integration or Dataset

Open the Actor that produces company domains, choose Integrations → Add integration → Careers Page Scraper, and leave datasetId empty in the prefilled input. The triggering run supplies its default Dataset. For a manual Dataset, use the picker so this run receives READ access. Review a small sample of extracted domains before using a large upstream list.

cURL

Keep the token in a secret manager, never in a Dataset or screenshot:

curl -sS -X POST 'https://api.apify.com/v2/acts/zinin~careers-page-scraper/runs?waitForFinish=60' \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H 'Content-Type: application/json' \
--data '{"domains":["apify.com"],"maxConcurrency":1,"maxJobsPerCompany":100}'

The run response contains defaultDatasetId. After the run succeeds:

curl -sS "https://api.apify.com/v2/datasets/$DEFAULT_DATASET_ID/items" \
-H "Authorization: Bearer $APIFY_TOKEN"

JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('zinin/careers-page-scraper').call({
domains: ['apify.com'], maxConcurrency: 1, maxJobsPerCompany: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems({ clean: true });
for (const row of items) console.log(row.companyDomain, row.recordType, row.title, row.url);

Python

import os
from apify_client import ApifyClient
client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('zinin/careers-page-scraper').call(run_input={
'domains': ['apify.com'], 'maxConcurrency': 1, 'maxJobsPerCompany': 100,
})
for row in client.dataset(run['defaultDatasetId']).iterate_items(clean=True):
print(row.get('companyDomain'), row.get('recordType'), row.get('title'), row.get('url'))

Apify MCP

{"name":"call-actor","arguments":{"actor":"zinin/careers-page-scraper","input":{"domains":["apify.com"],"maxConcurrency":1,"maxJobsPerCompany":100}}}

A webhook or scheduled workflow should first check that the Actor run ended SUCCEEDED, then inspect job, status and notice rows. Preserve run ID, input, source URLs and entityId; send safeToAutomate: false rows to review. A failed run or unresolved row must never be converted into “no hiring.” Make destination writes idempotent.

Limits and common questions

Why might a known Workday company remain unresolved? The Workday tenant can differ completely from the company domain. This Actor follows a link from the company’s own career page instead of guessing a tenant. If that page does not expose the board link, the result can be unresolved even when a board exists.

Why not accept an empty guessed board? Some providers return a valid HTTP 200 and zero jobs for a registered but unrelated board. Without a first-party company link, this is not proof that the guessed board belongs to the submitted domain. Only a non-empty candidate proceeds to ownership checking.

What if a source is blocked or changes? An inaccessible or changed source returns a disclosed status or failure; it does not become a confirmed zero. Personio and BambooHR routes are checked against their company-host robots rules. Recruitee uses a company-hosted careers-site API rather than its disallowed central API. Never infer permission solely from the fact that a job page is public.

Why may a large board be slow? Workday and other paginated providers need multiple page requests. A larger maxJobsPerCompany can increase time and charge. Test one domain before scaling.

Why did my list stop early? If 14 completed company checks in a row are unresolved and no company has resolved yet, the Actor stops the remaining list and emits a free run-notice with the number not attempted. A single resolved company lifts this guard for the rest of the run. In-flight checks at concurrency above 1 can finish after the threshold. Source errors and invalid domains do not count toward the unresolved streak.

Does a job prove buying intent or future hiring? No. It is a public opening on a supported board at observation time. The Actor does not access private applicants or pipelines, submit applications, or contact anyone. Verify material facts at the source and apply your own policies before using them in decisions.

Can I use it for only new jobs or filter by title? Those controls are not in the current Input. Schedule runs and compare Dataset snapshots in your own system if you need a monitor today; treat failed runs and partial boards as gaps, not changes. Filters and a built-in new-jobs mode are product candidates, not current features.

How should I report a wrong result? Open an issue on this Actor’s Apify page with the run ID, redacted input, affected row, source URL, expected result and observed result. Do not include tokens or private customer data.

Built by zinin. Questions? Telegram @timzinin.

⌂ 换网址