Careers Page Scraper — Open Roles from Any Company's Site avatar

Careers Page Scraper — Open Roles from Any Company's Site

Pricing

from $0.60 / 1,000 job postings

Go to Apify Store
Careers Page Scraper — Open Roles from Any Company's Site

Careers Page Scraper — Open Roles from Any Company's Site

Give company domains, get their open roles. Finds each careers site, recognises the platform — 14 hosted ATSs, Eightfold, Phenom, Jibe, iCIMS, Google and Amazon — and falls back to the structured data on the company's own pages. One normalized row per job. No browser, no key.

Pricing

from $0.60 / 1,000 job postings

Rating

0.0

(0)

Developer

Insight Solutions

Insight Solutions

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Security

Limited permissions

Share

Company domain in, open roles out. Give this Actor a list of company domains — netflix.com, cvshealth.com, costco.com — and it finds each company's careers site, recognises the platform it runs on, and returns every open role as one normalized row: title, department, location, country, remote flag, employment type, seniority, salary when published, posted date, job and apply URLs, a teaser, and the full description when you ask for it.

It reads the platforms the big employers actually use — Eightfold, Phenom, Jibe and iCIMS career sites, Google Careers, Amazon Jobs — and the 14 hosted applicant tracking systems of our ATS Jobs API (Greenhouse, Lever, Ashby, Workday, SAP SuccessFactors and 9 more). Where no platform is recognised, it reads the structured data on the company's own careers pages: schema.org JobPosting (JSON-LD or microdata), __NEXT_DATA__, job links, job feeds and the sitemap. HTTP only — no browser, no login, no API key — and it never reads LinkedIn, Indeed or Glassdoor.

No recruiter contacts, by design: names, e-mail addresses and phone numbers are removed from every description. $1.00 per 1,000 job postings plus $1.00 per 1,000 careers sites resolved on the FREE tier; a company we cannot resolve is free.

Already have board slugs (greenhouse:stripe)? ATS Jobs API is the direct route. Want one row per company with hiring velocity and a surge flag? That is Hiring Signals API. Have company domains and no idea what they run? This one. Want startup jobs by role and city, with salary, equity and company stage? That is Wellfound Startup Jobs API.

Try it in 30 seconds

This is the Store prefill; paste it and run:

{ "companies": ["netflix.com", "cvshealth.com", "stripe.com", "shopify.com", "ramp.com", "cloudflare.com"], "maxJobsPerCompany": 100 }

Six companies on five routes: Netflix on Eightfold, CVS Health on Phenom, Shopify's own careers pages (microdata JobPosting), Stripe and Cloudflare on Greenhouse, and Ramp on Ashby. In our offline test suite they give 65 jobs and 6 careers sites — the fixtures hold one page of each platform's answer; a live run reads every page up to 100 jobs per company (Netflix lists about 400, CVS Health about 19,000, Stripe about 750).

Only remote engineering roles posted this month, across a target list:

{ "companies": ["netflix.com", "pepsico.com", "google.com", "spotify.com"], "keywords": "engineer", "remoteOnly": true, "postedWithinDays": 30 }

A careers page or a board you already know works too:

{ "companies": ["https://www.shopify.com/careers", "eightfold:explore.jobs.netflix.net?domain=netflix.com", "greenhouse:stripe"], "includeDescriptions": true }

From code — client.actor("insight.solutions/careers-page-jobs-api").call(run_input={"companies": ["netflix.com"]}) with apify-client, or POST https://api.apify.com/v2/acts/insight.solutions~careers-page-jobs-api/run-sync-get-dataset-items.

What comes back

A job row (from the captured CVS Health answer; null and empty columns cut, 49 locations shortened to two):

