Multi-ATS Job Board Scraper (Greenhouse, Lever, Ashby & More)
Pricing
from $3.00 / 1,000 job posting fetcheds
Multi-ATS Job Board Scraper (Greenhouse, Lever, Ashby & More)
Fetch normalized job postings from Greenhouse, Lever, Ashby, SmartRecruiters, and Recruitee in one run. Returns title, location, department, employment type, description, and apply URL.
Pricing
from $3.00 / 1,000 job posting fetcheds
Rating
0.0
(0)
Developer
Geo
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
10 hours ago
Last modified
Categories
Share
Multi-ATS Job Board Scraper (Greenhouse, Lever, Ashby, SmartRecruiters, Recruitee)
Fetch normalized job postings from five popular ATS platforms — Greenhouse, Lever, Ashby, SmartRecruiters, and Recruitee — in a single run. Get title, location, department, employment type, description, and apply URL, ready for pipelines, dashboards, or AI search.
Why use this actor
Talent data is siloed across ATS platforms. A single company may post jobs on Greenhouse while a competitor uses Lever. Checking each platform manually, or building and maintaining five separate API integrations, is expensive.
This actor gives you one normalized job dataset from all five platforms with a single input. It's designed for:
- Recruiters and sourcing teams monitoring competitor or partner job boards
- Product managers analyzing hiring trends by department, location, or role
- Data engineers building talent-intel pipelines or company-growth signals
- Developers automating job alerts, career aggregators, or internal hiring dashboards
- VC/PE analysts tracking portfolio company headcount via live job postings
Supported platforms
| Platform | Input example | Notes |
|---|---|---|
| Greenhouse | { "platform": "greenhouse", "companyId": "vercel" } | Official JSON board API; per-job description fetch available |
| Lever | { "platform": "lever", "companyId": "netflix" } | Official v0 postings API; crawl-delay honored |
| Ashby | { "platform": "ashby", "companyId": "notion" } | Documented public posting-api endpoint |
| SmartRecruiters | { "platform": "smartrecruiters", "companyId": "McDonalds" } | Official /v1/companies API |
| Recruitee | { "platform": "recruitee", "companyId": "acme" } | Public /api/offers/ endpoint |
Input
| Field | Type | Default | Description |
|---|---|---|---|
sources | array | required | List of {platform, companyId} objects |
maxJobsPerCompany | integer | 100 | Max jobs per source, capped at 500 |
includeDescription | boolean | true | Fetch and include full job description (plain text, HTML stripped) |
scrubPii | boolean | true | Redact incidental email/phone in descriptions (GDPR) |
maxTotalChargeUsd | number | 10.0 | Hard charge cap; actor stops gracefully when reached |
Output
One dataset record per job posting. Fields:
{"platform": "greenhouse","companyId": "vercel","jobId": "7612345","title": "Senior Software Engineer, Edge Network","location": "Remote","department": "Engineering","employmentType": null,"description": "Join Vercel's Edge Network team...","applyUrl": "https://boards.greenhouse.io/vercel/jobs/7612345","postedAt": null,"updatedAt": "2026-06-15T10:30:00Z","fetchedAt": "2026-07-28T12:00:00Z"}
Error records (invalid companyId, platform unreachable, zero results) are pushed to the dataset with "status": "error" and a plain-English "reason", so the run never exits silently on bad input.
Worked example + cost math
Input:
{"sources": [{ "platform": "greenhouse", "companyId": "vercel" },{ "platform": "lever", "companyId": "netflix" },{ "platform": "ashby", "companyId": "notion" }],"maxJobsPerCompany": 50,"includeDescription": true}
Expected events and cost:
| Event | Count | Unit price | Subtotal |
|---|---|---|---|
actor-start | 1 | $0.01 | $0.01 |
job-fetched | ~150 (50 per co.) | $0.003 | $0.45 |
| Total | ~$0.46 |
For 3 companies × 50 jobs each (150 jobs):
- Platform compute:
0.005 CU × $0.40/CU = **$0.002** (< 1% of revenue — well under the 30% cost cap) - Revenue per run: ~$0.46
- Gross margin: ~99%
At $0.003 per job, a user fetching 1,000 jobs/month spends $3.00 — comparable to a manual analyst spending 2–3 hours.
Compliance and rate limiting
- All five platforms are accessed via their official, documented public APIs (not HTML scraping)
- robots.txt honored on all target domains (Greenhouse: allows all; Lever: crawl-delay 1 honored; Ashby posting-api: not disallowed; SmartRecruiters /v1/companies/: explicitly allowed; Recruitee: Cloudflare-gated but public)
- Rate limited to ~1 request/second per-tenant, well within each platform's tolerance
- Descriptive
User-Agentheader set on every request - Incidental PII (recruiter emails/phones in descriptions) is redacted by default (
scrubPii: true) - No login-walled content, no candidate data, no session cookies
Limitations
- Workday is not supported: Cloudflare + Akamai bot-management makes reliable access infeasible without a browser; a separate Workday actor is warranted
- SmartRecruiters descriptions require a per-job secondary fetch that would multiply requests; descriptions are omitted for that platform to stay polite
- Recruitee descriptions similarly require a per-posting HTML parse; omitted for the same reason
- Company IDs are platform-specific slugs — use the slug visible in the platform's job board URL (e.g.
boards.greenhouse.io/vercel→vercel)
Integrations
- Apify API:
POST /v2/acts/gp005~multi-ats-jobs-scraper/runs— get a JSON feed of jobs in any pipeline - Make / n8n: Trigger on schedule, filter by department or location, post to Slack/Sheets
- MCP: Available via the Apify MCP server (
apify/actors-mcp-server) — let your AI assistant query live job postings - Webhooks: Use
ACTOR_RUN_FINISHEDwebhooks to push new jobs to your CRM, ATS, or data warehouse
FAQ
Which companyId should I use?
Use the slug in the platform's job-board URL. For Greenhouse it's boards.greenhouse.io/<slug>, for Lever it's jobs.lever.co/<slug>, for Ashby it's jobs.ashbyhq.com/<slug>.
Can I monitor new postings automatically? Yes — schedule the actor on a daily/weekly cadence and compare datasets across runs, or use Apify webhooks to get notified on completion.
Does this work for private/internal job boards? No — only publicly accessible boards (no login required) are supported.
Is this GDPR-compliant?
The core data (job titles, departments, locations) is not personal data. Descriptions may incidentally include recruiter contact details; the scrubPii: true default redacts those. Users are responsible for their own downstream data handling.
What if a company has no open jobs?
An error record is pushed with "reason": "No job postings found..." so you always get a result, not a silent empty run.