Jora.com – Job Listings, Salaries & Full Descriptions
Pricing
from $1.00 / 1,000 dataset items
Jora.com – Job Listings, Salaries & Full Descriptions
Collect Jora.com job listings by keyword, filters, or URLs across supported countries. Returns full descriptions, salary, work type, company, location, and connector export.
Pricing
from $1.00 / 1,000 dataset items
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
9 days ago
Last modified
Categories
Share
Jora Jobs Scraper
The Jora Jobs Scraper collects current job listings from Jora across Australia, New Zealand, Singapore, Hong Kong, Malaysia, Indonesia, the United States, the United Kingdom, and Canada. It supports keyword/location search mode and URL mode for existing Jora search pages or job detail pages. Detail mode adds the full description, apply redirect, source name, salary, work type, and work arrangement when available.
Why This Scraper?
- Search by keywords and location across all supported Jora country sites.
- Start from Jora search URLs or direct job URLs when you already have a curated source list.
- Includes Jora filters for listed date, job type, quick apply, sort, distance, and minimum salary.
- Uses
maxItemsas the main output cap;maxPagesis unlimited by default, walking every result page for a search. - Detail mode adds full job descriptions and apply URLs.
- Daily/recurring change monitoring: turn on Incremental mode to get only NEW, UPDATED, and REAPPEARED jobs on every scheduled run, instead of the same full list again.
- Optional MCP connector export sends a concise job summary into your selected apps while the complete record stays in the Apify dataset.
Data You Get
Sample shape, values are illustrative placeholders, not from a live listing.
| Field | Example |
|---|---|
id | 00000000000000000000000000000001 |
jobId | 00000000000000000000000000000001 |
title | Sample Software Engineer |
company | Sample Company |
location | Sydney NSW |
countryCode | au |
url | https://au.jora.com/job/Sample-Job-00000000000000000000000000000001 |
sourceUrl | https://au.jora.com/j?q=software+engineer&l=Sydney%2C+NSW |
salary | $100,000 - $120,000 a year |
salaryMin | 100000 |
salaryMax | 120000 |
workType | Full time |
workArrangement | Hybrid |
postedAtText | Posted 3d ago |
quickApply | true |
isSponsored | false |
rank | 1 |
page | 1 |
abstract | Short summary from the search card. |
snippetBullets | ["Build sample services", "Work with a sample team"] |
descriptionText | Full job description appears here when fetchDetails=true. |
descriptionHtml | <div>Full job description appears here.</div> |
applyUrl | https://au.jora.com/job/rd/00000000000000000000000000000001 |
sourceName | Sample Source |
searchKeywords | software engineer |
searchLocation | Sydney, NSW |
searchTotalCount | 250 |
detailFetched | true |
scrapedAt | 2026-01-01T00:00:00.000Z |
changeType | NEW (incremental mode only — see "Recurring updates" below) |
changedFields | ["salary"] (incremental mode, UPDATED rows only) |
firstSeenAt | 2026-01-01T00:00:00.000Z (incremental mode only) |
lastSeenAt | 2026-01-02T00:00:00.000Z (incremental mode only) |
How to Use
Search by keyword and location:
{"mode": "search","searches": [{"keywords": "software engineer","location": "Sydney, NSW","country": "au"}],"maxItems": 20}
Search with filters:
{"mode": "search","searches": [{"keywords": "developer","location": "Melbourne VIC","country": "au"}],"postedWithin": "7d","workType": "contract","quickApply": true,"sort": "date","salaryMin": 90000,"maxItems": 25,"fetchDetails": true}
Run several searches in one run:
{"mode": "search","searches": [{ "keywords": "data analyst", "location": "Auckland", "country": "nz" },{ "keywords": "data analyst", "location": "Singapore", "country": "sg" }],"maxItems": 40}
Start from URLs:
{"mode": "url","urls": ["https://au.jora.com/j?q=software+engineer&l=Sydney%2C+NSW","https://au.jora.com/job/Sample-Job-00000000000000000000000000000001"],"maxItems": 20}
Send results into your apps:
{"mode": "search","searches": [{ "keywords": "marketing manager", "location": "Sydney", "country": "au" }],"mcpConnectors": ["your-connector-id"],"notionParentPageUrl": "https://www.notion.so/sample-parent-page","maxNotifyListings": 10}
The connector export writes a condensed, human-readable summary for each selected job: title, company, location, salary, work type, posted text, and links. The complete JSON record is always kept in the Apify dataset.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | search | Choose search for keyword/filter searches or url for existing Jora URLs. |
searches | array | software engineer in Sydney | Search mode inputs. Each item can include keywords, location, and country. |
postedWithin | string | anytime | Date filter: anytime, 24h, 7d, 14d, or 30d. |
workType | string | any | Job type filter such as full_time, part_time, contract, permanent, or internship. |
quickApply | boolean | false | Limits results to Jora quick apply jobs. |
sort | string | relevance | Use relevance or date. |
distanceKm | integer | empty | Optional location radius. |
salaryMin | integer | empty | Optional minimum salary filter. |
urls | array | sample search URL | URL mode inputs. Accepts search result URLs and job detail URLs. |
fetchDetails | boolean | true | Opens job pages for full details. |
maxItems | integer | 20 | Maximum matching rows to save. 0 means unlimited. Results can be fewer when the source has fewer matching jobs. |
maxPages | integer | empty | Maximum search pages per source. Leave empty to walk every result page for that search until Jora has no next page; maxItems remains the main cap. |
resumeFromRunId | string | empty | A previous run ID or dataset ID to continue a full-catalogue walk across separate runs. Jobs already collected there (matched by jobId) are skipped, so this run only saves the new ones. |
incrementalMode | boolean | false | Daily/recurring monitoring of this same search. The first run returns everything as NEW; later runs return only NEW, UPDATED, and REAPPEARED rows by default. See "Recurring updates" below. |
stateKey | string | empty | Optional name for a monitoring campaign, so its incremental state stays stable or is deliberately shared. Derived automatically from your search scope and fetchDetails setting when left empty. |
emitUnchanged | boolean | false | Incremental mode only. Also return jobs unchanged since the last run, marked UNCHANGED. Adds — and bills for — extra rows you already have. |
emitExpired | boolean | false | Incremental mode only. Also return jobs from a previous run that are no longer found, marked EXPIRED, once a run has covered the whole tracked search (not capped by maxItems/maxPages, not a resume). Adds — and bills for — extra rows. |
proxy | object | Residential AU | Connection settings. Residential AU is selected by default. |
mcpConnectors | array | empty | Optional MCP connector ids for app export. |
notionParentPageUrl | string | empty | Required only for Notion page export. |
maxNotifyListings | integer | 50 | Maximum jobs sent to each connector. Does not affect the dataset. |
Resuming a full-catalogue walk
For an unbounded pull (maxPages empty, maxItems: 0), two things protect a long run:
resumeFromRunIdlets you continue in a brand-new run: paste the ID of a previous run (or its dataset), and this run skips everyjobIdalready saved there, appending only new jobs.- A checkpoint is saved automatically as the run progresses. If the run is interrupted by an Apify platform migration or you click Resurrect on a failed run, it picks back up from where it left off in the same run, without re-saving (or re-charging for) jobs it already collected. No input is needed for this; it's automatic.
Recurring updates (incremental mode)
Resuming and incremental monitoring are two different things — pick the one that matches what you are doing:
| Need | Use |
|---|---|
| One long pull stopped and should continue | resumeFromRunId / the automatic checkpoint |
| Run the same search every day and receive only what changed | incrementalMode |
| Keep separate daily campaigns for similar searches | distinct stateKey values |
| Run a normal full snapshot | leave both off |
Incremental mode (incrementalMode) is meant for a schedule. The actor remembers the previous run of the same search by itself, so there is no run ID to paste. The first run returns every matching job as NEW. Later runs return only NEW, UPDATED, and REAPPEARED jobs — everything unchanged since last time is suppressed and not billed. UPDATED rows carry changedFields listing exactly which fields moved, and every row carries firstSeenAt and lastSeenAt so you can tell a long-running listing from a fresh one.
Turn on emitUnchanged or emitExpired only when you also want those rows back — they are returned and billed for, so leave them off unless you specifically need a full snapshot every run or explicit expiry tracking. emitExpired additionally holds back its rows on any run that did not cover the whole tracked search (capped by maxItems/maxPages, or resumed), so a short run never reports jobs as gone when they simply were not reached.
State is isolated automatically: each distinct search scope — mode, searches/urls, and the filters — gets its own state, and so does each fetchDetails setting, so a detail run and a card-only run of the same search never compare against each other. Set stateKey to give a campaign a stable name of your own, or to deliberately point two differently-configured runs at the same state.
Scheduled-run example — the same search, run daily:
{"mode": "search","searches": [{ "keywords": "software engineer", "location": "Sydney, NSW", "country": "au" }],"incrementalMode": true,"stateKey": "sydney-swe-daily","maxItems": 100}
Day 1 returns every job with "changeType": "NEW". From day 2 on, the identical input returns brand-new postings as NEW, jobs whose salary/title/description changed as UPDATED with changedFields naming them, jobs that were missing and came back as REAPPEARED — and nothing else.
What does not count as a change. Six fields are deliberately left out of change detection, because measurement across repeated runs of the identical search showed they move on their own while the job itself is untouched: url and applyUrl (they carry tracking parameters that differ per request), postedAtText (a relative age that drifts by itself, 4d ago → 9d ago), rank and searchTotalCount (a position and a total-match count belong to the search, not to the job), and scrapedAt (a per-run timestamp). When only these move, the job is not reported as UPDATED. All six are still returned on every row exactly as before — only change detection ignores them.
Output Example
Sample shape, values are illustrative placeholders, not from a live listing.
{"id": "00000000000000000000000000000001","jobId": "00000000000000000000000000000001","title": "Sample Software Engineer","company": "Sample Company","location": "Sydney NSW","countryCode": "au","url": "https://au.jora.com/job/Sample-Job-00000000000000000000000000000001","sourceUrl": "https://au.jora.com/j?q=software+engineer&l=Sydney%2C+NSW","salary": "$100,000 - $120,000 a year","salaryMin": 100000,"salaryMax": 120000,"workType": "Full time","workArrangement": "Hybrid","postedAtText": "Posted 3d ago","quickApply": true,"isSponsored": false,"rank": 1,"page": 1,"abstract": "Short summary from the search card.","snippetBullets": ["Build sample services", "Work with a sample team"],"descriptionHtml": "<div>Full job description appears here.</div>","descriptionText": "Full job description appears here when fetchDetails=true.","applyUrl": "https://au.jora.com/job/rd/00000000000000000000000000000001","sourceName": "Sample Source","searchKeywords": "software engineer","searchLocation": "Sydney, NSW","searchTotalCount": 250,"detailFetched": true,"scrapedAt": "2026-01-01T00:00:00.000Z"}
Plan Requirement
Residential AU is selected by default because Jora can return empty responses from cloud datacenter connections. For searches outside Australia, choose the closest Residential country supported by your Apify plan. Detail mode uses the detail-enrichment charge event in addition to the built-in dataset item event.