{
"rowType": "job",
"input": "cvshealth.com",
"company": "CVS Health",
"companyDomain": "cvshealth.com",
"platform": "phenom",
"jobId": "R1065518",
"title": "Senior Data Engineer",
"url": "https://jobs.cvshealth.com/us/en/job/R1065518/Senior-Data-Engineer",
"applyUrl": "https://cvshealth.wd1.myworkdayjobs.com/CVS_Health_Careers/job/IL---Work-from-home/Senior-Data-Engineer_R1065518/apply",
"department": "Innovation and Technology",
"team": "Data and Analytics",
"location": "Work at Home, Illinois, United States (+48 more locations)",
"locations": [
{ "city": null, "region": "Illinois", "country": "United States", "isRemote": true, "note": null },
{ "city": null, "region": "Alabama", "country": "United States", "isRemote": true, "note": null }
],
"country": "US",
"isRemote": true,
"workplaceType": "remote",
"employmentType": "FullTime",
"seniority": "senior",
"postedAt": "2026-10-29T00:00:00.000+0000",
"descriptionTeaser": "We are looking for a Senior Data Engineer to design and implement data pipelines supporting analytical and data science workloads. …",
"skills": ["sql", "data modeling", "data pipeline development", "python", "etl", "…"],
"scrapedAt": "2026-11-03T12:00:00.000Z"
}

A site row, one per company resolved, after its jobs (from the captured Netflix answer):

{
"rowType": "site",
"input": "netflix.com",
"company": "Netflix",
"companyDomain": "netflix.com",
"platform": "eightfold",
"careersUrl": "https://explore.jobs.netflix.net/careers",
"resolvedBy": "registry",
"jobCount": 138,
"jobsReturned": 10,
"departments": ["Engineering", "Data & Insights"],
"countries": ["US", "PL"],
"remoteShare": 0.5,
"requests": 2
}

A company that could not be read comes back as a free diagnostic row naming what was tried and what was found — careers-page-not-found, careers-page-not-supported, no-jobs-parsed (with platformHints[]: what the pages are built on), robots-disallowed, blocked, rate-limited or timeout — and the last row of every run is a free summary.

Use cases

  • Account-based sales and recruiting agencies — which target accounts are hiring, for what, where: a domain list in, a table of open roles out, whatever careers platform each company runs.
  • Hiring-watch boards — schedule it weekly over a watchlist of large employers and chart roles per department, per country, remote share.
  • Market and competitive research — where a company is building teams (departments[], countries[] on the site row), and which skills it asks for (skills[] on Phenom sites).
  • Job aggregators and niche boards — first-party postings straight from the employer's own site, with the employer's own job and apply URLs, no reposted copies.
  • Data enrichment — add "careers platform" and "open roles" to a company list: the site row alone says which platform a company uses and how many roles it lists.

How it compares

  • Company domain in, every platform we recognise, structured data for the rest, no browser. You do not need to know whether a company runs Eightfold, Phenom, Workday or its own site; the Actor works it out, cheapest way first, and says how (resolvedBy).
  • The platforms' own data, not guesses at the HTML. Eightfold, Phenom, Jibe and Amazon are read from the JSON their own careers sites load; Google Careers from the data embedded in its results pages; the 14 ATSs from their public job feeds; a company's own pages from the schema.org JobPosting markup it publishes for search engines.
  • One row shape across 20 platforms and four kinds of structured data, the same row shape as ATS Jobs API, so the two can be loaded into one table.
  • Honest about what it cannot read. A JavaScript-only careers site, an API that answers only its own site's session, a bot wall: each is a free diagnostic row that says which, never a charge and never a workaround.
  • No recruiters. Contact names, e-mail addresses and phone numbers are removed from descriptions, and the visitor blocks some platforms echo are never read.

Which careers platforms are recognised

