SEEK, JobStreet & JobsDB Job Scraper — 8 Markets
Pricing
from $0.50 / 1,000 results
SEEK, JobStreet & JobsDB Job Scraper — 8 Markets
Scrape public job listings from SEEK, JobStreet and JobsDB across 8 APAC markets, one market per run. Export titles, companies, locations and salary fields to JSON, CSV or Excel. Add optional company data and inspect search coverage in RUN_SUMMARY.
Pricing
from $0.50 / 1,000 results
Rating
5.0
(1)
Developer
BlueData
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
SEEK, JobStreet & JobsDB Job Scraper — 8 Markets
Search public job listings across eight SEEK, JobStreet, and JobsDB markets with one consistent dataset. Filter by keywords, location, salary, and category; optionally add company context, descriptions, and application details. Results include source links and market/currency labels to support hiring research and cross-market comparison.
Start with a small search in one market. Optional data groups are off unless selected, and requested groups report observed availability. Field coverage varies by listing and market; results are not guaranteed to include every job or every selected field.
Choose a workflow
- Regional hiring research: use the same fields across SEEK, JobStreet, and JobsDB, while keeping currency and market labels explicit.
- Company context: select company profiles, aggregate reviews, work context, and application information without enabling every optional group.
- Advanced/experimental change tracking: incremental runs may flag new and changed jobs. They are not a guaranteed monitoring or delivery service.
- AI and automation: choose compact output and inspect run status before treating results as complete.
Salary bands remain in source currencies; the Actor does not convert currencies or infer missing pay. Applicant counts and login-only insights are not supported.
What this Actor does
This actor extracts structured job data from all eight SEEK markets — Australia and New Zealand (SEEK), Singapore, Malaysia, Indonesia, and the Philippines (JobStreet), Hong Kong and Thailand (JobsDB) — including structured salary (min/max/currency/period), real posting datetimes, work types and arrangements, categories, and source links. It supports keyword search, category filters, location and salary post-filters, and controllable result limits, so you can run the same query consistently. Opt-in detail enrichment adds full descriptions, apply links, company pages, classification IDs, and other supported fields; incremental mode can flag changes between runs. These are public-source observations, not proof that a job is still accepting applications or that an employer has officially closed it.
Key features
- 🌏 Eight-market coverage — one input shape across AU, NZ, SG, MY, HK, TH, ID, and PH, with market-aware currency and locale handling.
- 📦 Normalized output — consistent fields, source links, and run status make results easy to use in applications and Agent workflows.
- 💰 Structured salary —
salaryMin/salaryMax/salaryCurrency/salaryPeriodwhen provided by the source (THB, SGD, AUD, NZD, MYR, HKD, IDR, PHP), plus aplaceholderstatus for implausibly low ranges such as monthly "1 - 2 THB". These are parsing heuristics, not evidence of employer intent. - 📅 Real posting dates —
postedDate/postedDaysAgofrom the true UTC timestamp, not a parsed "2 days ago" label. - 🎯 Category filter —
categoryIdsnarrows results using source classification data. IDs can be read from enriched records. - 📋 Detail enrichment — toggle
enrichDetails: truefor the full description (plain text), apply link, company page, and classification IDs. - ♻️ Incremental mode — recurring runs flag
isNew/isUpdatedper record from cross-run state. First run builds the baseline; later runs highlight the diff. - 🛡️ Output validation —
contractCheck: truechecks expected fields for scheduled monitoring. - 📦 Compact mode — smaller payloads for AI-agent and MCP workflows.
Public contact fields are sensitive and remain off by default; enable them only when needed, and separately allow them in notifications. Data that requires a logged-in session, including applicant insights, is not accessed and is rejected if requested. Activity counts describe listing activity and are not applicant counts. Descriptions and company text use best-effort PII redaction; this is not a guarantee of anonymization.
What data can you extract?
Each result includes core listing fields (jobId, title, company,
canonicalUrl, location, market, source, sourceCountry), structured
salary (salaryText, salaryMin, salaryMax, salaryCurrency,
salaryPeriod, salaryParseStatus), work context (workType,
workArrangement, categories, teaser), posting data (postedAt,
postedDaysAgo, postedDate, fetchedAt), relevance (queryTermsMatched,
relevanceScore), provenance (searchQuery, searchUrl), and — when detail
enrichment is on — description, applyUrl, companySearchUrl,
classificationIds, subClassificationIds. Optional data groups can add
listing metadata, work and location context, classifications, company profile
and review summaries, public media, application details, public contacts,
listing activity, and source references. Groups are off by default; fields are
omitted when the source does not provide them, with availability reported in
optionalDataStatus. Incremental runs add isNew / isUpdated.
Important interpretation limits
- Visibility is not availability. Current Actor metadata (
isPublic) controls deployment visibility; the README cannot override it. Public accessibility of a source listing is a separate concept and does not confirm application access or an open vacancy. - A posting date is not an open/closed decision.
postedDateandpostedAtdescribe when the source reported the listing. The Actor does not guarantee that the employer is still accepting applications, and a reliable closing date is not generally available. - Verify links before acting. Treat
canonicalUrlas the source citation andapplyUrlas a candidate application/share link. Re-check both at use time; a link can redirect, expire, require a login, or no longer represent an active vacancy. - Read salary status, not numbers alone.
salaryParseStatus: suspiciousnulls questionable numeric bounds while preserving readablesalaryText. ChecksalaryWarnings; these are heuristics, not proof of fraud or pay accuracy.structuredmeans parseable, not verified by an employer. isExpiredis a search observation. It means a previously seen listing was absent from a later eligible/full search under the incremental scope. It does not mean the employer officially closed the vacancy. It can reflect source changes, filters, or temporary absence; inspectRUN_SUMMARYbefore acting on it.
Input
The main inputs are search keywords, a market code, and a result limit.
Key parameters:
- 🔍 Search:
query,market(defaultTH, dropdown, 8 markets),location,startUrls,preset(Basic / Company context / Full optional data),sortMode, andmaxResults(accepted output limit; 0 removes the requested output cap subject to safety limits unlessexportExcelis enabled. Check run status for partial coverage). - 🧩 Flexible API input:
queryandlocationaccept comma-separated text, JSON-string arrays, or native string arrays. Direct API callers may also use{"terms":["software engineer","data analyst"]}forquery.startUrlsaccepts either URL strings or{ "url": "..." }objects. If bothqueryandstartUrlsare empty, the legacy default query isAI Engineer; an emptyquerywithstartUrlsuses the URL targets without adding that default. - 📊 Custom XLSX: set
exportExcel: truefor a stateless run withmaxResultsfrom 1 through 1000. The requested workbook is available at the enabled-onlyJOBS.xlsxoutput link after a successful collection. - 🎯 Filters:
salaryMin/salaryMax(market home currency, overlap),classificationtext,categoryIds. - 🎯 Post filters:
includeKeywords/excludeKeywords,keywordMatch*field toggles,fromDate/toDate/maxAgeMinutes,customFilters(field/op/value engine). - 📄 Enrichment: choose
presetfirst. Basic is fastest; Company context enables selected detail groups; Full optional data enables supported public groups except contacts/login-only data. Advanced users may still provideenrichDetails,descriptionMaxLength, oradditionalDataexplicitly. - 🧩 Optional data (
additionalData.<group>):listingMetadata,workContext,locationDetails,classifications,companyProfile,companyReviews,jobMedia,applicationInfo,publicContacts,sourceActivity,sourceReferences,searchInsights, andapplicantInsights. Applicant insights are not available for public searches. Contact fields are sensitive and are sent in notifications only when explicitly allowlisted withnotificationDataGroups. - 🤖 AI output:
compact,excludeEmptyFields,contractCheck. - ♻️ Incremental:
incremental,stateStoreName,stateKey,emitUnchanged,emitExpired,skipReposts(addsisNew/isUpdated/isExpired/isRepostflags). - 🔔 Notifications:
webhookUrl/webhookHeaders,discordWebhookUrl,notifyOnlyChanges,notificationLimit,includeRunSummary.
Stateless quick start
Start with this small Basic search, which requests up to five software-engineer
listings in Singapore. Standard market input selects one market per run; it
does not automatically fan out across all eight markets. Advanced startUrls
can select supported hosts and add URL-based searches.
{"query": "software engineer","market": "SG","preset": "basic","maxResults": 5}
Optional data groups are off unless selected; public contacts and applicant insights remain off in both examples.
Guidance for AI agents
When choosing inputs programmatically, select exactly one preset unless the
user explicitly asks for custom fields:
basic: default choice for fast search; no detail enrichment.company: use when the user asks for company, work-context, or application context; it enables the selected public detail groups.full: use only when the user asks for the deepest available public data; it enables supported public groups but never login-only applicant insights or public contacts by default.
Keep market to the user's requested market, set maxResults to the requested
bounded count, and use compact: true for agent-oriented output unless the user
needs full teaser text. Do not send detailConcurrency; it is managed by the
Actor. Do not claim completeness from sourceStatus: partial or coverage_limited, or treat
not_provided, restricted, failed, and skipped_budget as equivalent. Read
RUN_SUMMARY and optionalDataStatus before summarizing results. The standard
input searches one market per run; do not silently fan out across all eight.
Preset reference
Presets add enforced defaults; additionalData may add more groups but a
preset's groups cannot be turned off with false. Choose preset: "basic" when
no enrichment is requested. It leaves enrichDetails off and enables no optional
groups. preset: "company" enables exactly workContext, companyProfile, and
applicationInfo; it is intended for company/work/application context and does
not enable every optional group. Choose Basic instead of Company when those
groups must stay off. preset: "full" enables enrichDetails by default plus
these public groups:
listingMetadata, workContext, locationDetails, classifications,
companyProfile, companyReviews, jobMedia, applicationInfo,
sourceActivity, sourceReferences, and searchInsights. Neither preset
turns on publicContacts or applicantInsights; applicant insights are not
available for public searches. Use explicit additionalData or
enrichDetails only when the preset choices do not match the user's request.
If a caller explicitly sends enrichDetails: false with Full, the optional
preset groups still run but legacy description/apply-link enrichment is disabled.
Preset values are lowercase basic, company, or full.
Input formats and location handling
Market selection does not automatically translate Malay or Indonesian query phrases into English. Submit the exact search terms you want sent to the source. Location names are not translated arbitrarily. The Actor retains the original location and reports the effective source location used; location filtering is not a guarantee of complete geographic coverage.
The saved INPUT preserves the original input, RUN_SUMMARY.locations reports
canonical values, and RUN_SUMMARY.inputNotes records normalization. Each
searchPlan entry and processed searches entry exposes originalLocation (the
value you sent) and effectiveLocation (the source label actually used); for
example originalLocation: "香港" and effectiveLocation: "Hong Kong". A location
filter is a post-filter, not a guarantee of complete geographic coverage. If the source stops before full coverage, read
sourceStatus, searches[].stopReason, searches[].filteredOut, and
searches[].coverageComplete before concluding that no jobs exist. Hit the
output cap and hitting a fetch-window cap are reported separately through
resultLimitReached and coverageLimitReached.
Accepted API examples:
{"query": ["software engineer", "data analyst"],"market": "TH","location": "Bangkok","startUrls": ["https://th.jobsdb.com/th/software-engineer-jobs"],"maxResults": 10,"preset": "basic"}
{"query": {"terms": ["software engineer", "data analyst"]},"market": "TH","startUrls": [{"url": "https://th.jobsdb.com/th/software-engineer-jobs"}]}
If RUN_SUMMARY.sourceStatus is coverage_limited, inspect
coverageLimitedSearches, searches[].coverageLimit, and filteredBy. The
result is not a full-market result and is not proof that the source has no other
matching jobs. coverageLimitReached: true means the fetch window ended before
the source was exhausted; resultLimitReached answers the different question
of whether the requested maxResults output cap was met. A run can show
resultCount below maxResults with resultLimitReached: false because the
coverage window was capped or because filters rejected the remaining candidates;
filteredBy and coverageLimit distinguish those causes.
Query matching and language handling
Eight markets does not mean every query language is translated or understood. Queries are not automatically translated; submit the exact phrase you want searched. Supported query matching is literal evidence, not semantic search or a language translation service.
Choose queryMatchMode:
source(default): preserves source ranking when choosing candidates, but only records with complete target-specific literal evidence are emitted. Zero-evidence suggestions are filtered before output and never appear withrelevanceScore: 0.- Non-Latin queries require literal evidence in the selected fields. Thai in TH
and Chinese in HK are supported as exact text: the original query is sent
unchanged, with no translation or added synonyms. Complete coverage with no
literal match returns
no_resultsandlanguageSupport: supported; incomplete coverage returnscoverage_limitedandlanguageSupport: unknown. - For the SG source, an Arabic- or Korean-script query whose first result page
contains candidates but no literal query match is terminally marked
unsupported_languageinstead of paging through generic fallback results. Literal matches on that page remain eligible. This terminal outcome counts as completed, but not fully covered; it does not settruncated. all_terms: requires every normalized query token across the selected fields. ASCII tokens use word boundaries (engineerdoes not matchengineering); other scripts use literal matching without a linguistic word segmenter.phrase: requires the contiguous query phrase in a selected field.
The default strict-query fields are title, teaser and actual description.
keywordMatch* selects a narrower field set. With no explicit include/exclude
keywords, selecting fields also enables all-token query validation, so
keywordMatchTitle: true with junior software engineer rejects a title that
only says Software Developer. With explicit include/exclude keywords the old
keyword-only scope is preserved; set queryMatchMode: all_terms to enforce both.
Description-based query validation waits for requested enrichDetails and uses
real description text, not teaser text mislabeled as description.
matchedTerms and matchedFields are literal evidence, not a semantic score.
Every emitted relevanceScore is 1 for this search target, meaning all
required token/phrase evidence was found in the original or normalized query.
queryTermsMatched names the validated target query, not an incidental match to
a different query in the batch. This is never a confidence probability. Strict
checks can reject relevant synonyms and do not guarantee semantic accuracy.
An empty complete Thai/Chinese exact query is no_results; a known unsupported
language/source combination is unsupported_language. Configured page/scan or
candidate caps return coverage_limited, not partial, and keep
truncated: true plus coverageLimit so consumers know the source was not
fully covered.
{"query": "junior software engineer","market": "TH","location": "Bangkok","queryMatchMode": "all_terms","keywordMatchTitle": true,"maxResults": 10,"preset": "basic"}
Search URLs
startUrls is optional and additive to explicitly supplied keyword searches. It accepts an array of
HTTPS search/category URL strings or objects such as
{"url":"https://th.jobsdb.com/th/developer-jobs"}. URLs must use one of the
8 supported SEEK/JobStreet/JobsDB hosts, must be search/category pages (not a
homepage or detail page), and support at most 20 entries. A URL's host selects
the market for that target; when a URL is supplied without a query, the search
term is derived from its URL slug. If both query and startUrls are supplied,
both sets of searches run and duplicate normalized URLs are merged. A URL-only
input does not receive a hidden schema-default keyword. RUN_SUMMARY.searchPlan
exposes each target URL and inputSource (query, startUrl, or a merged value)
so default-query and URL-duplication cases are distinguishable. market
still controls generated keyword searches and remains a useful explicit default.
Example:
{"query": "developer","market": "TH","startUrls": [{"url":"https://th.jobsdb.com/th/developer-jobs"}],"preset": "basic","maxResults": 25}
Filters and field semantics
classificationmatches text in source category labels;categoryIdsmatches source classification IDs and is not a salary or internal database ID. Read classification fields from an enriched sample before reusing an ID.includeKeywordsrequires every term to match;excludeKeywordsrejects a record when any term matches. With nokeywordMatch*toggle, matching uses the legacy set of title, company, location, work type, teaser, category, and description. Selecting one or morekeywordMatchTitle,keywordMatchCompany,keywordMatchLocation,keywordMatchCategory, orkeywordMatchDescriptionrestricts matching to those fields.customFiltersis a JSON array of{field, op, value}objects. Supported operators areincludes,notIncludes,equals,notEquals,gt,gte,lt, andlte. Example:[ {"field":"salaryMin","op":"gte","value":50000} ]. A filter on an optional group requires that group inadditionalData; a description/apply/classification detail filter requiresenrichDetailsor the corresponding optional group.
Filter order and missing values
The Actor maps and validates source listings first, then applies location,
keyword, salary, date, classification, and any non-detail customFilters before
accepting a candidate. Accepted candidates are deduplicated by job ID and
fetched for requested detail groups. Filters that need detail fields (for
example description or an optional company field) run after enrichment. When
incremental/repost logic is enabled, change flags are computed after the final
record is assembled; formatting such as compact happens last. maxResults
counts final accepted output records, so deferred filters may inspect more source
candidates or detail records than the output count.
Include/exclude keyword matching is case-insensitive substring matching; unlike
strict query checks, it has no token boundaries, stemming, or language-aware
segmentation. Missing keyword fields behave as empty text. If a
salary threshold is set, records with no structured salary are excluded; records
in a different currency are kept rather than incorrectly converted. Records with
no parseable posting date are kept by date filters. A missing custom-filter field
fails positive operators (includes, equals, numeric comparisons) and passes
negative operators (notIncludes, notEquals). Multiple custom filters are
ANDed together; multiple include terms are ANDed and exclude terms are ORed.
Salary plausibility
salaryParseStatus is structured, placeholder, suspicious, or
not_provided. Suspicious heuristics cover implausible lower bounds crossing a
known currency/period floor, ranges of at least 100:1, and multiple numeric bands
in one display label. Example: AUD 1–500,000/year is not treated as a trustworthy
structured range: numeric bounds become null and readable text remains.
Salary thresholds exclude such null-bound records. salaryWarnings explains
flags; foreign_currency alone keeps a structured range because legitimate
foreign-currency offers exist. No automatic currency conversion is performed.
Multi-query execution and the global result cap
maxResults is a run-wide output cap, not a per-query output quota and not
a guarantee that the source scan reaches every listing. The Actor fetches a
candidate window sized for scanning (at least 100 listings per source page for
bounded runs), because market filters can reject most candidates after fetching.
For a multi-query or multi-URL plan, a best-effort run divides the source
candidate allowance across targets so every planned target gets an execution
opportunity before the final output cap is applied. A fill_target run may
intentionally skip later targets once the run-wide output target is met. The
Actor never emits more than maxResults;
source request/time budgets, challenges, interruptions, and source scan/page caps
can leave searches incomplete. Detail request limits are reported separately.
coverageMode selects how hard the run tries to reach maxResults:
best_effort(default): the bounded scan that stops at the standard safety limits. UseRUN_SUMMARYcoverage facts to see whether the target was met.fill_target: keeps scanning and enriching candidates untilmaxResultsmatched jobs are emitted, the source is exhausted, or a hard run limit (global candidate cap, page cap, request budget, or time budget) is reached. The page and detail-candidate safety windows are widened for that run; the hard caps and the run time budget still apply. Once the run-wide target is met, remaining planned targets are skipped withstopReason: max_results. Pricing is unchanged: only emitted dataset items and the start event are charged, and rejected candidates are not charged.
RUN_SUMMARY exposes:
plannedSearches: distinct targets after URL/alias deduplication.attemptedSearches: targets whose source attempt started, including prefetches whose results were subsequently discarded. Retries do not inflate this count.processedSearches: targets executed in this run, excluding skipped, discarded, and checkpoint-resumed targets.completedSearches: target outcomes that reached a terminal result in this run, includingcoverage_limitedand intentionalmaxResultscaps. It excludes source request/time/challenge failures and failed attempts.fullyCoveredSearches: processed targets for which the source reported complete pagination. A cap-limited search can be processed and completed while remaining not fully covered.coverageLimitedSearches: processed targets stopped by an explicit source page/candidate cap; inspect theircoverageLimitfor the configured window.- Run-level
resultLimitReached: final accepted output reached the requestedmaxResultscap.coverageLimitReached: a source page/candidate window cap cut collection short. They are independent. LegacylimitReachedremains a broader cap signal; use the explicit flags to distinguish output limits from incomplete source coverage. Per-search flags report whether that target itself stopped at either limit. Final run-wide trimming can set the run-level output flag while a fully scanned search hasstopReason: nulland per-searchresultLimitReached: false. sourceStatusandsearches[].statusdescribe source search only.detailStatusdescribes enrichment separately; a detail-request budget (maxDetailRequests) or detail failure does not make a completed source searchpartialor truncated. The separate detail-candidate coverage cap is a source coverage limit and can make the run coverage-limited.detailsEnrichedcounts valid detail responses per candidate listing, not final dataset rows. It can exceedresultCountwhen candidates are filtered after enrichment.detailsFailedcounts unsuccessful detail responses.coverageMode,requestedResults,targetReached, andshortfallstate how close the run came to themaxResultstarget;candidatesScannedandcandidatesRejectedshow the work done; run-levelstopReasonexplains why the run stopped (target_reached,candidate_limit,time_limit,request_limit,interrupted,challenge,source_exhausted,early_stop).resultNoticeis a short human-readable note when the target was not met; aTARGET_NOT_REACHEDwarning is added only forfill_targetruns with a shortfall.incrementalStateStatusisready,run_scoped,unavailable, ornot_requested. State-load failure suppressesisNew/isUpdatedrather than claiming every result is new; check the warningINCREMENTAL_STATE_UNAVAILABLE.baselineCompleteandexpiredRecordsReliableare reported for incremental runs. An incomplete coverage window makes the baseline partial: expiration markers are suppressed,expiredRecordsstays0, and theBASELINE_INCOMPLETEwarning explains why.searches[].coverageLimitidentifies the page/candidate safety cap and configured limit when source coverage was cut short.skippedSearches/discardedSearches: never attempted versus attempted but not processed;resumedTargetsidentifies work already completed in a checkpoint.allSearchesProcessed: every planned target was processed, checkpoint-resumed, or intentionally skipped because a fill_target run had already met its output target.searchPlan: each target's URL, original/normalized query, market,originalLocation/effectiveLocation,inputSource(query,startUrl, or a merged/duplicate value),attempted,executionStatus(processed,skipped,discarded,resumed) and reason such asmax_results,request_limit,time_limit,circuit_breaker,unsupported_language,interrupted, oralready_completed.
Reaching the output cap does not by itself skip later planned targets. A target
that reaches its fair source quota can have stopReason: max_results while the
batch remains sourceStatus: ok; fullyCoveredSearches stays lower than the
completed count because the source was intentionally bounded. Explicit page,
global-candidate, and detail-dependent candidate caps use
sourceStatus: coverage_limited, COVERAGE_LIMIT_REACHED, and
truncated: true; this describes incomplete source coverage, not an Actor
failure. Request/time/challenge or mapping failures remain partial or a
stronger failure status. Pure enrichment failures are reported in detailStatus
without downgrading an otherwise completed source search.
Run summary reference
RUN_SUMMARY is available at /records/RUN_SUMMARY. Treat it as part of the
result, not as an internal log. A representative successful or partial summary
contains fields such as:
{"resultCount": 20,"detailsEnriched": 20,"detailsFailed": 0,"sourceStatus": "ok","limitReached": true,"resultLimitReached": true,"coverageLimitReached": false,"truncated": false,"optionalDataStatus": {"companyProfile": {"status": "available", "available": 20}},"requestBudget": {"source": {"limit": 50, "consumed": 21, "remaining": 29},"detail": {"limit": 20, "consumed": 20, "remaining": 0}}}
The example is illustrative: counts and optional groups vary by input. Check
sourceStatus, relevanceStatus, matched/unscored counts, searchPlan,
resultCount, detailsFailed, truncated, stop/coverage fields, and each
requested group's status before reporting success. Optional data can be
missing for a legitimate listing, restricted, skipped by budget, or failed to
load; these cases are not interchangeable.
For a retry, first distinguish partial/timeout/request_limit/challenge
from a completed ok run. coverage_limited means the Actor ran but the source
window was capped; inspect coverageLimit before deciding whether to increase
work. Increase the run timeout or relevant process budget
only when the user permits more work; do not treat a second run as a guaranteed
continuation or as a deduplicated global result set. contractCheck: true checks
required record shape, not source completeness. An empty completed search does
not itself violate the record contract.
warning/warnings flag coverage caps, incomplete searches, unconfirmed literal relevance, and
salary review needs. searches[].filteredBy counts location, relevance, keywords,
salary, date, classification and custom rejections so a salary rejection is not
misdiagnosed as an unresolved location. failureStage/failureCode expose bounded
codes such as rate_limited, challenge_detected, coverage_limit_reached and
contract_failure, never raw source errors or credentials.
A platform SUCCEEDED run can contain sourceStatus: coverage_limited with zero
records: the Actor ran successfully, but the configured source window ended
before full coverage. The run log emits status/stage/code and warnings. Genuine
source or validation errors still fail with safe diagnostics. Changing query-validation mode resets
the incremental baseline; the updated scope fingerprint can also reset baselines
from older builds. Concurrent monitoring safety is still not guaranteed.
apify call bluedata/seek-jobstreet-jobsdb-scraper --input-file examples/basic-search.json --jsonapify call bluedata/seek-jobstreet-jobsdb-scraper --input-file examples/company-context.json --json
maxResults is an accepted-output limit. maxSourceRequests and
maxDetailRequests are process-only request controls (failed attempts and
retries consume them); none of these inputs is a money or price cap.
Detail fetch concurrency is managed automatically by the Actor and is not a
user-facing input. Review RUN_SUMMARY and sourceStatus before treating a run
as complete. Requested
optional groups can be available, not_provided, restricted, failed, or
skipped_budget; these statuses describe observed availability, not a
completeness guarantee.
Input examples
Choose your company enrichment — a small sample without enabling public
contacts or login-only data. Switch market to reuse this workflow elsewhere.
{"query": "software engineer","market": "SG","preset": "company","maxResults": 3,"additionalData": {"companyProfile": true,"workContext": true,"applicationInfo": true}}
Selected detail groups fetch listing details even when enrichDetails is false;
that switch separately controls legacy description/apply-link enrichment.
Inspect optionalDataStatus and RUN_SUMMARY before using the results.
Recommended Agent-first search — Singapore Senior Software Engineer jobs with compact output.
{"query": "Senior Software Engineer","market": "SG","preset": "basic","maxResults": 25,"compact": true,"contractCheck": true}
ADVANCED / EXPERIMENTAL recurring monitor — reuse the same state store and
key on every run. This is not the recommended quick start: concurrent monitor
state, persistence failures, and resume request budgets are not hardened, and
there is no production safety guarantee.
The named store is opened in Apify cloud storage and created on first use. If
state cannot be loaded or saved, check incrementalStateStatus and the
INCREMENTAL_STATE_UNAVAILABLE warning; records are not falsely marked isNew
when no baseline was loaded. Expiration markers are emitted only from a complete
baseline: a coverage-limited run reports baselineComplete: false and
expiredRecordsReliable: false, suppresses emitExpired output, and adds the
BASELINE_INCOMPLETE warning.
{"query": "Backend Engineer","market": "SG","maxResults": 50,"compact": true,"incremental": true,"stateStoreName": "my-private-hiring-state","stateKey": "sg-backend-daily","notifyOnlyChanges": true}
Basic keyword search — 25 Thailand developer jobs, no frills.
{"query": "developer","market": "TH","maxResults": 25}
Singapore with details — full descriptions and apply links included.
{"query": "software engineer","market": "SG","maxResults": 25,"enrichDetails": true,"additionalData": {"companyProfile": true,"companyReviews": true}}
Australia, software-only + incremental — category filter and change flags for a scheduled monitor.
{"query": "developer","market": "AU","maxResults": 100,"categoryIds": "6290","incremental": true,"stateStoreName": "my-private-hiring-state","stateKey": "au-developer-monitor"}
Output
Each run produces a dataset of structured job records, downloadable as JSON,
CSV, or the native Excel export from the Dataset tab in Apify Console, plus a
RUN_SUMMARY record with counts, per-search status, optional-data availability,
and source status. Canonical JSON is the representation for nested optional groups;
it preserves the null/empty-value shape. Native Dataset export behavior is
unchanged: its JSON, CSV, and native Excel renderings may flatten nested objects
and arrays into separate columns and may omit or reshape null and empty values;
it is not the custom workbook.
Optional custom XLSX
Set exportExcel to true on a stateless run (incremental must be false) and
set maxResults to 1–1000. After collection returns, the enabled-only output
link downloads the fixed JOBS.xlsx record from the default key-value store.
The run summary is at /records/RUN_SUMMARY; inspect excelExport.status,
rowCount, recordKey, and the source coverage fields before using the file.
A failed requested export is reported as failed and is not advertised as
available. A partial or coverage-limited source run may still provide a workbook
of its acknowledged rows, but its status does not claim complete source coverage.
The custom workbook keeps a readable Jobs sheet with field/part rows and a
Canonical sheet whose JSON chunks reconstruct the projected Dataset records
exactly, including nested values, nulls, empty values, and large integers. Long
text is split into UTF-16-safe cell parts. XML-invalid controls and lone
surrogates use reversible \u{HEX} display encodings, while canonical JSON is
ASCII encoded with underscore escaping to protect literal Excel escape
sequences. These encodings are workbook-specific; native Dataset exports remain
unchanged.
Use optionalDataStatus to distinguish available, not_provided, restricted,
failed, and skipped_budget; these values do not assert complete source coverage.
For operational decisions, also inspect salaryParseStatus, re-check
canonicalUrl/applyUrl, and do not interpret isExpired as an official
employer closure.
Example job record (illustrative)
{"source": "jobsdb","sourceCountry": "TH","market": "TH","jobId": "12345678","title": "Full Stack Developer","company": "Example Employer","canonicalUrl": "https://th.jobsdb.com/job/12345678","location": "Chiang Mai","salaryText": "40,000 – 50,000 THB per month","salaryMin": 40000,"salaryMax": 50000,"salaryCurrency": "THB","salaryPeriod": "month","salaryParseStatus": "structured","workType": "Full time","workArrangement": "Office","categories": ["Software"],"teaser": "Build and maintain web applications.","postedDaysAgo": 2,"postedDate": "2026-10-14","postedDateTime": "2026-10-14T00:00:00+00:00","queryTermsMatched": ["developer"],"relevanceScore": 1,"sourceStatus": "ok","searchQuery": "developer","searchUrl": "https://th.jobsdb.com/th/developer-jobs","fetchedAt": "2026-10-16T00:00:00+00:00"}
postedAt is intentionally omitted from this illustrative record: it is the
source's relative display label (for example, "2 days ago"), while
postedDate/postedDateTime are normalized UTC values. Do not parse postedAt
as an ISO timestamp. Neither field confirms that the vacancy is still open;
there is usually no reliable employer closing date.
Limits and short glossary
maxResults: accepted final output cap, default 20, hard ceiling 10,000, range 0–10,000.0removes the requested output cap; the Actor still applies run, page, and candidate safety limits, and a large scan may be required. It is not a spending limit. CustomJOBS.xlsxrequires 1–1,000.coverageMode:best_effort(default) orfill_target.fill_targetwidens the page and detail-candidate windows and scans untilmaxResultsis met or a hard run limit is reached, then reportstargetReached,shortfall, and a run-levelstopReason. It is still bounded by the global candidate cap, request budgets, and the run time budget; it is not a spending limit. WithmaxResults: 0,fill_targetis echoed but remains bounded likebest_effort; set a positivemaxResultsto enable target filling.maxSourceRequests: optional process-run budget for search/detail requests, range 0–20,000; failed attempts and retries consume it. Omitted preserves the legacy behavior.maxDetailRequests: optional process-run detail-request budget, range 0–1,000; explicit 0 disables detail requests. It is separate from output count.maxRetries: retries after failed source requests, default 2, range 0–10.- Detail concurrency: the number of detail requests the Actor may process in
parallel. It is automatically managed (currently default 8) and is not a
user-facing input; it is different from
maxDetailRequests, which is a total request budget. - Enrichment: fetching detail records after search results, such as full descriptions, application links, or optional company groups.
- Canonical JSON: the lossless nested record representation. Native Dataset
CSV/Excel may flatten or reshape it; custom
JOBS.xlsxincludes a Canonical reconstruction sheet. - Partial coverage: the run stopped before establishing complete source coverage. It is not a successful-complete status.
The Actor also enforces safety limits on source scanning and detail candidates; those limits can produce a truthful partial run and are not price guarantees.
Pricing and resource use
The current default configuration uses 256 MB memory. Current pay-per-event
pricing is $0.0005 per default-dataset item ($0.50 per 1,000 items) plus
$0.00005 per run-start event. A run that produces no dataset items still incurs
the start event. For example, 20 default-dataset items and one start event cost
$0.01005 USD before any other adjustments or tax. Expiration markers in the
default dataset are items too; pricing is not limited to newly found jobs, and
there is no separate enrichment event charge in the current configuration.
coverageMode: fill_target may scan and enrich more candidates, but the billed
events are unchanged: emitted dataset items and the run start; rejected
candidates are not charged.
Memory above 1 GB increases the number of start events. Consult the Actor's current pricing
tab as the authority for configured prices and usage. This example is not a
spend cap; result and request limits do not cap charges.
How to run it
- Open this actor in Apify Console.
- Enter search keywords, pick a market, and set
maxResults. - Turn on
enrichDetailsif you need descriptions and apply links. - Click Start and wait. The actor reports
coverage_limitedwhen a configured page/candidate cap stops paging, andpartialfor request/time or challenge failures. - Export the dataset as JSON, CSV, or Excel.
AI Agent / MCP quick start
The Actor exposes a structured input/output contract that can be called by an authorized Agent or MCP client when enabled in the account.
CLI
Inspect the input contract before calling:
$apify actors info bluedata/seek-jobstreet-jobsdb-scraper --input
Call with structured JSON and machine-readable output:
$apify call bluedata/seek-jobstreet-jobsdb-scraper --input '{"query":"Senior Software Engineer","market":"SG","maxResults":25,"compact":true}' --json
Install Apify MCP into an authorized local AI client:
apify mcp install codex# or: apify mcp install claude-code# or: apify mcp install cursor
For safer Agent selection, expose only the tools/Actors needed for the workflow
with --tools. Do not embed a development token in a shared config.
Agent calling rules
- Use this Actor for supported public job-search intents; abstain when a request needs login-only data or unsupported markets/fields. Public contact fields are off by default and require explicit user intent.
- Prefer
compact: truefor tool calls and useenrichDetails: trueonly when descriptions/apply links are required. - Treat
sourceStatus, coverage/stop reasons,RUN_SUMMARY, and partial status as part of the answer; do not claim completeness when a run is partial. - Treat recurring monitoring as advanced/experimental: concurrent state,
persistence failures, and resume budgets are not hardened, so there is no
production safety guarantee. If used, keep the same
stateStoreName/stateKeyand review every run rather than assuming durable or concurrent safety.
This section documents the CLI/MCP interface only. Availability and service levels depend on the account configuration and current listing.
Use cases
- Salary comparisons across APAC markets with structured, currency-tagged pay bands.
- Recruitment sourcing and talent mapping with company, category, and date filters.
- Advanced/experimental new-job monitoring with incremental change flags; no production safety guarantee is implied.
- Cross-country hiring-trend analysis on one schema.
- AI-agent and MCP pipelines via compact mode and the auto-generated OpenAPI spec.
- Enrichment of hiring-company context; public contact fields are a separate sensitive opt-in.
Availability
Pricing is described above; the Actor's current pricing tab is authoritative. Actual run duration and available data vary with market, query, requested fields, source availability, and platform conditions. No fixed runtime, completeness, or recurring delivery is guaranteed.
FAQ
Which markets are supported?
All eight SEEK markets: AU, NZ (SEEK), SG, MY, ID, PH (JobStreet), HK, TH
(JobsDB). One market code per run.
How many results can I get?
maxResults limits accepted output records after final filters. It is not a
network-request or spending cap: enrichment and filters can require processing
more candidates than the final output count. Set a run timeout and review usage.
Runs that cannot complete the requested search report their status in the run
summary; inspect coverage before treating results as complete.
Does it support recurring monitoring?
The existing incremental API remains available as an advanced/experimental
feature. Enable incremental, reuse the same stateStoreName and stateKey,
and keep the search scope stable. Concurrent state, persistence failures, and
resume request budgets are not hardened; there is no production safety
guarantee. The first run establishes a baseline and later runs may flag new or
changed jobs, but each run's status and coverage must be reviewed. contractCheck
checks required output fields, not the availability of every optional field.
Can I use it with the Apify API / MCP?
Yes, when the Actor is enabled for your account. Use the documented input and output contract and inspect run status before claiming complete coverage.
Is it legal to scrape these sites?
This actor extracts publicly available data without login-only access or credential use. Public contact fields are disabled by default and included only when explicitly requested; review the source terms and applicable privacy laws before using them. Descriptions and company text receive best-effort contact redaction; this does not guarantee anonymization.
Disclaimer
This actor accesses only publicly available data. You are responsible for how you use the extracted data and for complying with each site's terms of use and applicable data-protection law. This actor is an independent tool and is not affiliated with, endorsed by, or sponsored by SEEK, JobStreet, or JobsDB. All trademarks are the property of their respective owners.