# Workday Jobs & Hiring Changes Radar (`nexascout/workday-jobs-radar`) Actor

Scrape public Workday job boards and track new, updated, removed and reopened postings. Export full descriptions, locations and source links, with saved history for recurring hiring monitoring.

- **URL**: https://apify.com/nexascout/workday-jobs-radar.md
- **Developed by:** [NexaScout](https://apify.com/nexascout) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 job or change records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Workday Jobs & Hiring Changes Radar

Collect public Workday job postings from company career boards and track changes between complete observations. Get full job descriptions, locations, requisition IDs, employment types, source dates and direct links. Save a baseline, then identify new, updated, missing, removed and reopened postings.

Independent software by NexaScout. Not affiliated with Workday or any monitored employer.

### Quick start

1. Paste a public Workday board URL, such as `https://zoom.wd5.myworkdayjobs.com/Zoom`.
2. Keep **Remember jobs between runs** enabled and use the same **History profile** on subsequent runs.
3. Run with **512 MB** memory and a **300-second** platform timeout.
4. Read **Jobs and changes** and **Coverage and history** in Output. A successful process exit does not guarantee complete coverage: check `SUMMARY.status`, each board's status, and `historySaved`.
5. After a complete baseline, enable **Output changes only** if you want to exclude baseline and unchanged rows.

The first successful complete observation establishes what currently exists. It does not classify every existing vacancy as newly posted. With `changesOnly: true`, a baseline run can correctly return zero rows.

```json
{
  "boardUrls": ["https://zoom.wd5.myworkdayjobs.com/Zoom"],
  "keywords": [],
  "locations": [],
  "maxJobsPerBoard": 1000,
  "maxRunSeconds": 180,
  "detailConcurrency": 4,
  "saveHistory": true,
  "historyProfile": "default",
  "changesOnly": false
}
```

### Supported URLs

Public HTTPS boards on `tenant.wdN.myworkdayjobs.com`, with an optional locale segment such as `/en-US/`. Job links on those boards are accepted and normalized to the parent board. Custom company domains, sign-in pages, other ATS platforms and URLs with query parameters are rejected. Use a direct Workday board link without search/filter parameters. Locale is part of the history identity.

There is no company discovery database. You supply the board URLs. The Actor does not log in, submit applications, access candidate profiles, or call third-party scraping Actors. It makes direct HTTP requests; no browser or paid proxy is configured. Requests are paced at no more than two starts per second within a run, with shared backoff on rate limits. Some boards may still reject these requests.

### Input

| Field | Default | Meaning |
|---|---|---|
| `boardUrls` | Zoom public board | 1–10 supported boards |
| `keywords` | `[]` | Literal, case-insensitive OR match in title/description |
| `locations` | `[]` | Literal OR match in main/additional locations |
| `maxJobsPerBoard` | `1000` | 1–2,000 jobs; truncated boards do not advance history |
| `maxRunSeconds` | `180` | Shared HTTP collection budget, 15–240 seconds |
| `detailConcurrency` | `4` | 1–4 concurrent detail requests |
| `saveHistory` | `true` | Persist state in Actor-created named storage |
| `historyProfile` | `default` | 1–32 letters, digits or hyphens |
| `changesOnly` | `false` | Omit BASELINE and UNCHANGED output rows |

Keyword and location filters combine using AND. Filtering happens **after** collection and comparison; it does not reduce HTTP requests or narrow the stored inventory. Adding or removing filters will not create false disappearance events.

### Change events

| Event | Meaning |
|---|---|
| `BASELINE` | First complete-history establishment, or no saved history |
| `NEW` | First observed after a saved baseline, not necessarily newly published |
| `UPDATED` | A tracked field differs from the previous observation |
| `UNCHANGED` | Tracked values match the previous observation |
| `MISSING_UNCONFIRMED` | Previously observed posting is absent; awaiting confirmation |
| `REMOVED` | Absent in separate complete checks at least six hours apart |
| `REOPENED` | A previously removed posting reappeared with the same posting key |

A removed listing is **not proof that the role was filled**. Removed records are retained for 30 days. A later reappearance after retention expires can be classified as NEW.

Changes include title, employer, location, additional locations, employment/workplace type, URL, description, source start/end dates and apply availability. Relative text such as “Posted 7 Days Ago” is not compared, preventing daily false updates. For a description change, the prior SHA-256 hash is supplied instead of a second full description.

### Complete coverage and safe history

Every retrieved job must have a valid matching full detail response. The Actor scans the board again and checks the posting inventory before committing a baseline. Missing pages, failed details, changed totals, duplicate IDs, time limits, truncated boards and changed verification inventories prevent history updates and removal events for that board.

Some Workday endpoints can cap their advertised total at 2,000. This version conservatively treats any source total of 2,000 or more as partial; it does not attempt facet splitting to bypass the ceiling. It can return collected jobs with `observationComplete: false`, but cannot reliably monitor removals on those boards. Large boards may also exceed the shared collection budget. Split your board list into separate tasks; do not interpret PARTIAL as full coverage.

Two list scans reduce pagination-related false changes but cannot provide a transactional snapshot of a site changing during a run. Descriptions are observed once per run. A job that disappears during detail collection invalidates that board's baseline commit.

Only one run per history profile should run at once. The stale-writer check is best-effort, not a distributed lock. Use separate profiles for independent tasks. Do not resurrect an old run after a newer run has saved history. Do not delete the named history store if you want comparisons to continue.

If history saving fails, emitted jobs remain available and SUMMARY reports HISTORY\_ERROR. If dataset writing fails, history is not advanced for that board. With native dataset billing, the Actor checks the remaining output budget before each batch (up to 100 rows). If the entire next batch is not affordable, it stops output and subsequent board collection, reports OUTPUT\_BUDGET\_LIMIT, and does not advance that board's history. This can leave part of the spending limit unused. A platform abort may prevent final summary generation; check the run status as well.

### Output

- **Default dataset:** one emitted job/change record per row; export with Apify as JSON, CSV or Excel.
- **SUMMARY / OUTPUT:** coverage, per-board failures, HTTP request/byte counts, event counts and history persistence.
- **JOBS\_JSON:** emitted records for this run, excluding failed writes.
- **DASHBOARD:** HTML summary with the first 200 rows.

Key fields: `event`, `jobKey`, `jobId`, `requisitionId`, `company`, `title`, `location`, `additionalLocations`, `employmentType`, `workplaceType`, `description`, `jobUrl`, `sourcePublishedAt`, `sourceEndDate`, `changedFields`, `previousValues`, `firstSeenAt`, `lastSeenAt`, `observedAt`, `comparisonAt`, `observationComplete`.

Workday posting keys can carry a numeric suffix in addition to a requisition ID. `jobId` preserves that suffix; `requisitionId` is the source's requisition identifier. Records are deduplicated within each board, not across different career sites or locales.

`salary`, `department`, and `sourceUpdatedAt` are null in v0.1.0 rather than inferred. Salary information, when present, remains in the full description. Date fields preserve source values and are not guessed from relative dates. Missing or localized workplace values are not classified by AI.

### Scheduling and integrations

Save the input as an Apify Task and configure a daily schedule if desired. Keep the same history profile and prevent overlapping runs. Use the dataset or API with your own downstream workflow. This Actor does not send notifications by itself. Scheduling, public task publication and external integrations are separate Console actions.

### Pricing and permissions

See the Actor's current Pricing tab for any public price. This release package does not configure monetization or publish itself. If native pay-per-event charging is enabled, every written default-dataset row can be billable, including baseline, unchanged and missing-confirmation rows; `changesOnly` reduces emitted rows, not collection work. The synthetic Actor Start event can be charged even if no changes are found. No manual duplicate charging is performed by this code.

Start with Limited permissions. History uses named stores created by this Actor. Cloud permissions, platform cost and paid-user billing must be validated after deployment; local HTTP tests do not establish cloud unit economics.

# Changelog

This Actor's version history is a separate document: https://apify.com/nexascout/workday-jobs-radar/changelog.md

# Actor input Schema

## `boardUrls` (type: `array`):

1–10 public tenant.wdN.myworkdayjobs.com career board URLs. Remove query parameters. Custom company domains, login pages and other ATS platforms are not supported.

## `keywords` (type: `array`):

Literal OR match in title or description. Filtering does not change stored history. Up to 20 keywords. Output filter only; does not reduce collection requests.

## `maxJobsPerBoard` (type: `integer`):

Always collects full details for retrieved jobs. Truncated boards do not advance history. Source totals of 2,000 or more are conservatively treated as incomplete.

## `maxRunSeconds` (type: `integer`):

Set platform timeout to at least 300 seconds.

## `saveHistory` (type: `boolean`):

Named storage created by this Actor. Use Limited permissions from the first run.

## `historyProfile` (type: `string`):

Letters, digits, hyphens; 1–32 characters. Separate profiles isolate monitoring histories.

## `changesOnly` (type: `boolean`):

Excludes BASELINE and UNCHANGED. First run can have zero output rows while creating a baseline.

## `locations` (type: `array`):

Literal OR match in main or additional locations. Combined with keywords using AND. Output filter only: all jobs are still collected for reliable history.

## `detailConcurrency` (type: `integer`):

Up to four public job-detail requests at a time. Lower this if a board rate limits you.

## Actor input object example

```json
{
  "boardUrls": [
    "https://zoom.wd5.myworkdayjobs.com/Zoom"
  ],
  "keywords": [],
  "maxJobsPerBoard": 1000,
  "maxRunSeconds": 180,
  "saveHistory": true,
  "historyProfile": "default",
  "changesOnly": false,
  "locations": [],
  "detailConcurrency": 4
}
```

# Actor output Schema

## `jobs` (type: `string`):

No description

## `dashboard` (type: `string`):

No description

## `summary` (type: `string`):

No description

## `json` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "boardUrls": [
        "https://zoom.wd5.myworkdayjobs.com/Zoom"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("nexascout/workday-jobs-radar").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "boardUrls": ["https://zoom.wd5.myworkdayjobs.com/Zoom"] }

# Run the Actor and wait for it to finish
run = client.actor("nexascout/workday-jobs-radar").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "boardUrls": [
    "https://zoom.wd5.myworkdayjobs.com/Zoom"
  ]
}' |
apify call nexascout/workday-jobs-radar --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nexascout/workday-jobs-radar"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/jPkWuo9gAu3oV7klW/builds/FsvoOJwadUfHyDlHX/openapi.json