Platform (platform)How it is recognisedHow it is readFields beyond the common set
eightfold — Eightfold*.eightfold.ai, or a careers page carrying Eightfold's assets and config (Netflix: explore.jobs.netflix.net)GET /api/apply/v2/jobs?domain=…&start=…&num=10&query=…, 10 a page; descriptions from /api/apply/v2/jobs/<id> with includeDescriptionsteam = business unit, workplaceType, postedAt/updatedAt
phenom — Phenomthe page's phApp config (widgetApiEndpoint, refNum)one POST <host>/widgets with the site's own refineSearch body, 10 a pageskills[] (the platform's own extraction), descriptionTeaser, team = sub-category
jibe — Jibe (iCIMS career sites)window._jibe = { "cid": … } on the page, or a *.jibeapply.com host (Costco, PepsiCo)GET <host>/api/jobs?page=N&keywords=…, 10 a pagefull description in the list. Intermittent: in our live tests both Jibe sites answered every request for two runs, then HTTP 403 to Apify datacenter IPs on page 1 — results from Jibe sites may come and go (a free blocked row when they refuse)
icims — iCIMS classic boardsa <client>.icims.com/jobs host or linkthe board's own HTML listing (/jobs/search?ss=1&in_iframe=1), "Page N of M"; posting pages' JSON-LD with includeDescriptions. iCIMS boards' robots.txt disallows automated clients (PepsiCo's, seen live), so an iCIMS company normally comes back as a free robots-disallowed row — a company with a Jibe site over its iCIMS board is read through the Jibe site insteaddepartment = job function, teaser
google-careers — Google Careersgoogle.com/about/careers, careers.google.comthe results page's embedded data (AF_initDataCallback, ds:1): the first page only, 20 jobs per run — google.com's robots.txt disallows the results with a page= parameterfull description in the list
amazon-jobs — Amazon Jobs (experimental)amazon.jobsGET /en/search.json?…&result_limit=100, 100 a pageteam = business category, teaser
greenhouse, lever, ashby, workable, recruitee, smartrecruiters, teamtailor, personio, breezy, workday, jazzhr, bamboohr, rippling, successfactorsa board link on the company's careers pages, a board URL or slug, or the bundled registryexactly as ATS Jobs API reads them — the same adapter codesalary where the ATS publishes it
structured-dataschema.org JobPosting (JSON-LD or microdata) on the careers page, or on the detail pages its job links lead to (Shopify)the page, then each posting page — at most maxJobsPerCompany, and none after three detail pages in a row carry no JobPostingsalary* from baseSalary, employmentType, postedAt
next-dataa __NEXT_DATA__ (or plain-JSON window.__NUXT__) array of job-shaped objectsthe page itself, no extra requestwhatever the array names
sitemapjob-posting URLs in the site's sitemap.xml (an index is narrowed to three partitions of at most 5 MB, job-named ones first)each posting page, as for structured-dataas structured-data
job-feedan RSS or Atom feed the careers page links whose title says jobsthe feed's items that link to a postingpostedAt from the item

Large employers already verified (zero requests to resolve): Netflix (Eightfold), CVS Health (Phenom), Costco and PepsiCo (Jibe), Google and Alphabet (Google Careers), Amazon (Amazon Jobs), The Home Depot (Workday), Shopify and Spotify (their own pages), plus every company in ATS Jobs API's bundled registry (Stripe, Cloudflare and NVIDIA among them).

