Careerjet Scraper [From $3.5💰] | Jobs | 23 Portals | Salary avatar

Careerjet Scraper [From $3.5💰] | Jobs | 23 Portals | Salary

Pricing

from $3.30 / 1,000 results

Go to Apify Store
Careerjet Scraper [From $3.5💰] | Jobs | 23 Portals | Salary

Careerjet Scraper [From $3.5💰] | Jobs | 23 Portals | Salary

Scrape job postings from Careerjet's 23 country portals for job posting aggregation, hiring trend analysis and job board backfill. Structured JSON with parsed salary fields via the Apify API.

Pricing

from $3.30 / 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

2 days ago

Last modified

Categories

Share

Careerjet Scraper

Scrape job postings from Careerjet's 23 verified country portals — France, Spain, Italy, the Netherlands, Poland, Austria, Portugal, Sweden, Switzerland, Czechia, Japan, Brazil, Norway, Finland, Hungary, Slovakia, Romania, Ukraine, Russia, South Korea, Türkiye, Israel and Singapore — in a single run, with no official API account required. One pay-per-event run returns job title, company, location, parsed salary, posting date, full description and the outbound apply URL for every ad it finds.

Built for recruiters, job-board operators, labour-market analysts and hiring-signal lead-gen teams that need cross-country vacancy data as a job listings data feed. Careerjet is an aggregator — it never hosts the vacancy, so each row carries the employer (company, companyUrl) and the origin site (publisherName / publisherUrl) it indexed the ad from.

Main use cases

  • Job posting aggregation — collect openings across many countries in one run instead of merging per-board exports by hand.
  • Job market research and hiring trend analysis — snapshot the same query on a schedule to see which roles, employers and locations are growing.
  • Job board backfill and job feed syndication — populate a niche job board with structured listings that link out to the employer's own application page.
  • Salary benchmarking and recruitment data — parsed salaryMin / salaryMax / salaryCurrency / salaryPeriod fields turn raw ads into comparable pay ranges.
  • Competitor hiring tracking and job board monitoring — watch a company's or sector's live vacancies as a leading demand signal.

How it works

The Actor is a plain CheerioCrawler — server-rendered HTML over HTTP, no browser at all. Careerjet's markup is classic server-rendered PHP (no __NEXT_DATA__, no client-side search index), so every job card can be parsed from the raw response. A run works in five steps:

  1. A 12-second probe of the first listing URL logs HTTP status, byte count and whether the answer is the Cloudflare Turnstile challenge — the first log lines say why the run will return rows or 0 rows.
  2. Listing pass parses every served page into cards.
  3. Listing recovery rotates challenged listing pages through up to three fresh exit IPs.
  4. Detail pass, probed first fetches one /jobad/<id> per cookie-less host to test whether the host is gated; gated hosts have their remaining ads skipped instead of fetched.
  5. Bounded detail retry re-fetches at most 10 challenged detail pages once from a fresh IP.

Careerjet gates every content page behind a Cloudflare Turnstile interstitial served from /bi-verifycc. This is an IP-reputation gate, not a JavaScript-rendering gate — a datacenter IP is always challenged, a residential one is usually served — which is why the whole Actor stays on plain HTTP with the RESIDENTIAL proxy group pre-enabled.

Scrape job listings from Careerjet's 23 verified country portals

Careerjet's gate is per portal, not per IP. Some domains serve their listing page to any residential exit IP; others answer every request — from any exit IP, and however many different ones are tried — with the interstitial. Verified over plain HTTP on the RESIDENTIAL group on 2026-10-07:

Listing page served (23)Listing page always gated (13)
.fr .es .it .nl .pl .at .pt .se .ch .cz .jp .com.br .no .fi .hu .sk .ro .ua .ru .co.kr .com.tr .co.il .com.sg.com (US) .co.uk .de .ie .com.au .co.in .be .dk .co.za .sg .co.nz .ae .ly

The gated portals are what the input dropdown omits: they answer every request with the interstitial and can only ever return 0 rows here, so the Actor never claims them.

