Workday Jobs Scraper — Pay Ranges by Company Name avatar

Workday Jobs Scraper — Pay Ranges by Company Name

Pricing

from $2.00 / 1,000 results

Go to Apify Store
Workday Jobs Scraper — Pay Ranges by Company Name

Workday Jobs Scraper — Pay Ranges by Company Name

Scrape open roles from any company's Workday career site by typing the company name — no tenant ID, pod or site name needed. Extracts disclosed pay ranges (min, max, currency, hourly vs annual), location, remote type, requisition ID and posting date. For comp benchmarking and hiring intelligence.

Pricing

from $2.00 / 1,000 results

Rating

0.0

(0)

Developer

mochi

mochi

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 days ago

Last modified

Share

Get every open role from any company's Workday career site by typing the company name. No tenant ID, no pod number, no career-site name — and no URL hunting.

Built for compensation benchmarking and hiring intelligence: alongside the usual job fields it extracts the disclosed pay range — minimum, maximum, currency, and whether the figure is hourly or annual — from the posting text, including the multi-band ranges that large US employers now publish under state pay-transparency laws.


Why this is harder than it looks

A Workday career site lives at https://<tenant>.wd<N>.myworkdayjobs.com/<CareerSite>. To fetch one company you need all three parts:

PartExampleWhere you find it
tenantcvshealthusually the company slug, but not always
podwd1 / wd5 / wd12 / wd103which Workday data centre hosts them — no pattern, no registry
career siteCVS_Health_Careersfreely chosen by the employer

There is no public directory mapping companies to those values. This actor resolves all three from a plain company name by reading the tenant's own robots.txt, which publishes a Sitemap: directive for each career site it operates.

You type CVS Health — it finds cvshealth.wd1 / CVS_Health_Careers.

You can also paste a career-site URL directly if you already have one.


Pay-range coverage — measured, not claimed

Disclosure is entirely up to the employer, and it varies enormously. These are real numbers from a sweep of 325 live postings across 12 companies:

CompanyPostings sampledWith a pay range
CVS Health30100%
Target3093%
Workday3073%
Cisco3063%
Adobe3053%
NVIDIA3043%
AstraZeneca3017%
Pfizer3013%
Shell3010%
RBC248%
Salesforce307%
Unilever10%
Overall32544%

Currencies seen: USD, EUR, CAD. Periods: annual and hourly. Roughly 1.65 pay bands per disclosing posting — because many postings quote more than one (see below).

If you only want rows that carry pay, set onlyWithPayRange. US-filtered runs land far above the average — a countryCodes: ["US"] run on these companies returns close to 100% disclosure, because the disclosure laws are American.


Multi-band ranges — the part most scrapers flatten

A single posting frequently contains several ranges, and they mean different things. Real examples from the captures in fixtures/:

Cisco publishes a base range plus state-specific ranges in the same posting:

starting salary range ................ $145,200.00 to $184,100.00
New York City Metro Area ............. $145,200.00 - $212,100.00
Non-Metro New York state & Washington $129,100.00 - $188,300.00

NVIDIA publishes one range per level:

base salary range is 60,000 USD - 101,200 USD for Level 3,
and 72,000 USD - 120,750 USD for Level 4

Target publishes a starting range and a full range:

The starting pay range for this position per hour is $21.00 - $23.00
The full pay range for this position per hour is $21.00 - $35.70

The primary band is reported in the flat payMin / payMax columns, and every band is kept in payBands, each with its own scope (starting / full), level (e.g. Level 3) and an includesVariablePay flag for ranges labelled OTE or "cash compensation".


Hourly vs annual

Workday postings do not label the period in a machine-readable field, and the wording is often ambiguous. CVS Health, for example, prints this next to every range:

"This pay range represents the base hourly rate or base annual full-time salary…"

That sentence cannot decide the question, so:

  • If the surrounding text gives exactly one unambiguous period phrase (per hour, per year, annually…), it is used and payPeriodInferred is false.
  • If the text is silent or self-contradictory, the period is inferred from the magnitude, and payPeriodInferred is true so you can tell the difference.
  • Between roughly 400 and 12,000 in a major currency, an amount could be monthly, weekly or a daily rate. The period is left null rather than guessed. A benchmark with gaps is more useful than one with invented numbers.