Looked at, and honestly not readable: Apple (jobs.apple.com builds its results in the browser and its search API answers an empty list without the site's own session), Walmart (its search API answers a "Redirecting…" page instead of data), SpaceX (a script-only application with no job data in the page). These come back as a free careers-page-not-supported row at no request.

How a company is resolved

Cheapest first, one platform per company, and the answer is cached for 30 days in the run's key-value store, so a repeat run skips straight to the jobs.

  1. The entry is already a board — greenhouse:stripe, eightfold:explore.jobs.netflix.net?domain=netflix.com, phenom:jobs.cvshealth.com/us/en, jibe:careers.costco.com, icims:uscareers-pepsico.icims.com, google-careers:, amazon-jobs:, or a board URL (boards.greenhouse.io/…, *.myworkdayjobs.com/…, *.eightfold.ai, *.icims.com, *.jibeapply.com). resolvedBy: input-board.
  2. Known sites and the registry — the large employers above and ATS Jobs API's bundled board registry, by domain. No request. resolvedBy: registry. Then the site cache (cache).
  3. The careers URL you gave, read for a platform or an ATS board link (careers-url).
  4. The 14 ATSs: ATS Jobs API's own detection reads /careers, /jobs, /, careers.<domain>/, /company/careers and /about/careers for a board link (five seconds a page, 30 seconds in all) — ats-detection. A page that is an enterprise careers site wins over an ATS link it carries (a Phenom site links its Workday apply flow).
  5. Enterprise platforms: the same pages (served from the run's cache, no second request) and up to four careers links found on them — jobs.<domain>, <brand>jobs.com, lifeat<brand>.com — read for Eightfold, Phenom, Jibe, iCIMS, Google Careers and Amazon Jobs (platform-detection).
  6. Structured data on the careers pages read: JobPosting nodes, __NEXT_DATA__, job links and their detail pages, job feeds, then the sitemap (structured-data).
  7. Nothing: a free careers-page-not-found row (no page answered; candidatesTried[]) or no-jobs-parsed (pages were read and nothing was recognised; platformHints[] says what they are built on — next.js, angular, taleo, workday, client-rendered — so you can pass the right board).

robots.txt is read once per site per run and honoured for every page: a disallowed page is never requested, and a company whose careers pages are all disallowed is a free robots-disallowed row. Requests to any one host go one at a time and at least one second apart — further apart when the host's robots.txt declares a Crawl-delay (honoured up to 10 seconds; pepsicojobs.com and careers.costco.com ask for 5). A platform's JSON API is paced by its host's Crawl-delay too, though robots.txt rules gate pages only.

Input reference

FieldTypeDefaultWhat it does
companiesstring[]prefill: 6 companiesCompany domains, careers-page URLs or boards, up to 500 companies. An entry listed twice is read once.
keywordsstring""Sent to the platforms that search (Eightfold, Phenom, Jibe, iCIMS, Google Careers, Amazon Jobs); elsewhere every word must appear in the title.
locationsstring[][]Keep a job when its location text or a parsed city, region or country contains one of these.
countriesstring[][]ISO codes or country names; a US state or Canadian province implies its country. An unknown value is ignored and reported in a free row.
remoteOnlybooleanfalseOnly jobs the platform marks remote (never inferred from the title).
postedWithinDaysinteger00–3,650. Jobs posted within this many days; a job with no posting date is kept.
includeDescriptionsbooleanfalseThe full description as plain text (at most 20,000 characters). One detail request per job where the list carries none (Eightfold, Phenom, iCIMS).
maxJobsPerCompanyinteger500 (prefill 100)1–5,000 postings read per company.
maxPagesinteger201–100 result or listing pages per company.
maxConcurrencyinteger61–10 companies at once; requests to one host are always sent one at a time.
maxRunSecsinteger24030–3,600. Rows already returned are kept — and billed — when it runs out; each company never reached gets a free timeout row.
proxyConfigurationobject{ "useApifyProxy": true }Careers pages and platform APIs go through it; Apify datacenter by default. The 14 ATSs' public job feeds are read direct, as ATS Jobs API reads them.

A run with nothing usable — no company, more than 500, or no entry that is a domain, a careers URL or a board — finishes FAILED before a single request, with a free invalid-input row saying why. Anything else finishes SUCCEEDED: a run whose companies all came back as diagnostics says "N companies, no careers site resolved" and bills nothing.

Output reference

Every row has the same columns, null where a column does not apply, so the dataset exports as one table. rowType is job, site, diagnostic or summary.

On every row: ok, rowType, input (your entry, as typed), company, companyDomain, platform, scrapedAt.

Job rows (paid, the primary event) — the ATS Jobs API row under these names: jobId, title, url, applyUrl, department, team, location (as published), locations[] (city, region, country, isRemote, note), city, country (ISO code when recognised), isRemote, workplaceType (remote · hybrid · onsite), employmentType (FullTime · PartTime · Contract · Temporary · Internship · Volunteer · Other), seniority (from the title), salaryMin, salaryMax, salaryCurrency, salaryPeriod (only when the platform publishes structured pay), postedAt, updatedAt, description (with includeDescriptions: plain text, at most 20,000 characters, contacts removed), descriptionTeaser (at most 300 characters), skills[] (Phenom).

Site rows (paid, one per company resolved, after its jobs): careersUrl, resolvedBy, jobCount (the platform's own total when it gives one, else jobs read), jobsReturned, departments[], countries[], remoteShare, requests (what the company cost; pages served from the run's cache are not counted), note (why fewer were read than listed: a cap, the deadline, the maximum charge).

Diagnostic rows (free): errorType, error, careersUrl, candidatesTried[], platformHints[], requests.

Summary row (free, last): note (the status message), jobsReturned, requests, stats (companies, sites resolved, jobs read, returned, filtered and de-duplicated, platforms, diagnostics by type, what was charged).

errorTypeMeaning
careers-page-not-foundNo careers page of the company answered, or the platform's board is gone; candidatesTried[] lists what was tried.
careers-page-not-supportedA careers site this Actor cannot read without a browser or the site's own session (Apple, Walmart, SpaceX, an API that answers a web page instead of data, a cut-off answer).
no-jobs-parsedCareers pages were read and carry nothing this Actor recognises; platformHints[] says what they are built on.
robots-disallowedrobots.txt disallows this Actor on the company's careers pages; they were not read.
blockedA bot wall (HTTP 403 on first contact, a challenge page). One request was made; walls are never worked around.
rate-limitedThe site refused the run with HTTP 429, or with a plain 403 after it had already served this run (a results page or two). One request was made, nothing was retried; try again later — the jobs read before it are kept, and the site row's note says where it stopped.
timeoutmaxRunSecs ran out before the company was reached or resolved.
invalid-inputAn entry or a value that cannot be used. When nothing usable is left, the run is FAILED.

Pricing

EventWhat it isFREEBRONZESILVERGOLD
actor-startOnce per run, only after the run has returned a paid row$0.001$0.001$0.001$0.001
jobOne open role returned$0.001$0.001$0.0008$0.0006
siteOne company whose careers site was resolved, after its jobs$0.001$0.001$0.001$0.001

$1.00 per 1,000 job postings plus $1.00 per 1,000 careers sites resolved; a company we can't resolve is free.

RunCost
The prefill as the offline test suite runs it — 65 jobs, 6 sites$0.072
The prefill live at 100 jobs per company (≈ 430 jobs, 6 sites)≈ $0.44
25 large employers at 200 jobs each (the example task)≈ $5.03
The same at GOLD≈ $3.03
100 company domains, 60 resolved, 80 jobs each≈ $4.86
50 domains, none resolvable$0.00, SUCCEEDED

Charging is charge-after-push: rows are in your dataset before the event is recorded. A company's jobs are checked against ACTOR_MAX_TOTAL_CHARGE_USD together with its site row before anything is pushed; when the budget cannot cover them all, the jobs it can cover are returned, the site row says so, and the run stops cleanly — never a row past the ceiling. Never charged: diagnostics, the summary, filtered-out postings, duplicates, a company we could not resolve, and a run that returns nothing (start fee included). A company that resolved but has no role matching your filters is one site event: that is the answer ("Netflix lists nothing matching").

Limits

  • JavaScript-only careers sites without structured data are not readable. A site that draws its job list in the browser from an API this Actor does not know, and publishes no JobPosting markup, job links, feed or sitemap entries, comes back as no-jobs-parsed with platformHints[]. SpaceX is the captured example.
  • Some enterprise APIs answer only their own site's session: Apple's search API returns an empty list, Walmart's a redirect page. They are named in careers-page-not-supported rows, not worked around.
  • iCIMS boards disallow automated clients in robots.txt, so a company that hires only through an iCIMS board is a free robots-disallowed row; the iCIMS reader is kept for boards that allow it.
  • Google Careers: 20 jobs per run — the first results page (newest matching your keywords); robots.txt disallows the later pages, so they are never requested. Narrow with keywords to reach the roles you want.
  • Paced, so not instant: one request at a time and at least one second apart per host, or the host's robots.txt Crawl-delay (up to 10 s). A company read through 10 result pages takes at least 9 s — at a 5-second Crawl-delay, 45 s; a structured-data company with 25 detail pages at least 25 s. Companies run in parallel (maxConcurrency).
  • Amazon Jobs is experimental. Its search answer was cut short in our captures; when the full answer does not arrive, the run says so in a free row rather than returning half a page.
  • Bot walls end the company. One request, a free blocked row; no proxy rotation, no browser, no retry.
  • Jibe sites (iCIMS career sites) are intermittent. In our live tests careers.costco.com and www.pepsicojobs.com served full runs, then answered HTTP 403 to Apify datacenter IPs on the first request after a few runs in an hour. Expect some runs to return a free blocked row for them; space runs hours apart.
  • Repeated runs can be rate-limited. A careers site that served the first runs of the hour may refuse the next (rate-limited, free). Schedule watchlists hours apart, not minutes.
  • The 14 ATS feeds are read direct with a 60-second request timeout (a board with full descriptions — Stripe's on Greenhouse — is several megabytes); a board slower than that is a free careers-page-not-found row naming the timeout.
  • Pages, not the whole site. maxPages listing or result pages and maxJobsPerCompany postings per company. A platform's own total is in jobCount even when fewer were read.
  • Structured data is as good as the site publishes it. A posting page without JobPosting markup gives a row with the title and location its listing link shows, and the rung stops opening detail pages after three in a row carry none.
  • Keywords: the platforms that search match them their own way (often descriptions too); elsewhere every word must appear in the title.
  • One platform per company. A company that runs two careers sites (one per region) is read through the first found; pass the second as its own entry.
  • Salaries only where the platform publishes structured pay (Greenhouse, several ATSs, JobPosting.baseSalary); never parsed out of prose.
  • Not affiliated with Eightfold, Phenom, iCIMS, Google, Amazon, any ATS vendor, or any employer whose postings you retrieve. Names are used descriptively, to say which public pages are read.

Use it from an AI agent, or from code

One JSON object in, one flat array out — the shape agent runtimes want. The Actor runs with limited permissions and pay-per-event pricing, so it works over the Apify MCP server (mcp.apify.com) and with agentic (x402) payments. The Integrations tab pushes results to Slack, a webhook, Zapier, Make, Google Sheets, Snowflake or BigQuery, and Apify Schedules run it unattended — weekly with postedWithinDays: 7 is a "new roles at my accounts" feed.

curl -X POST "https://api.apify.com/v2/acts/insight.solutions~careers-page-jobs-api/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"companies":["netflix.com","costco.com"],"keywords":"engineer","maxJobsPerCompany":50}'
# pip install apify-client
from apify_client import ApifyClient
client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("insight.solutions/careers-page-jobs-api").call(run_input={
"companies": ["netflix.com", "cvshealth.com", "pepsico.com"],
"countries": ["US"],
"maxJobsPerCompany": 200,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
if row["rowType"] == "job":
print(row["company"], row["title"], row["location"], row["postedAt"], row["url"], sep=" | ")
elif row["rowType"] == "site":
print(f'{row["company"]}: {row["jobCount"]} roles on {row["platform"]} ({row["careersUrl"]})')

Building an app with Lovable? Apify's Lovable connector runs any Actor from inside a Lovable project with your Apify token. Connect Apify in Lovable once, then ask it: "Use Apify to run insight.solutions/careers-page-jobs-api on my target accounts and build a hiring-watch board around the results." A run of a handful of companies finishes well inside Lovable's 300-second synchronous limit at the default settings, and every result is one JSON object per row, so the generated app needs no extra parsing. Usage bills to the Apify account whose token is connected.

FAQ

How is this different from ATS Jobs API and Hiring Signals API? ATS Jobs API reads 14 hosted ATS boards; give it board slugs and it is the most direct route. Hiring Signals API turns those boards into one row per company per run, with what changed and a surge flag. This Actor starts from a company domain whose platform you do not know, reads the enterprise careers platforms and companies' own sites those two do not cover, and uses ATS Jobs API's own adapter code for the 14 ATSs, so the rows line up.

Why did a company I know is hiring come back no-jobs-parsed? Its careers site draws its jobs in the browser from an API we do not recognise and publishes no structured data. platformHints[] says what the pages are built on; if it names an ATS (workday, taleo, successfactors) or you can see the board URL in an apply link, pass that board or URL directly.

Why does the site row say 138 when 10 jobs came back? jobCount is the platform's own total; jobsReturned is what this run returned after maxJobsPerCompany, maxPages and your filters. The note says when a cap or the deadline cut it short.

Does it read job descriptions? A short teaser always (at no extra request), the full text with includeDescriptions. On Eightfold, Phenom and iCIMS that is one extra request per job, so leave it off for counts and titles.

Is a cached resolution ever wrong? A company that moves platforms is re-resolved when its cached board stops answering. The cache records only which careers site a company uses, never postings, and expires after 30 days.

Can I get only what is new? Schedule it with postedWithinDays: 7. For a true diff against the last run (opened, closed, changed), use Hiring Signals API on the boards this Actor finds.

Why is my keyword search returning roles without the word in the title? On platforms that search (Eightfold, Phenom, Jibe, iCIMS, Google Careers, Amazon Jobs) the keyword goes to their own search, which also matches descriptions. Everywhere else it is matched against titles.

  • Public pages only. Every source is a careers page, careers API or job feed any anonymous visitor's browser loads. The Actor never logs in, never sends cookies or session tokens, never accepts credentials and needs no API key.
  • No recruiter contacts by design. Recruiter, hiring-manager and employee names, e-mail addresses (mailto: links, plain and obfuscated), phone numbers and personal profile links are removed from every description and teaser before a row is written; a sentence that points the reader at a named person ("contact …", "reach out to …", "Recruiter: …") is cut whole. The visitor and candidate blocks some platform APIs echo are never read. Salary ranges are kept: they are attributes of the job.
  • robots.txt is respected on every page we fetch — careers pages, listing pages, posting pages, sitemaps and feeds — read once per site per run and evaluated per RFC 9309 against our user-agent token (apifycareerspagejobsapi) and *. Crawl-delay is honoured for every host but the ATS feeds, up to 10 seconds. The platforms' JSON job APIs (Eightfold, Phenom, Jibe, Amazon) and the ATS job feeds are public feeds rather than pages and are treated the way ATS Jobs API treats them. Crawl-delay is honoured for every host but the ATS feeds (up to 10 seconds; at least one second between any two requests to a host); the ATS feeds are read direct, without the proxy, as ATS Jobs API reads them.
  • No bot walls are bypassed. A wall is one request and a free blocked row; a site that starts refusing mid-run is a free rate-limited row (the jobs already read are kept). Requests to a host honour its robots.txt Crawl-delay, up to 10 seconds, and are never less than a second apart.
  • Never LinkedIn, Indeed or Glassdoor, and no other job aggregator: only the employer's own careers site and the platform it runs on.
  • You are the controller of what you do next. If you combine this data with personal data or contact people based on it, GDPR, CCPA and similar obligations are yours.
  • Not affiliated with, endorsed by or sponsored by Eightfold, Phenom, iCIMS, Google, Amazon, any ATS vendor, or any employer named. Names and trademarks are used descriptively.

Our other Actors

Every Insight Solutions Actor is pay-per-result with no browser, no login and no API key, and every one of them returns free diagnostic rows instead of billing for failures. Prices are per 1,000 results.

Video, audio & social

News, documents & the web

Business, finance & jobs

Apps & games