Why rows = portals × 5. Careerjet serves a 5-card, pager-less listing page to a guest session and ignores page=N (measured on 16 portals; ?page=2..4 returns page 1's ads, which the row buffer deduplicates). A run therefore scales by portals, never by pages, and maxItems is the only row-shaped input: with countryDomains empty the Actor plans ceil(maxItems / 5) verified portals (30 → 6, 100 → 20 of the 23 available). An explicit portal list is the starting point — when it cannot hold maxItems the Actor tops it up with more verified portals and logs which ones it added. The practical ceiling is 115 rows (the most the 23 verified portals hold).

Measured run times (Actor run only — Apify adds container start-up on top):

RunResult
.fr, 5 rows, details on10 s — 5 rows card-only; details tried twice (fresh exit IP on the 2nd try)
.es, 5 rows, details on8 s — 5 rows card-only
6 open portals in one run, listing only25 s — 20 rows; 2 gated pages rotated 3× then reported
5 default portals, details on9 s — 25 rows card-only; 1 probe/host, 20 ads skipped, 5 challenges (was 35)
.com (US) alone, details on8 s — 0 rows, 4 exit IPs challenged, explicit error instead of silence
14 remaining portals, one bulk probe26 s — 11 served (55 rows), .co.nz .ae .ly challenged from 3 exit IPs each

Job posting aggregation across country portals in a single run

Careerjet renders every job card server-side in plain HTML, with no client-side templating. The same card markup appears on search-results pages and in Careerjet's own "Latest jobs" section.jobs-contextual block, so the parser was validated offline against real, live server-rendered HTML rather than assumed:

<section class="jobs-contextual standard">
<ul class="jobs">
<li>
<article class="job clicky" data-url="/jobad/us222530badcca995d5d84006ae36d046c">
<header><h3><a href="/jobad/us222530badcca995d5d84006ae36d046c">…</a></h3></header>
<p class="company">UniFirst</p>
<ul class="location"><li><svg class="icon" /> Tacoma, WA</li></ul>
<ul class="salary"><li><svg class="icon" /> $31.25-33.65 per hour</li></ul>
<div class="desc">Description: …</div>
<footer><ul><li><span class="badge">Just now</span></li></ul></footer>
</article>
</li>
</ul>
</section>

Detail-page selectors come from Careerjet's own published stylesheet static.careerjet.org/css/all.min.css, which declares the layout explicitly:

#job>.container>header .job-title /* title */
#job>.container>header .company a /* company */
#job>.container>header .details>li /* location, date, contract type, salary */
#job>.container>.content /* description body */
#job .actions a /* apply button */

Every selector has a looser fallback, so a partial markup change degrades a field instead of breaking the run.

Exact endpoints used

PurposeURL pattern
Search (most portals)https://{portal}/jobs?s={keywords}&l={location}&sort={sort}&page={n}
Search (UK)https://www.careerjet.co.uk/search/jobs?s=…&l=…
Search (DE)https://www.careerjet.de/suchen/stellenangebote?s=…&l=…
Job detailhttps://{portal}/jobad/{2-letter country}{32 hex chars}

The s / l parameter names are not guesswork — they come from Careerjet's own <form id="search-main" method="get" action="/jobs">, whose inputs are name="s" (What) and name="l" (Where). Localized search routes are stored per portal in src/countries.ts; if a portal's primary route renders zero cards the Actor retries once on that portal's next known route.

Proxy is effectively required

Careerjet puts every content page behind a Cloudflare Turnstile interstitial served from /bi-verifycc, confirmed on all 29 country domains tested plus a Google-Cloud-hosted reader proxy — i.e. every datacenter IP is challenged, regardless of User-Agent, headers or HTTP version.

AttemptResult
Cheerio, direct (no proxy)blocked
Cheerio + Apify Proxy RESIDENTIAL, apifyProxyCountry: GBlisting served; job-ad pages still challenged
Spoofed User-Agent (Googlebot / bingbot / empty)blocked — the WAF judges the IP, not the UA
TLS-impersonating client (curl_cffi)blocked — Chrome's TLS + HTTP/2 fingerprint is not enough
Apify UNBLOCKER proxy group502 (no such group for this account)
Careerjet RSS / sitemap / /jobview/ / /clk/ / /apply/404 — legacy surfaces are gone
Playwright headless Chrome + RESIDENTIALblocked — waited the full 45 s
Playwright headed under Xvfb + RESIDENTIALcleared on a fresh exit IP, but only after up to ~60 s/page

A headed browser did work — and that is exactly what this build drops. It costs 40–90 s per page and the 2 GB Playwright image, and the only thing it ever buys beyond plain HTTP is the full description. Enable the proxy input and pick the RESIDENTIAL group, ideally with apifyProxyCountry set to the portal's country (FR for .fr, JP for .jp). The Actor pins the run to one sticky exit IP because a cached clearance cookie only passes from the address it was earned on, and switches to a fresh session whenever a pass comes back challenged. If every listing page was challenged it exits with an explicit error — it never silently returns an empty dataset.

Output Fields: structured job data across all 23 country portals

One row per job posting; exactly one row per ad id — listing data is buffered and the /jobad/<id> detail fetch overwrites it, so a row is never duplicated or half-empty. The Output tab is driven by .actor/output_schema.json and renders the same dataset through two views: Overview (one line per job) and Details (every extracted field).

FieldNotes
adIdAd id: 2-letter country code + 32 hex chars, e.g. us222530badcca995d5d84006ae36d046c. Unique across portals — the row key.
countryCodeThe 2-letter prefix parsed out of adId.
domainCareerjet country portal the row was scraped from.
urlCanonical /jobad/<id> page.
titleJob title as rendered by Careerjet.
company, companyUrlHiring company + employer profile page when the card links one (else null).
location, locations[]Raw location text plus the comma/slash split parts for multi-site ads.
salarySalary exactly as Careerjet renders it (may be null — many ads publish none).
salaryMin, salaryMaxLower/upper bounds parsed out of salary.
salaryCurrency, salaryPeriodCurrency symbol/code detected; pay period (hour/week/month/year).
datePostedLabel, datePostedRelative label as shown, plus a best-effort ISO-8601 date.
description, descriptionHtmlFull posting body (plain text + HTML) — detail fetches only.
listingExcerptTeaser text from the search-results card.
employmentType, badgesContract / working-hours chips and all footer chips (incl. posting date).
applyUrlThe portal's apply link (detail fetches only).
publisherName, publisherUrlOrigin site Careerjet indexed the ad from, derived from applyUrl.
query, queryLocationKeywords and location the search that surfaced this ad was run with.
source, scrapedAtEmitted by careerjet; ISO-8601 parse timestamp.

The salary/date parsers were validated offline against a real, unchallenged listing fragment: 5/5 cards parsed with 0 missing adId/title/company/location/url, and $18.50-19.25 per hour → 18.5/19.25/USD-hour, £45,000 – 55,000 per year → 45000/55000/GBP-year, €2.500 per maand → 2500/EUR-month.

Input Parameters

FieldTypeRequiredDefaultNotes
startUrlsarrayNo[]Explicit Careerjet search URLs. When filled, keywords, location and countryDomains are ignored.
keywordsstringNosoftware engineerJob title, keywords or company, sent as the s search parameter.
locationstringNo""City or region, sent as the l parameter. Empty = country-wide search.
countryDomainsstring[]No[]Multiselect of the 23 verified portals. Empty = the Actor auto-selects ceil(maxItems / 5) portals and tops up a short selection.
sortenumNorelevancerelevance | date | salary.
maxItemsintegerNo100The row target (1–2000). The Actor plans ceil(maxItems / 5) portals and stops at the target.
includeJobDetailsbooleanNotrueFetch each /jobad/<id> over HTTP for the full description + apply URL. Gated pages ship card-only.
maxRequestsPerCrawlintegerNo400Safety cap on total HTTP requests (1–5000).
proxyobjectNoRESIDENTIAL, Apify Proxy onPre-enabled. RESIDENTIAL is effectively required; the run pins one sticky session.

Free Apify accounts are automatically capped at 10 jobs per run.

Example Input And Output

Row target only (recommended) — portals are derived from maxItems:

{
"keywords": "software engineer",
"location": "",
"sort": "date",
"maxItems": 100
}

Plans ceil(100 / 5) = 20 verified portals, one request each, and stops at 100 rows.

Pinned to three portals:

{
"keywords": "nurse",
"countryDomains": ["www.careerjet.fr", "www.careerjet.es", "www.careerjet.it"],
"maxItems": 15
}

Fast listing-only run (no detail fetches — ~1 request per portal):

{ "keywords": "nurse", "includeJobDetails": false, "maxItems": 50 }

Example output row:

{
"adId": "fr222530badcca995d5d84006ae36d046c",
"countryCode": "fr",
"domain": "www.careerjet.fr",
"url": "https://www.careerjet.fr/jobad/fr222530badcca995d5d84006ae36d046c",
"title": "Ingénieur logiciel senior",
"company": "Acme SAS",
"companyUrl": "https://www.careerjet.fr/company/acme",
"location": "Paris, Île-de-France",
"locations": ["Paris", "Île-de-France"],
"salary": "45 000 € - 55 000 € par an",
"salaryMin": 45000,
"salaryMax": 55000,
"salaryCurrency": "€",
"salaryPeriod": "year",
"datePostedLabel": "il y a 2 jours",
"datePosted": "2026-10-03T00:00:00.000Z",
"description": "Nous recrutons un ingénieur logiciel senior pour …",
"listingExcerpt": "Nous recrutons un ingénieur logiciel senior …",
"employmentType": ["Temps plein", "CDI"],
"badges": ["il y a 2 jours", "Temps plein"],
"applyUrl": "https://careers.acme.example/jobs/1234",
"publisherName": "careers.acme.example",
"publisherUrl": "https://careers.acme.example",
"query": "software engineer",
"queryLocation": "",
"source": "careerjet",
"scrapedAt": "2026-10-05T12:00:00.000Z"
}

Careerjet API vs this scraper

Careerjet does run an official API, but it is not open: v4 (search.api.careerjet.net/v4/query) requires a publisher account, an API key via HTTP Basic auth, and a mandatory IP whitelist. It caps depth at 10 pages × 100 results and omits the origin site. The legacy affiliate API (public.api.careerjet.net/search) is dead, internal hosts (api.careerjet.net) return Unrecognized request URL on every route, and ac.careerjet.net is only the type-ahead autocompleter, not job data.

This Actor is the no-account route to the same listings: it reads what a guest browser sees and returns 28 structured fields the partner API does not, including publisherName / publisherUrl. If you already hold a Careerjet partner account, prefer the official v4 API for supported access — and use this Actor when you need cross-portal coverage without signing up.

Integrations & Automation

  • Apify API / Dataset API — every run's rows are available as JSON via /v2/datasets/{datasetId}/items?format=json&clean=true.
  • Webhooks — trigger downstream jobs on run completion (e.g. push new rows to your DB or ATS).
  • Zapier / Make — connect the dataset to hundreds of apps without writing code.
  • Schedules — recommend a daily run per target query for job market monitoring, or weekly for slower-moving hiring-trend snapshots. Recurring runs build the time series that makes trend analysis possible, and they improve the Actor's Store recommendation signals.

FAQ

Is there an official Careerjet API?

Yes — Careerjet publishes a v4 partner API at search.api.careerjet.net/v4/query, but it requires a publisher account, an API key with HTTP Basic auth (empty password) and a whitelisted IP, and it caps results at 10 pages × 100. The legacy affiliate API is dead. This Actor needs no account.

What are the alternatives to this Actor?

Apify Store carries several Careerjet actors (see Related Actors) plus broader job-posting aggregators. Commercial job-data vendors such as TheirStack, JobsPikr, Jobo Data and jobdataapi publish job feeds too. The open-source JobSpy library is a common alternative for multi-board scraping in Python. This Actor's differentiator is no-account access to 23 verified Careerjet portals with parsed salary fields and the outbound apply URL.

How do I aggregate job listings from multiple job boards?

Run the Actor once across as many Careerjet portals as you need — set keywords and let maxItems drive portal selection, or pin countryDomains explicitly. Every row lands in one dataset keyed by adId, so there is no per-board export to merge by hand.

Is there a job listings API?

The Actor's own Dataset API is one: GET /v2/datasets/{datasetId}/items?format=json&clean=true returns the structured rows as JSON. Combined with the pay-per-event pricing (result $0.0035), you get a job-listings API without a partner agreement.

How do I get salary data for benchmarking from job postings?

Each row carries salaryMin, salaryMax, salaryCurrency and salaryPeriod, parsed from the raw salary string — for example £45,000 – 55,000 per year becomes 45000/55000/GBP/year. Ads with no published salary have salary: null and null bounds, so filter those out before averaging.

Legality depends on the source's Terms of Service and your jurisdiction. This Actor does not scrape Indeed or LinkedIn — it scrapes Careerjet, whose robots.txt disallows the paging/legacy routes but not the /jobad/ detail path this Actor reads. Review those terms and your own compliance requirements before running at scale.

Which countries does Careerjet cover in this Actor?

23 portals are verified to return rows: France, Spain, Italy, the Netherlands, Poland, Austria, Portugal, Sweden, Switzerland, Czechia, Japan, Brazil, Norway, Finland, Hungary, Slovakia, Romania, Ukraine, Russia, South Korea, Türkiye, Israel and Singapore. Careerjet's US, UK, Germany, Ireland, Australia, India and several other portals are always gated and are omitted from the input dropdown.

What is the difference between a job board and a job aggregator?

A job board hosts vacancies on its own domain; Careerjet is an aggregator — it indexes ads from employers and other sites and links out to apply. That is why every row here carries publisherName / publisherUrl (the origin site) and applyUrl (the outbound apply link).

SEO Keywords

careerjet api, careerjet scraper, job aggregator api, job listings data feed, job postings api, scrape job listings, job posting aggregation, job market research, hiring trend analysis, track competitor hiring, job board monitoring, job feed syndication, recruitment data, salary benchmarking, job board backfill, indeed api, linkedin jobs scraper, jobspy, job search engines, indeed alternative, ats job feed, structured job data, job data api, european job market data

For AI Agents & LLM Apps

Purpose: return structured Careerjet job postings (title, company, location, parsed salary, dates, description, apply URL, publisher) from one or more of 23 verified country portals.

Minimal working input:

{ "keywords": "software engineer", "maxItems": 30 }

Variant — pinned portals with full details:

{
"keywords": "nurse",
"countryDomains": ["www.careerjet.fr", "www.careerjet.es"],
"includeJobDetails": true,
"maxItems": 10
}

Output fields: adId, countryCode, domain, url, title, company, companyUrl, location, locations, salary, salaryMin, salaryMax, salaryCurrency, salaryPeriod, datePostedLabel, datePosted, description, descriptionHtml, listingExcerpt, employmentType, badges, applyUrl, publisherName, publisherUrl, query, queryLocation, source, scrapedAt.

Behaviors an agent should know:

  • If startUrls is set, keywords, location and countryDomains are ignored.
  • maxItems is the only row-shaped input; leaves unset → default 100 rows (billed). Careerjet yields 5 rows per portal per search, so the Actor plans ceil(maxItems / 5) portals — the practical ceiling is 115 rows across the 23 verified portals.
  • Careerjet's US/UK/DE/IE/AU/IN/be/dk/za/sg/nz/ae/ly portals are always gated and return 0 rows; they are omitted from countryDomains.
  • includeJobDetails: true (default) adds billed detail-page requests and enables description, descriptionHtml and applyUrl. Gated job-ad pages ship card-only rows instead — the run names the affected hosts and does not fail.
  • The RESIDENTIAL proxy is effectively required; datacenter IPs are always challenged (0 rows). The run pins one sticky session and rotates only on a challenge.

Billing: pay-per-event — result $0.0035 per result (DIAMOND $0.0033) plus Actor Start $0.00005 per run.

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Careerjet. It reads only publicly available Careerjet pages over HTTP (no login bypass, no CAPTCHA solving, no browser) and does not access any authenticated or private surface. Users are responsible for complying with Careerjet's Terms of Service, its robots.txt, and applicable data-protection law (e.g. GDPR for EU/UK job data) when using the extracted postings. The dataset contains employer names, job postings and outbound apply links; do not use it for unsolicited commercial outreach in violation of applicable law.