# Career Sites ATS Job Feed & Company Hiring Signals (`codeclouds/career-sites-ats-jobfeed`) Actor

Live jobs from company career sites on Greenhouse, Lever, Ashby, Workday, Workable, Recruitee, SmartRecruiters and Personio. Pass a name, website or board URL; the ATS is auto-detected. Get normalized jobs plus a hiring profile per company: new/closed roles, trend, momentum score, salary bands.

- **URL**: https://apify.com/codeclouds/career-sites-ats-jobfeed.md
- **Developed by:** [Dennis](https://apify.com/codeclouds) (community)
- **Categories:** Jobs, Lead generation
- **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 results

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

## Career Sites ATS Job Feed & Company Hiring Signals

Get live job postings straight from company career sites on **Greenhouse, Lever, Ashby, Workday, Workable, Recruitee, SmartRecruiters and Personio**. Give a company name, website or board URL and the ATS is detected for you. You get clean, normalized jobs plus a **hiring-signal profile per company**: open roles by function, seniority and country, new and closed roles since the last run, salary bands and a 0-100 hiring momentum score.

Most job scrapers give you a list of postings. This Actor also tells you **what that list means**: who is scaling engineering, who just opened their first sales roles in Germany, who stopped hiring.

### When should an AI agent use this?

- "Is Stripe hiring engineers in Europe right now, and how many?"
- "Which of these 50 SaaS companies grew their open roles the most since last week?"
- "Give me all remote senior data roles at Notion, Ramp and Spotify with salary ranges."
- "Which companies in my target account list are hiring a VP of Sales or Head of Marketing?"
- "What is the median disclosed base salary for engineering roles at Ramp?"
- "Alert me when Hugging Face posts a new job."

Pass the companies as an array of strings. For agents, `outputMode: "profiles_only"` is the cheapest way to answer "is X hiring and in what" questions, because one profile summarizes an entire board.

### Quick start

1. Click **Start** with the default input. It profiles Stripe, Notion, Spotify and Ramp and returns up to 50 jobs each, for about $0.25.
2. Open the **Company hiring profiles** view in the Output tab to see open roles, top hiring areas, salary bands and signals.
3. Replace the companies with your own list, then **schedule** the run (daily or weekly). From the second run on you get new roles, closed roles and a trend line per company.

### What this Actor does

- **8 ATS platforms, one schema.** Greenhouse, Lever, Ashby, Workday, Workable, Recruitee, SmartRecruiters and Personio are mapped to one flat, predictable job record, including Fortune 500 career sites that run on Workday.
- **Automatic ATS detection.** Pass a board URL for the fastest result, a website (`notion.com`), which is scanned for embedded ATS links on its careers page, or just a name (`Stripe`), which is matched against the public board of every supported ATS. Name matches are flagged in the profile's `message` so you can verify them.
- **Profiles always cover the full board.** `maxJobsPerCompany` only limits how many job records you receive and pay for. The company profile and the new/closed detection are always calculated on every open role (up to 5,000 per board).
- **Normalized fields you can filter on.** `jobFunction` (engineering, data & AI, product, design, sales, marketing, customer success, operations, finance, people & HR, legal & compliance), `seniority` (intern to C-level, with product/account manager titles correctly treated as individual contributors), `workplaceType` (remote/hybrid/onsite), `employmentType` and ISO `country` codes.
- **Salary extraction.** Structured pay ranges from Ashby, Lever and Recruitee are used directly. For every other job, the description's pay-transparency text is parsed ("The annual US base salary range is $274,456 - $334,600", "R$9.000 - R$11.250 monthly", "$211.4K – $290.6K"). Company revenue figures such as "$20M–$50M in payment volume" are ignored.
- **Change detection between runs.** A snapshot per board is kept, so scheduled runs flag each job as new (`isNew`), list the titles of roles that closed, and compute net hiring change. `onlyNewJobs` turns the Actor into a new-job alert feed.
- **Company hiring profile.** One record per company with open roles, roles posted in the last 7/30 days, median days open, breakdowns by function, seniority, department and location, remote share, leadership openings, pay-disclosure share, median salary band, a momentum score, an `openJobsHistory` trend line (last 26 runs) and plain-English signals.
- **Straight from the source.** Data comes from each employer's own public job board at run time, not from a stale aggregated database. No login, no proxies, no browser.
- **Fair billing.** Companies that cannot be found are reported for free, with a hint on what to pass instead.

### Input

| Field | Type | Description |
|---|---|---|
| `companies` | array of strings | Company names, websites/careers pages or ATS board URLs. Required. |
| `outputMode` | string | `jobs_and_profiles` (default), `profiles_only` or `jobs_only`. |
| `titleKeywords` | array | Only jobs whose title contains one of these words. |
| `locationKeywords` | array | Only jobs whose location, country code or workplace type contains one of these words (`London`, `DE`, `remote`). |
| `functions` | array | Only these normalized job functions. |
| `seniorities` | array | Only these seniority levels. |
| `remoteOnly` | boolean | Only fully remote jobs. |
| `trackChanges` | boolean | Keep a snapshot per board for new/closed detection (default `true`). |
| `onlyNewJobs` | boolean | Only return jobs that were not on the board during the previous run. |
| `atsPlatforms` | array | Restrict detection to specific ATS platforms. |
| `includeDescription` | boolean | Add the plain-text description to each job (default `false`). |
| `maxJobsPerCompany` | integer | Max job records delivered per company after filters (default 50). Profiles always use the full board. |

Example:

```json
{
  "companies": ["Stripe", "notion.com", "https://jobs.lever.co/spotify", "https://jobs.ashbyhq.com/ramp"],
  "functions": ["engineering", "data_ai"],
  "locationKeywords": ["remote", "GB", "DE"],
  "outputMode": "jobs_and_profiles"
}
```

Filters only apply to the job records. The company profile is always calculated from the full board, so you still see the overall hiring picture.

### Output

The default dataset contains two record types, distinguished by `recordType`. The Output tab has a **Jobs** view and a **Company hiring profiles** view. All profiles are also stored as one JSON array under the key-value store record `HIRING_PROFILES`.

Job record (`recordType: "job"`):

```json
{
  "recordType": "job",
  "jobKey": "ashby:ramp:34413f8d-26bf-4bbc-8ade-eb309a0e2245",
  "company": "Ramp",
  "companySlug": "ramp",
  "ats": "ashby",
  "jobId": "34413f8d-26bf-4bbc-8ade-eb309a0e2245",
  "title": "Security Engineer, Cloud",
  "department": "Engineering",
  "team": "Backend",
  "location": "New York, NY (HQ); Remote (Canada); Remote (US); Miami, FL",
  "country": "US",
  "workplaceType": "hybrid",
  "employmentType": "full_time",
  "seniority": "mid",
  "jobFunction": "engineering",
  "salaryMin": 211400,
  "salaryMax": 290600,
  "salaryCurrency": "USD",
  "salaryPeriod": "year",
  "salarySource": "structured",
  "publishedAt": "2026-04-07T17:12:35.753Z",
  "daysOpen": 174,
  "isNew": false,
  "firstSeenAt": "2026-04-07T17:12:35.753Z",
  "url": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245",
  "applyUrl": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245/application",
  "description": null,
  "scrapedAt": "2026-09-29T08:00:00.000Z"
}
```

Company hiring profile (`recordType: "company_profile"`, shortened):

```json
{
  "recordType": "company_profile",
  "input": "Stripe",
  "status": "ok",
  "company": "Stripe",
  "ats": "greenhouse",
  "detectionMethod": "slug_guess",
  "boardUrl": "https://job-boards.greenhouse.io/stripe",
  "openJobs": 703,
  "jobsPostedLast7Days": 61,
  "jobsPostedLast30Days": 298,
  "newJobsSinceLastRun": 14,
  "closedJobsSinceLastRun": 9,
  "netChangeSinceLastRun": 5,
  "closedJobTitles": ["Account Executive, Enterprise", "..."],
  "topFunction": "sales",
  "jobsByFunction": [{ "name": "sales", "count": 188 }, { "name": "engineering", "count": 119 }],
  "jobsBySeniority": [{ "name": "mid", "count": 430 }, { "name": "manager", "count": 116 }],
  "countries": ["AU", "CA", "DE", "GB", "IE", "JP", "SG", "US"],
  "leadershipOpenings": 16,
  "salaryDisclosedShare": 0.033,
  "medianSalaryMin": 196227,
  "medianSalaryMax": 230250,
  "medianSalaryCurrency": "USD",
  "hiringMomentumScore": 60,
  "hiringMomentum": "growing",
  "signals": [
    "703 open roles; 298 published in the last 30 days (momentum: growing, 60/100).",
    "Since the previous run (2026-09-22): 14 new, 9 closed (net +5).",
    "Biggest hiring area: sales (188 roles, 27%).",
    "Leadership hiring: 16 director/VP/executive role(s), e.g. Creative Director, Copy & Campaigns."
  ]
}
```

**Hiring momentum score (0-100)** = volume (up to 30 points, logarithmic in open roles) + freshness (up to 40 points, share of roles published in the last 30 days) + growth (up to 30 points, net change versus the previous run; a neutral 15 on the first run). Labels: `hot` ≥ 70, `growing` ≥ 50, `steady` ≥ 30, `slow` below that, `not_hiring` with zero open roles.

### Use cases

- **Sales and lead generation:** hiring is a buying signal. Find target accounts that are scaling the team you sell to (for example companies opening data or security roles), and time your outreach on new openings.
- **Investors and market research:** track hiring velocity across a portfolio or a competitor set every week without maintaining seven different scrapers.
- **Competitive intelligence:** see which functions and countries competitors are expanding into, and which leadership roles they are filling.
- **Recruiting and talent intelligence:** monitor where talent demand is rising, benchmark disclosed salary bands, and build sourcing lists.
- **Job boards and niche job sites:** feed fresh, deduplicated postings with stable `jobKey` identifiers and apply links straight to the employer.
- **AI agents:** answer "is company X hiring for Y" questions with one tool call and a compact, structured answer.

### Pricing

Pay per event, no subscription:

- **job-result:** $0.001 per job delivered ($1 per 1,000 jobs)
- **company-profile:** $0.01 per company hiring profile
- Companies that are not found, or fail, are free.

Examples: a weekly profile of 100 companies (`profiles_only`) costs about $1 per run. The engineering jobs from 20 companies (around 1,000 jobs) plus their profiles cost about $1.20. Set a maximum charge per run in the Apify Console to cap spending; the Actor stops cleanly when the limit is reached.

### Legal

The Actor only reads the **public job board endpoints** that employers publish via their applicant tracking system so their vacancies can be shown and reused on career sites and job platforms. It does not log in, bypass protections or use proxies. The data describes job openings of organizations, not individuals, and no personal data about candidates or employees is collected. Job descriptions stay the copyright of the employer: you are responsible for how you republish them. Respect each platform's terms when you build a product on top of this data.

### FAQ

**Q: Which company names work without a URL?**
A: Any company whose board slug matches its name (Stripe, Ramp, Notion, Spotify and thousands of others). If a name is not found, pass the careers page or board URL. The profile record will then show `status: "not_found"`, and you are not charged.

**Q: Why is `isNew` null?**
A: The first run for a board creates the baseline. Schedule the Actor (daily or weekly) with `trackChanges` enabled to get new and closed roles from the second run on.

**Q: How accurate are function and seniority?**
A: Both are inferred from the job title first, then from the department and the ATS's own level. They are designed for aggregate analysis and filtering, not as an HR classification. Titles that don't clearly indicate a level default to `mid`.

**Q: Why do some jobs have no salary?**
A: Many employers only publish pay where the law requires it (for example several US states). The Actor uses structured pay data where the ATS offers it and otherwise parses the description text; it never guesses.

**Q: How do I add a Workday company?**
A: Open the company's careers site and copy the URL of its Workday job search page, for example `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite`. Workday boards cannot be guessed from a name because each company chooses its own site name. Workday only publishes a relative posting date ("Posted 3 Days Ago"), so `publishedAt` is exact to the day and empty for "30+ days". Departments and salaries are not part of Workday's public list.

**Q: Do you support iCIMS, Taleo or SuccessFactors?**
A: Not yet. Tell us which platform you need via the Issues tab.

**Q: Can I monitor hundreds of companies?**
A: Yes. Companies are processed in parallel with polite rate limiting, and `profiles_only` keeps the dataset and the cost small.

### Related Actors

- **[Google Ads Transparency Monitor](https://apify.com/CodeClouds/google-ads-transparency-monitor)**: pair hiring signals with the ads a company is running for a fuller picture of where a competitor or target account is investing.
- **[French Company Register Lookup (SIRENE)](https://apify.com/codeclouds/fr-sirene-company-register-lookup)**: enrich French employers from your hiring list with official registry data (SIREN, legal form, headcount band, activity code).

### Keywords

job scraper, ATS jobs, Greenhouse jobs API, Lever jobs API, Ashby jobs, Workday jobs scraper, myworkdayjobs, Workable jobs, Recruitee jobs, SmartRecruiters jobs, Personio jobs, career site jobs, company careers page scraper, hiring signals, hiring intent data, job postings API, job change detection, new job alerts, salary transparency data, recruiting intelligence, sales intelligence, lead generation, talent intelligence, MCP tool

### Changelog

#### 0.1.0

- First release: 8 ATS platforms (incl. Workday and Lever EU), automatic ATS detection, normalized job records, salary extraction, run-over-run change detection, full-board company hiring profiles with a momentum score and open-roles trend.

# Actor input Schema

## `companies` (type: `array`):

One company per line. Accepts a company name (Stripe), a website or careers page (notion.com, https://acme.com/careers) or a direct ATS board URL (https://jobs.lever.co/spotify, https://job-boards.greenhouse.io/stripe, https://jobs.ashbyhq.com/ramp, https://apply.workable.com/huggingface, bunq.recruitee.com, https://jobs.smartrecruiters.com/BoschGroup, acme.jobs.personio.de, https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite). The ATS is detected automatically; a board URL is the fastest and most precise option.

## `outputMode` (type: `string`):

jobs\_and\_profiles: every open job plus one hiring-signal profile per company. profiles\_only: only the company hiring profiles (cheapest way to monitor many companies). jobs\_only: only the normalized job records.

## `titleKeywords` (type: `array`):

Only return jobs whose title contains at least one of these words (case-insensitive), e.g. engineer, sales, designer. Leave empty for all jobs. Company profiles are always computed on the full board.

## `locationKeywords` (type: `array`):

Only return jobs whose location, ISO country code or workplace type contains one of these words, e.g. London, DE, remote.

## `functions` (type: `array`):

Only return jobs in these normalized functions. Leave empty for all.

## `seniorities` (type: `array`):

Only return jobs at these seniority levels (inferred from the title, with the ATS level as fallback). Leave empty for all.

## `remoteOnly` (type: `boolean`):

Only return jobs marked as fully remote.

## `trackChanges` (type: `boolean`):

Stores a snapshot per company board so the next run can flag new jobs (isNew), list closed jobs and compute net hiring change. The first run creates the baseline (isNew = null). Most useful on a schedule; for a single ad-hoc run it only creates the baseline.

## `onlyNewJobs` (type: `boolean`):

Return only jobs that were not on the board during the previous run (requires change tracking). The first run returns all jobs as the baseline. Ideal for scheduled alerts.

## `atsPlatforms` (type: `array`):

Which applicant tracking systems may be used. Workday boards are only used when you pass a Workday URL (https://{company}.wdN.myworkdayjobs.com/{site}) or when the careers page links to one; they are never guessed from a name.

## `includeDescription` (type: `boolean`):

Adds the plain-text job description (max 20,000 characters) to every job record. Off by default to keep datasets small; salary extraction from the description runs either way.

## `maxJobsPerCompany` (type: `integer`):

Maximum number of job records delivered (and billed) per company after filters. Company hiring profiles and new/closed detection always use the full board, so profiles\_only runs stay cheap and complete.

## Actor input object example

```json
{
  "companies": [
    "Stripe",
    "notion.com",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/ramp"
  ],
  "outputMode": "jobs_and_profiles",
  "titleKeywords": [],
  "locationKeywords": [],
  "functions": [],
  "seniorities": [],
  "remoteOnly": false,
  "trackChanges": true,
  "onlyNewJobs": false,
  "atsPlatforms": [
    "greenhouse",
    "lever",
    "ashby",
    "workable",
    "recruitee",
    "smartrecruiters",
    "personio",
    "workday"
  ],
  "includeDescription": false,
  "maxJobsPerCompany": 50
}
```

# Actor output Schema

## `results` (type: `string`):

All dataset items: jobs and company hiring profiles.

## `hiringProfiles` (type: `string`):

Array with one hiring profile per requested company, including not-found companies.

# 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 = {
    "companies": [
        "Stripe",
        "notion.com",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/ramp"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("codeclouds/career-sites-ats-jobfeed").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 = { "companies": [
        "Stripe",
        "notion.com",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/ramp",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("codeclouds/career-sites-ats-jobfeed").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 '{
  "companies": [
    "Stripe",
    "notion.com",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/ramp"
  ]
}' |
apify call codeclouds/career-sites-ats-jobfeed --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,codeclouds/career-sites-ats-jobfeed"
        }
    }
}
```

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/VBx6a5H18bAdOeaxu/builds/x2HpA4ilKXtbjx0bN/openapi.json
