Ashby Jobs Scraper - Fast ATS API
Pricing
Pay per event
Ashby Jobs Scraper - Fast ATS API
Jobs from Ashby boards (OpenAI, Notion, Linear, Ramp, Perplexity, hundreds more). Structured salary + equity + bonus, filters + diff mode. New `report` mode: 1 row/company with hiringScore, velocity, priorityRoles, remoteShare. $0.50/1k jobs or $0.025/report.
Pricing
Pay per event
Rating
0.0
(0)
Developer
An Tan Huynh
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
2 days ago
Last modified
Categories
Share
Ashby Jobs Scraper – Fast ATS API
Scrape Ashby-hosted career pages via the public JSON API. One row per
job with structured compensation (salary min/max, equity, bonus),
workplaceType, department, team and descriptionPlain – no proxy
required.
$0.50 per 1,000 jobs ($0.0005 / job, pay-per-event).
Who is this for?
Ashby is the ATS of choice for AI-first and modern SaaS startups.
Boards you can scrape today include OpenAI, Notion, Linear, Ramp,
Perplexity, Vercel, Supabase, Clay, Modal, Hex, Rippling, Mercury,
Loom and hundreds more. If a job board URL looks like
https://jobs.ashbyhq.com/<company>, this actor can scrape it.
Input
| Field | Type | Default | Notes |
|---|---|---|---|
boardSlugs | string[] | required | Company slugs or full board URLs. The actor extracts the slug automatically. Pass as many companies as you want in a single run. |
includeCompensation | bool | true | Append ?includeCompensation=true to pull structured salary + equity + bonus for boards that opt in. |
maxJobsPerBoard | int | 5000 | Safety cap per board (OpenAI has ~800). |
titleKeywords | string[] | (empty) | Keep only jobs whose title contains any of these (case-insensitive). Example: ["engineer","research scientist","ml"]. |
titleExclusions | string[] | (empty) | Drop jobs whose title contains any of these. Example: ["senior","manager","staff"]. |
departments | string[] | (empty) | Case-insensitive substring match on job department. |
locations | string[] | (empty) | Case-insensitive substring match on location / country / region / locality / secondary locations. |
workplaceTypes | string[] | (empty) | Match normalised workplaceType: remote, hybrid, onsite. |
employmentTypes | string[] | (empty) | Match employmentType: fulltime, parttime, contract, temporary, intern. |
onlyWithSalary | bool | false | Keep only jobs where the compensation has a numeric Salary component. |
onlyRemote | bool | false | Shortcut – keep only jobs with workplaceType=Remote or isRemote=true. |
publishedAfter | string | (empty) | ISO date / datetime cut-off on publishedAt. |
minSalary | int | (empty) | Keep only jobs whose compensation annualises to at least this amount. Hourly rates are multiplied by 2080, monthly by 12. Jobs without a numeric salary are dropped. |
salaryCurrency | string | (empty) | ISO 4217 currency filter (USD, EUR, GBP...). When set, jobs in other currencies are dropped. |
onlyNewSinceLastRun | bool | false | Diff mode. The actor remembers (per stateKey + board) the set of jobIds seen on previous runs in a named key-value store, and on each subsequent run only pushes jobs that are new. Every pushed row carries isNew: true. Pair with Apify Scheduler for daily deltas. |
stateKey | string | default | Optional label for the diff state bucket. Different stateKey values keep independent "seen" memories; shared values share memory. |
proxyConfiguration | object | (none) | Optional. API is open; use proxy only if you hit rate limits. |
Example input:
{"boardSlugs": ["openai", "notion", "linear"],"includeCompensation": true,"maxJobsPerBoard": 5000}
Output (one row per job)
{"boardSlug": "openai","jobId": "8fb1615c-34bf-47c4-a1d1-b7b2f836bbd3","title": "Technical Program Manager, Compute Infrastructure","jobUrl": "https://jobs.ashbyhq.com/openai/8fb1615c-34bf-47c4-a1d1-b7b2f836bbd3","applyUrl": "https://jobs.ashbyhq.com/openai/8fb1615c-34bf-47c4-a1d1-b7b2f836bbd3/application","location": "San Francisco","secondaryLocations": [],"country": "United States","region": "California","locality": "San Francisco","workplaceType": "Hybrid","workplaceTypeRaw": null,"isRemote": false,"employmentType": "FullTime","department": "Technical Program Management","team": "Technical Program Management","isListed": true,"publishedAt": "2026-03-12T16:38:15.322+00:00","salaryMin": 257000,"salaryMax": 335000,"salaryCurrency": "USD","salaryInterval": "1 YEAR","equitySummary": "Offers Equity","bonusSummary": null,"commissionSummary": null,"compensationSummary": "$257K – $335K • Offers Equity","shouldDisplayCompensation": true,"compensation": {"...": "...raw compensation object..."},"descriptionPlain": "ABOUT THE TEAM\n\nThe compute infrastructure team...","descriptionHtml": "<h3><strong>About the Team</strong></h3>...","scrapedAt": "2026-10-15T21:04:00+00:00"}
Workplace type normalisation
The actor maps workplaceType (and isRemote as fallback) to one of
Remote, Hybrid, Onsite, or leaves it null when the board doesn't
publish the attribute.
Compensation
Ashby stores compensation as a tiered object. The actor flattens the
primary Salary component into salaryMin / salaryMax /
salaryCurrency / salaryInterval, and surfaces human text for
equitySummary, bonusSummary, commissionSummary and the overall
compensationSummary. The full raw compensation object is kept too
for advanced consumers (multi-tier roles, geographic salary bands).
Boards that do publish pay (OpenAI, Ramp, Ashby itself) populate salary fields on ~80–96 % of listings; boards that don't (Notion, Linear) leave the compensation object empty.
Smoke run numbers (2026-10-16)
| Input | Boards | Rows | Field coverage |
|---|---|---|---|
| Default smoke (3 boards, with compensation) | openai + notion + linear | 965 | 100 % jobId/title/jobUrl/location/employmentType/department/publishedAt/descriptionPlain/descriptionHtml; 69 % workplaceType; 67 % salaryMin |
| Filtered (engineering + remote/hybrid + onlyWithSalary) | openai + ramp | 48 | 100 % salary present, 34 Engineering + 14 Forward Deployed Engineering, 47 Hybrid + 1 Remote |
| publishedAfter 2026-09-01, employmentTypes=[fulltime] | ramp | 69 | 0 violations, 100 % FullTime |
Per-board workplace coverage: OpenAI 68 %, Notion 64 %, Linear 100 %, Ramp 100 %. Boards that don't tag workplace leave it null – no guess is made.
Pricing
Pay-per-event. Two charge types:
$0.0005perjobrow pushed (defaultmode: "jobs").$0.025perreportrow pushed (mode: "report", one row per company).
Example runs:
- OpenAI + Notion + Linear (965 jobs, jobs mode) → $0.48.
- Ramp only, published after 2026-09-01, full-time (69 jobs) → $0.03.
- Filtered OpenAI + Ramp engineering roles with pay (48 jobs) → $0.02.
- OpenAI + Notion + Linear in report mode → $0.075 (3 reports; OpenAI score 90 / 808 open roles, Notion 90 / 135, Linear 55 / 29).
Compute cost is almost zero (direct API, no proxy, ~1 request/board).
Report mode (mode: "report")
Instead of one row per job, emit one hiring-signal report per company. Each report row carries:
totalOpenRoles+hiringScore0-100 +hiringLabel(aggressive_hiring/active_hiring/steady_hiring/low_hiring/no_signal).hiringVelocity:{ recentWindowDays, netOpenRolesChange, hadPreviousRun, previousTotal }— the delta vs the previous run of the samestateKey.priorityRoles[]: top 5 role families (engineering, data, research, product, design, sales, customer_success, support, marketing, operations, finance, legal, people_hr, security, other) with example titles.departmentSignals[],regionSignals[](us / canada / europe_uk / europe_eu / latam / mena / apac / africa / remote_global / remote_other / other / unknown),remoteShare0.0-1.0,seniorityMix(junior / mid / senior / leadership).keywordHits: user-supplied strings mapped to how many open titles contain each (case-insensitive substring).expansionSignals:newDepartments[],newRegions[],newRoleFamilies[]compared to the previous run.recommendedOutreach[]: short English suggestions for BD / sales / talent outreach based on the above signals.reportConfidence0.1-1.0 pluswarnings[].
Example input:
{"boardSlugs": ["openai", "notion", "linear"],"mode": "report","keywordHits": ["AI", "ML", "LLM"],"stateKey": "weekly-pipeline"}
Previous-run deltas live in the named key-value store
ashby-report-<stateKey> on your account.
Daily deltas (onlyNewSinceLastRun)
Pair with Apify Scheduler to get only newly-posted jobs each run. The
first run of a given (stateKey, boardSlug) records every open jobId
and pushes the first maxJobsPerBoard rows (all tagged isNew: true).
Every later run compares the current open set against the stored one
and emits only rows whose jobId is new.
{"boardSlugs": ["openai", "notion", "linear"],"onlyNewSinceLastRun": true,"stateKey": "daily-pipeline","titleKeywords": ["engineer"],"minSalary": 250000,"salaryCurrency": "USD"}
The dedup state lives in a named key-value store ashby-diff-<stateKey>
on your account; delete it from the Apify Console to force the next run
to treat every job as new. Use different stateKey names for
independent downstream pipelines.
Notes
- Ashby returns every open job on a board in one JSON response (no
pagination).
maxJobsPerBoardis a safety trim for big boards. publishedAtis ISO 8601 with timezone offset exactly as returned by the API.- Jobs where
isListed: falseare skipped (they are present in the API but intentionally hidden by the employer). - Unknown slugs return HTTP 404 – the actor logs and skips. Some companies that look Ashby-flavoured actually live on Greenhouse (eg anthropic, perplexity-ai) – see our companion Greenhouse scraper.
- You can paste the full board URL (
https://jobs.ashbyhq.com/openai) instead of just the slug – the slug is extracted automatically.