Magnitude inference is only applied to currencies with USD-like magnitudes. A JPY or INR figure never gets a guessed period.


What the parser refuses to do

Every one of these was a real false positive caught against live postings during the build:

  • Estimated Weekly Hours 40 — a bare integer is never money, and "Weekly" here is not a pay period.
  • 500-5,000 FTE, BGP 1-7 — a trailing capitalised acronym is only a currency if it is a real ISO-4217 code.
  • $231,000 - $275,000 OTE — that is a real USD range; OTE is recorded as a variable-pay flag, not mistaken for the currency.
  • a $500 sign-on bonus — a lone amount needs both an explicit period phrase and pay context before it counts as pay.
  • $2,500.00 per hour of transaction volume — has a period phrase but no pay context, so it is ignored.
  • A decoy number earlier in the description (a portfolio of 200 to 300 accounts) does not hide the real range further down.

Output fields

FieldNotes
company, legalEntity, tenant, pod, careerSite, requestedAswho, and how it was resolved
jobId, requisitionId, jobPostingId, title, jobUrlthe requisition
location, requisitionLocation, country, countryCode, additionalLocations, locationCountISO alpha-2 country code included
workplaceType, isRemote, timeTypeas Workday reports them; often unset
postedOnText, postedDate, daysSincePosted, applicationDeadline, timeLeftToApply, isOpenfreshness and deadlines
hasPayRange, payMin, payMax, payCurrency, payCurrencySymbolthe primary band
payPeriod, payPeriodInferred, payIsSingleValuehour / year / month / null
payIncludesVariablePay, payScope, payLevelOTE flag, starting-vs-full, level label
payRangeRawthe exact source text, so you can audit any number
payBandCount, payBandsevery band found, not just the first
descriptionTextoptional (includeDescription)
source, scrapedAtprovenance

Pay columns are always present, set to null when no range was found, so a CSV export keeps a stable shape.


Input

OptionDefaultWhat it does
companies5 sample employersCompany names or career-site URLs
maxResults20Allocated round-robin, so every company is represented
searchText""Passed to Workday's own search per company
onlyWithPayRangefalseKeep only postings with a disclosed range
titleKeywords[]Substring match on the title
locationKeywords[]Matches location, requisition location, country, additional locations
countryCodes[]Exact ISO alpha-2 match — US does not also select AUS
postedWithinDays0Freshness filter; 0 disables
remoteOnlyfalseMany employers leave the field unset; those are excluded
includeDescriptionfalseAdds the full plain-text description
includeSecondarySitesfalseEarly-careers / campaign sites, which mostly duplicate the main one
includeAllSitesfalseAlso sites marked internal / private / contractor

Round-robin matters. Filling results company-by-company means the first company consumes the whole quota and every company after it silently returns nothing. Results here are interleaved as they are fetched, so a five-company run at maxResults: 20 returns four from each.


How it reports problems

Silence is the failure mode that costs you money, so the run log distinguishes:

  • unresolved — no Workday tenant found for that name (it is never guessed at);
  • empty — the career site resolved fine but genuinely lists 0 open postings (Dell's Workday instance is a real example);
  • fetch failure — a request that actually failed.

The counts are also written to the RUN_SUMMARY key in the default key-value store.


Source, limits and compliance

  • Source: public Workday career sites — the same postings any visitor sees, read through the career site's own JSON endpoint.
  • robots.txt is honoured. The resolver reads each tenant's robots.txt at run time, uses its Sitemap: directives for discovery, and will not request a path that tenant disallows. If a tenant ever names an AI crawler in robots.txt, that company is refused outright rather than fetched.
  • Non-public career sites are skipped by default, including ones named internal, private, contractor or conversion-only, even where they are technically reachable.
  • PDPA / GDPR: organisation-level data only. Employer, requisition, location and pay. No candidate or recruiter data is collected.
  • Coverage limits: the actor only reaches employers who use Workday, and only sites listed in that tenant's robots.txt. Pay extraction depends on the employer disclosing in the posting text — 44% of postings in our sample, and 0% at some employers.
  • Rate: requests are issued one at a time per company with retries and backoff.