SmartRecruiters Scraper [From $0.8💰] | Job Data avatar

SmartRecruiters Scraper [From $0.8💰] | Job Data

Pricing

from $0.70 / 1,000 results

Go to Apify Store
SmartRecruiters Scraper [From $0.8💰] | Job Data

SmartRecruiters Scraper [From $0.8💰] | Job Data

Scrape all open job postings from any SmartRecruiters company board (jobs.smartrecruiters.com) via the public Posting API. Title, department, location, remote/hybrid, employment type, date, apply URL, full description and salary. Multi-company runs.

Pricing

from $0.70 / 1,000 results

Rating

0.0

(0)

Developer

Ahmed Jasarevic

Ahmed Jasarevic

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 days ago

Last modified

Categories

Share

SmartRecruiters Scraper — All Open Jobs From jobs.smartrecruiters.com

Scrape every open job posting from any SmartRecruiters company board (jobs.smartrecruiters.com) — many boards in one run — through SmartRecruiters' own public, keyless Posting REST API: no browser, no proxy, no CAPTCHA, no anti-bot bypass. A measured 1,000-posting run over Bosch Group (4,825 live postings) and Sportradar finished in 7.1–8.2 seconds with 42 structured fields per row.


Use Cases: Hiring Signals, Remote Job Feeds And Recruiting Intelligence

  • Hiring signals data for lead generation — a fresh posting means approved budget and an open pain; watch a prospect list's boards while roles are live.
  • Hiring intent data API for sales teams — pipe rows into your CRM so "company X opened 12 roles" becomes a trigger, not a manual check.
  • Competitor hiring intelligence — see which teams your rivals staff, where and at what seniority, from their own ATS.
  • Remote jobs data feed — isRemote and isHybrid come from the ATS itself, so remote filtering is a WHERE clause, not a guess from a location string.
  • A SmartRecruiters alternative to licensed job-data vendors — Lightcast, Textkernel and JobsPipe sell normalised feeds; public ATS APIs give you the raw material.

How It Works: The Public SmartRecruiters Posting API, No Browser Required

List (paged) GET https://api.smartrecruiters.com/v1/companies/{identifier}/postings?limit=100&offset={n}&q={query}
Detail GET https://api.smartrecruiters.com/v1/companies/{identifier}/postings/{postingId}

The list endpoint discovers postings (totalFound says how many exist); the detail endpoint returns the complete job ad (jobAd.sections, applyUrl, referralUrl, releasedDate, every employer customField). Both are read with CheerioCrawler as additionalMimeTypes: ['application/json'] parsing context.body — JSON in, JSON out, nothing rendered. Rows are normalised, salary is parsed, writes are batched (50 rows or 1.5 s). Why this beats the career-page HTML: below.


Input Parameters

FieldTypeRequiredDefaultNotes
companiesarray of stringYes— (prefilled BoschGroup, Sportradar)Identifiers — the path segment of jobs.smartrecruiters.com/{identifier}. Full board URLs are accepted and normalised. Many boards per run.
searchQuerystringNoemptyFull-text filter passed to the API's q (e.g. engineer). Empty = every open posting.
maxItemsintegerNo200Max postings across all companies combined. Range 1–5000.
includeDescriptionsbooleanNotruetrue fetches each posting's detail endpoint for full description text (~1 request per posting); false uses only the list endpoint, much faster (~1 request per 100 postings), no description text.
maxConcurrencyintegerNo32In-flight API requests. Range 1–64, capped 64; faster up to the API's ~200 req/s, then levels off.
proxyobjectNo{ "useApifyProxy": false }Standard Apify proxy picker, nothing hard-coded — none needed, the API answers with no anti-bot challenge.

Finding a company identifier: it is the path segment of the board URL — jobs.smartrecruiters.com/**BoschGroup** → BoschGroup — and is case-sensitive. An unknown identifier is not an error: the API returns totalFound: 0, the board is skipped (logged as 0 open postings), the run continues.


Output Fields

One dataset row per posting — 42 fields, exported as JSON, CSV, Excel, XML, JSONL or HTML.

  • Identity & organisation — companyIdentifier, companyName, postingId, uuid, refNumber (requisition reference, e.g. REF297662Y), title, department, team, function, industry, experienceLevel (seniority).
  • Location — city, region, country (lowercase ISO as published), postalCode, fullLocation, isRemote, isHybrid, additionalLocations[] (multi-site roles: {city, country, region, fullLocation, remote}).
  • Employment & timing — typeOfEmployment, employmentType (Full-time, Part-time, Contract…), contractType (Permanent / Fixed-term / Contractor), postedAt (ISO-8601), active, language, isEvergreen.
  • URLs — applyUrl (direct apply), postingUrl (public ad), referralUrl.
  • Salary — salaryText (raw snippet, null when pay is not published), salaryMin, salaryMax, salaryCurrency, salaryPeriod.
  • Description text — descriptionText / descriptionHtml, qualificationsText / qualificationsHtml, additionalInformationText, companyDescriptionText, from jobAd.sections.
  • Everything else — customFields (all employer-defined fields: legal entity, brands, worker type, tariff area…), scrapedAt (ISO-8601 row timestamp).

Text fields require includeDescriptions: true (the default); everything else comes from the list endpoint either way.


Example Input: Three Boards, Filtered

{
"companies": ["BoschGroup", "Sportradar", "SiemensHealthineers"],
"searchQuery": "engineer",
"maxItems": 300,
"includeDescriptions": true
}

Full board URLs work too: { "companies": ["https://jobs.smartrecruiters.com/BoschGroup"] }

Example Output: One Normalized Row Per Posting

{
"companyIdentifier": "BoschGroup",
"companyName": "Bosch",
"postingId": "10742915",
"refNumber": "REF297662Y",
"title": "Software Engineer, Embedded Systems",
"department": "Mobility Solutions",
"experienceLevel": "Mid-Senior Level",
"city": "Stuttgart",
"country": "de",
"fullLocation": "Stuttgart, Germany",
"isRemote": false,
"isHybrid": true,
"employmentType": "Full-time",
"contractType": "Permanent",
"postedAt": "2026-09-14T08:12:03.000Z",
"applyUrl": "https://jobs.smartrecruiters.com/BoschGroup/10742915/application",
"postingUrl": "https://jobs.smartrecruiters.com/BoschGroup/10742915",
"salaryText": "70,000 - 85,000 EUR per annum",
"salaryMin": 70000,
"salaryMax": 85000,
"salaryCurrency": "EUR",
"descriptionText": "You will develop embedded software for our vehicle domain controllers…",
"customFields": { "Global Salary Level": "EG12", "Worker Type": "Employee" },
"scrapedAt": "2026-10-05T09:41:22.000Z"
}

All 42 fields are documented above; this is the shape of one row.


SmartRecruiters API Vs Career-Page HTML: Why This Actor Never Renders A Browser

Surface used: SmartRecruiters' public Posting REST API (JSON). The recon followed the cheapest-surface-first rule:

  1. Embedded JSON in the HTML (__NEXT_DATA__, application/ld+json): jobs.smartrecruiters.com/BoschGroup returns 200 but is a pure SPA shell — the only script-level blob in the 78 KB of HTML is Google Tag Manager's dataLayer (9 occurrences), with zero job data, no ld+json, no __NEXT_DATA__.
  2. Third-party search backend (Algolia / Elasticsearch / Meilisearch / TypeSense): none — SmartRecruiters has no such index; its boards run on its own backend.
  3. Internal / mobile JSON API: ✅ the vendor's own officially documented developer API — HTTP 200, clean JSON, no API key, no cookies, no Cloudflare challenge, no session state.

It is the same source the career portal renders from, so nothing is lost: no browser means CheerioCrawler on JSON rather than PlaywrightCrawler — roughly an order of magnitude cheaper on Apify compute units; the detail endpoint still returns the complete structured ad (jobAd.sections: jobDescription, qualifications, additionalInformation, companyDescription, plus applyUrl, referralUrl, releasedDate and the whole customField array); and totalFound + offset give deterministic pagination for free.

server: cloudflare and cf-ray are present on the board HTML, but the API host answers the same IP with a plain 200 — no anti-bot bypass, residential proxy or paid anti-bot vendor required.

Paging: the list endpoint silently clamps limit to 100 (ask for limit=500, get 100), so the Actor pages at 100 with offset until totalFound is exhausted — and because totalFound arrives with page 1, all remaining pages are scheduled at once rather than chained. maxRequestsPerCrawl is derived from the input, so a run can never run away.

Re-verifying the contract — documented at developer.smartrecruiters.com:

curl -s "https://api.smartrecruiters.com/v1/companies/BoschGroup/postings?limit=2" | jq '.totalFound, .content[0].name'
curl -s "https://api.smartrecruiters.com/v1/companies/BoschGroup/postings/<postingId>" | jq '.jobAd.sections | keys'

All endpoints live in src/routes.ts (listUrl / detailUrl / makeListRequest / makeDetailRequest), so an API change is a one-file fix; mapping is buildRecord() in src/main.ts, salary parsing in src/salary.ts.


Salary Data Scraping: Extract Pay From SmartRecruiters Job Postings

SmartRecruiters has no standard salary field, so the Actor looks where pay actually appears:

  1. customField entries whose label matches /salary|compensation|remuneration|pay|wage|stipend/i (e.g. Bosch's Global Salary Level, or a Salary Range band).
  2. Free text in additionalInformation / jobDescription / qualifications with a currency marker, a k magnitude suffix or an explicit range — so "5 years of experience" is never mistaken for pay.

Currency detection covers symbols ($ £ € ¥ ₹ ₽) and ISO codes; parsing handles US (120,000) and EU (50.000) separators plus 70-85k shorthand, landing in salaryText, salaryMin, salaryMax, salaryCurrency, salaryPeriod. When the employer does not publish pay, salaryText is null — the honest answer, not a parsing failure: filter on it to isolate pay-transparent employers, or keep the nulls as "disclosure unknown".

Scrape SmartRecruiters Jobs 6x Faster: Parallel Runtime, Cost And Free Tier

  • CheerioCrawler, 256 MB default memory, no browser; maxRequestRetries: 3, 60 s handler timeout, maxRequestsPerCrawl computed from the input.
  • ~1 request per posting with includeDescriptions: true; ~1 request per 100 postings with false.
  • maxConcurrency: 32 (configurable, capped 64). No paid anti-bot API, no residential proxy — the proxy input is optional and off by default.

Throughput is bounded by API latency, and the Actor hides it: all list pages are enqueued up front (page 1's totalFound is known immediately, so every remaining offset 100, 200, … page is pushed in one batch instead of chained), detail fetches run in a parallel pump capped at maxConcurrency with backoff on 429 / 5xx / 408 (the request queue is used only for list pages — a storage round trip per request is expensive), and dataset writes are batched to Dataset.pushData in groups of 50 rows or every 1.5 s, with the final flush awaited before exit so no row is lost to shutdown.

Measured on the same machine, same boards (BoschGroup + Sportradar, 1000 postings, descriptions on):

VersionWall timeRows
Serial (concurrency 4, one page at a time, one row push per posting)48.2 s998
Parallel (concurrency 32, all pages up front, detail pump, batched writes)7.1–8.2 s1000

Roughly 6× faster, every requested row delivered; beyond ~32 requests speed levels off because the API caps out around 200 req/s.

Price: pay-per-event — result $0.0008 on the free plan, $0.0007 on GOLD+, per row, plus Actor Start $0.00005 per run. The gate checks APIFY_USER_IS_PAYING: 🆓 free users get a capped preview of the first 10 postings (all companies combined); ⭐️ paid users get the full maxItems (up to 5000). The cap is enforced by never enqueueing further detail requests — a free run is hard-bounded at 10 postings rather than killed mid-flight.


SmartRecruiters API Python: Query The Posting API Or Drive This Actor

Raw API — no key, no session, but you rebuild pagination and normalisation yourself:

import requests
BASE, identifier = "https://api.smartrecruiters.com/v1/companies", "BoschGroup" # case-sensitive
jobs, offset = [], 0
while True:
page = requests.get(f"{BASE}/{identifier}/postings", timeout=30,
params={"limit": 100, "offset": offset}).json() # limit clamps to 100
jobs.extend(page["content"]); offset += 100
if offset >= page["totalFound"] or not page["content"]:
break
detail = requests.get(f"{BASE}/{identifier}/postings/{page['content'][0]['id']}", timeout=30).json()
print(len(jobs), detail["jobAd"]["sections"].keys())

Or run this Actor and get the 42 normalised fields, multi-company handling, the salary parser and the free-tier rules already applied:

import requests
items = requests.post(
"https://api.apify.com/v2/acts/ahmed_jasarevic~jobs-smartrecruiters-scraper/run-sync-get-dataset-items",
params={"token": "YOUR_TOKEN", "waitsecs": 60},
json={"companies": ["BoschGroup", "Sportradar"], "maxItems": 500}, timeout=90).json()
print(len(items), items[0]["title"], items[0]["salaryText"])

SmartRecruiters Job Postings Data For Talent Acquisition Analytics And Labour Market Intelligence

  • postedAt (ISO-8601) — a real publish date from the ATS, not a re-scrape date; diff two runs on it to see what is genuinely new.
  • department / function / experienceLevel / team — headcount mix by organisational unit and seniority, per company or across a watchlist.
  • isRemote / isHybrid / fullLocation / additionalLocations[] — location strategy from the employer's own flags; customFields keeps employer-specific structure (legal entity, brands, worker type) intact; scrapedAt orders interleaved snapshots.

companies accepts many boards per run, so the same input scales from one client's board to a 50-company watchlist — Bosch Group alone publishes 4,825 live postings on a single identifier. Schedule it (daily for monitoring, weekly for benchmarking) and let the dataset accumulate; there is no built-in delta mode, so diff downstream on postedAt.


Build A Job Postings Database With A Job Market Data API - Labor Market Intelligence

  • Public ATS APIs — SmartRecruiters, Greenhouse, Lever, Ashby, Workable, Personio and Workday all publish keyless job endpoints: fresh, direct-from-source postings, at compute cost plus $0.0008 per row here.
  • Multi-ATS Store Actors — several schemas normalised into one dataset: softyways/greenhouse-lever-ashby-workday-job-scraper $1.50/1k, glidepath/ats-jobs-scraper (10 ATS) $1.75/1k.
  • Licensed vendors — Lightcast, Textkernel and JobsPipe sell cross-platform coverage, dedup and history at enterprise licensing prices; JobsPipe's claim that its public feed is plan-tier dependent is a self-published, unverified vendor claim.

The public-API route is the cheap one — the same material paid aggregators ingest, minus their dedup layer. What you give up is cross-ATS coverage: you must know which ATS each target runs, which is why the Related Actors list pairs this scraper with multi-ATS and Indeed/LinkedIn sources instead of pretending one feed is the whole market.

Greenhouse, Lever, Ashby And Workday Job API Comparison

Which ATS platforms expose public job APIs? SmartRecruiters, Greenhouse, Lever, Ashby, Workable, Personio and Workday — all keyless. SmartRecruiters vs Greenhouse vs Lever: none needs a key, but the shapes differ — SmartRecruiters paginates at 100 with totalFound and returns full jobAd.sections on the detail call; Greenhouse needs a second call for the description; Lever does not. SmartRecruiters' quirk is the silent limit clamp to 100, which this Actor handles for you.

What other SmartRecruiters Store Actors charge (verified Store listings): memo23/smartrecruiters-scraper $0.0009/result + $0.025 start (24 users, 5.0★); jobo.world/smartrecruiters-jobs-scraper-api $0.0031/job (50 users / 10 monthly); schnellscrapers/smartrecruiters-jobs-scraper $1 per 1,000; blooming_gator/smartrecruiters-jobs-api $5 per 1,000 with only 53.6% of runs succeeded; parseforge $0.04116/result — against this Actor's $0.0008/row (free plan), $0.0007/row (GOLD+) + $0.00005 start.

Need more than SmartRecruiters in one run? softyways/greenhouse-lever-ashby-workday-job-scraper covers 7 ATS at $1.50/1k; glidepath/ats-jobs-scraper covers 10 ATS at $1.75/1k.


Scrape Indeed And LinkedIn Jobs For A Multi-Source Job Data Pipeline

SmartRecruiters boards cover the employer's own careers site; aggregators combine them with the big boards, where the authoritative Store Actors are valig/indeed-jobs-scraper (32,875 users, 4.73★) and borderline/indeed-scraper (26,346 users, 4.63★, $0.005/job) on Indeed; curious_coder/linkedin-jobs-scraper (168,213 users, 4.59★, $0.001/result) and bebity/linkedin-jobs-scraper (42,299 users, 4.31★) on LinkedIn. ATS feeds are fresher and employer-authoritative but company-by-company; the aggregators give breadth across companies you never listed — use this Actor for depth on named targets, them for discovery.


Integrations & Automation: Apify API, Webhooks, Zapier, Make & Schedules

  • Apify REST API — POST https://api.apify.com/v2/acts/ahmed_jasarevic~jobs-smartrecruiters-scraper/runs?token=YOUR_TOKEN with the input JSON as the body, then read the dataset; the Python and JavaScript SDKs (apify-client-python / apify-client-js) make the same call.
  • Webhooks — fire on actor.run.SUCCEEDED to push each finished dataset into your database, CRM or Slack.
  • Zapier and Make — every Apify Actor is callable as a Zap or scenario; map dataset items to rows or sheets.
  • Schedules — daily for hiring-intent monitoring and competitor hiring intelligence; weekly for talent acquisition analytics and compensation benchmarking; hourly only if you power live job alerts.
  • Console — paste the Example Input JSON and hit Run; rows appear under Storage → Dataset, exportable as JSON, CSV, Excel, XML, JSONL or HTML.

FAQ

Is there an official SmartRecruiters API for job postings?

Yes. api.smartrecruiters.com/v1/companies/{identifier}/postings is publicly documented at developers.smartrecruiters.com and needs no API key, no OAuth token, no session and no cookies. The per-posting detail endpoint adds the full jobAd.sections text. This Actor is a thin paginated and normalised wrapper around those two endpoints.

How do I get all open jobs from jobs.smartrecruiters.com for many companies?

Put every board identifier into companies (BoschGroup, Sportradar, ... — the part after jobs.smartrecruiters.com/, case-sensitive; full board URLs are also accepted). The Actor pages the list endpoint at 100 postings per call, schedules every remaining page up front from totalFound, and fetches detail for each posting when includeDescriptions is on. One run handles a single client board or a 50-company watchlist.

What is the best way to scrape job postings without a browser?

Use the ATS's own public API rather than the career-page HTML. The SmartRecruiters career page is a JavaScript shell that ships only a GTM dataLayer — no job data, no ld+json, no __NEXT_DATA__ — so HTML scraping needs a full browser renderer and a proxy. The JSON API answers plainly with HTTP 200, which is what this Actor runs on (CheerioCrawler parsing context.body), roughly an order of magnitude cheaper than PlaywrightCrawler and with no anti-bot bypass involved.

SmartRecruiters vs Greenhouse vs Lever: which has the best public jobs API?

All three expose keyless endpoints. SmartRecruiters paginates at 100 with a totalFound counter (and silently clamps limit to 100 — this Actor handles that) and returns complete jobAd.sections on the detail call. Greenhouse needs a second call to get description text. Lever does not paginate the same way. If you are comparing Store Actors instead of raw endpoints: softyways/greenhouse-lever-ashby-workday-job-scraper covers 7 ATS platforms in one schema at $1.50/1k.

Can I get salary data from job postings programmatically?

Partly. SmartRecruiters has no standard salary field, so pay appears either in customFields whose label matches salary, compensation, remuneration, pay, wage or stipend, or in free text carrying a currency marker. This Actor parses both, handling currency symbols, ISO codes, US 120,000 and EU 50.000 separators and the 70-85k shorthand, and returns salaryText / salaryMin / salaryMax / salaryCurrency / salaryPeriod. When the employer does not publish pay, salaryText is null — an honest answer rather than a failure.

How can I build a job postings database with a job market data API?

Three routes: public ATS APIs (SmartRecruiters, Greenhouse, Lever, Ashby, Workable, Personio, Workday — all keyless), multi-ATS Store Actors that normalise several schemas into one dataset, or licensed vendors such as Lightcast, Textkernel and JobsPipe. The public-API route is the cheap one — the same material aggregators ingest — at compute cost plus $0.0008 per row here; what you give up is cross-ATS coverage, because you must know which ATS each target runs.

Which ATS platforms expose public job APIs?

SmartRecruiters, Greenhouse, Lever, Ashby, Workable, Personio and Workday all publish keyless job endpoints. Store Actors exist for the multi-ATS case (softyways/greenhouse-lever-ashby-workday-job-scraper for 7, glidepath/ats-jobs-scraper for 10) and for the aggregators (valig/indeed-jobs-scraper, curious_coder/linkedin-jobs-scraper).

Job postings are published by the employers themselves for the public to read, and this Actor needs no login, no CAPTCHA solving and no personal contact data. SmartRecruiters' own Customer Terms restrict customers from running automated scripts against the SmartRecruiters Applications; the public Posting API is separately documented for programmatic use. You remain responsible for your own compliance with the source's Terms of Service, robots policy and applicable data-protection law.

SEO Keywords

smartrecruiters api, smartrecruiters scraper, scrape smartrecruiters jobs, smartrecruiters api python, jobs.smartrecruiters.com, smartrecruiters job postings data, smartrecruiters jobs scraper apify, job postings database, hiring signals data, hiring intent data api, job market data API, remote jobs data feed, salary data scraping, recruiting intelligence, talent acquisition analytics, labour market intelligence, labor market intelligence, ats data extraction, job aggregator data source, best job scraping api, greenhouse lever ashby workday job api, scrape indeed linkedin jobs

For AI Agents & LLM Apps

Purpose: returns every open job posting from one or more jobs.smartrecruiters.com boards as 42 normalised dataset rows, read from the public keyless SmartRecruiters Posting API.

Minimal input — the smallest run that works:

{ "companies": ["BoschGroup"] }

Filtered variant (the only other fields an agent normally touches):

{ "companies": ["BoschGroup", "Sportradar"], "searchQuery": "engineer", "maxItems": 500, "includeDescriptions": false }

Output fields: companyIdentifier, companyName, postingId, uuid, refNumber, title, department, team, function, industry, experienceLevel, city, region, country, postalCode, fullLocation, isRemote, isHybrid, additionalLocations, typeOfEmployment, employmentType, contractType, postedAt, active, language, isEvergreen, applyUrl, postingUrl, referralUrl, salaryText, salaryMin, salaryMax, salaryCurrency, salaryPeriod, descriptionText, descriptionHtml, qualificationsText, qualificationsHtml, additionalInformationText, companyDescriptionText, customFields, scrapedAt.

Behaviors an agent should know:

  • companies is the only required field. Identifiers are case-sensitive; an unknown identifier returns totalFound: 0 and is skipped without an error, so a typo silently yields zero rows — pass the exact slug from the board URL.
  • Full board URLs (https://jobs.smartrecruiters.com/BoschGroup) are accepted and normalised to the identifier automatically.
  • Never paginate yourself: the list endpoint silently clamps limit to 100. The Actor reads totalFound from page 1 and schedules all remaining pages up front.
  • includeDescriptions defaults to true and costs roughly one extra request per posting; set it to false to use only the list endpoint (~1 request per 100 postings, much faster, no description text).
  • maxItems defaults to 200, caps at 5000, and counts across all companies combined, not per board.
  • On a non-paying plan the run is hard-bounded at the first 10 postings across all companies; paying plans get the full maxItems.
  • searchQuery maps straight to the API's q parameter; leave it unset for every open posting.
  • maxConcurrency defaults to 32 (capped at 64); the API tops out around 200 requests/s.
  • No browser and no proxy are required — the default proxy (useApifyProxy: false) is correct; leave it alone.
  • Salary is parsed by the Actor; salaryText: null means the employer does not publish pay.

Billing: pay-per-event — result at $0.0008 per row on the free plan ($0.0007 on GOLD+), plus Actor Start at $0.00005 per run. No other billed events.

  • This Actor is an independent tool. It is not affiliated with, endorsed by or sponsored by SmartRecruiters SE or jobs.smartrecruiters.com.
  • It reads the publicly documented, keyless SmartRecruiters Posting API (api.smartrecruiters.com) — no login, no CAPTCHA solving, no session hijacking and no browser fingerprint spoofing. It does not touch applicant accounts or application data.
  • The output contains publicly published job postings and employer-authored descriptions. It contains no applicant personal data and no personal contact details (no emails, no phone numbers).
  • SmartRecruiters' Customer Terms restrict customers from using automated agents or scripts to strip or mine data from the SmartRecruiters Applications; the public Posting API is documented separately for programmatic access. Users are responsible for their own compliance with the source platform's Terms of Service, its robots policy and applicable data-protection law (for example GDPR where you process data about individuals in the EU).