# SEEK, JobStreet & Jobsdb Scraper | All Jobs, from $0.60/1K (`alexmorain/seek-jobs-scraper`) Actor

Scrape jobs from SEEK (Australia, New Zealand), JobStreet and Jobsdb (Singapore, Malaysia, Philippines, Indonesia, Hong Kong, Thailand). Every job of a search, past the 550-result cap. Full details, parsed salary, contacts, new-jobs monitoring, webhook.

- **URL**: https://apify.com/alexmorain/seek-jobs-scraper.md
- **Developed by:** [Alex Morain](https://apify.com/alexmorain) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.60 / 1,000 jobs

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does SEEK, JobStreet & Jobsdb Jobs Scraper do?

It extracts job listings from the eight job boards run by SEEK: [seek.com.au](https://www.seek.com.au) and [seek.co.nz](https://www.seek.co.nz), [JobStreet](https://www.jobstreet.com) in Singapore, Malaysia, the Philippines and Indonesia, and [Jobsdb](https://hk.jobsdb.com) in Hong Kong and Thailand. One run can search several of them. It works as a **SEEK API** for job data: it reads the same JSON API the sites use, without a browser, and returns clean rows with the full description, parsed salary, contacts and company data.

The difference you will notice first: **it returns every job of a search, not just the first 550**. SEEK Australia and New Zealand stop paginating after about 550 results, whatever the total, and a plain scraper stops with it. This actor splits a big search into smaller ones until each fits, then merges and deduplicates the results. JobStreet and Jobsdb have no such cap, and their searches are read straight through.

| Search on SEEK Australia (17-18 Oct 2026) | Jobs SEEK reports | Plain paginated search | This actor |
|---|---|---|---|
| `nurse` | 8,756 | 500 (6%) | 8,509 to 8,522 (97%) |
| `data engineer` | 3,171 | 499 (16%) | 3,266 (all of them) |

SEEK's own count is an estimate (it changes with the page size you ask for), which is why one search comes back slightly above it. The run summary (`SUMMARY` record) shows both numbers for every market, so you can check coverage on your own searches.

### Why scrape SEEK, JobStreet and Jobsdb?

SEEK runs the largest job boards of Australia and New Zealand, and owns JobStreet and Jobsdb, which run on the same platform. The eight sites listed about 480,000 live jobs when we counted them (18 Oct 2026).

- **Job market research and salary benchmarks**: complete exports by category, region and work type, with salary amounts parsed into numbers, currency and period.
- **Recruitment agencies and sales teams**: find companies hiring, with the advertiser, company website, size and industry, plus the emails and phone numbers written in the ad.
- **Job alerts and aggregators**: run it daily in New jobs only mode and receive only the jobs you have not seen, by webhook if you like.
- **Data pipelines**: look up single jobs by URL, call it through the Apify API, schedule it, connect it to Make, Zapier, Google Sheets or your database.

### What data can it extract?

| Field | Example |
|---|---|
| `title`, `companyName`, `advertiserName` | Data Engineer, Example Health Group |
| `location`, `area`, `countryCode` | Melbourne VIC, Victoria VIC, AU |
| `classification`, `subClassification` | Information & Communication Technology, Database Development & Administration |
| `workTypes`, `workArrangements` | Full time, Hybrid |
| `salaryLabel` | $120,000 – $140,000 per year |
| `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod` | 120000, 140000, AUD, year |
| `listedAt`, `expiresAt` | 2026-10-02T03:33:34Z |
| `description`, `descriptionHtml` | Full job ad, as text and as HTML |
| `contactEmails`, `contactPhones` | Emails and phones written in the ad |
| `screeningQuestions` | Questions candidates answer when applying |
| `companyWebsite`, `companySize`, `companyIndustry`, `companyRating` | Company profile on SEEK |
| `url`, `id`, `market` | https://www.seek.com.au/job/95018609 |

Every row has the same columns, whether details were fetched or not, so CSV and Excel exports stay aligned.

### How to scrape SEEK jobs

1. Open the Input tab and pick one or more markets (Australia is selected by default).
2. Type keywords as you would in the site's search box, and add a location if you want one city or state.
3. Narrow down with categories, work types, work arrangements, date posted or salary if needed. Leave a field empty to keep all jobs.
4. Set Max jobs per market. Put 0 to get every job of the search, past the 550 limit.
5. Click Start, then download the results as JSON, CSV, Excel or HTML.

To monitor a search, set Mode to New jobs only and schedule the run (daily, hourly). Each run then returns and charges only jobs that no earlier run of the same search returned. Add a webhook URL to be notified with the new jobs.

### How much does it cost to scrape SEEK?

You pay per job delivered, and a small fee per run:

| Event | Free plan | Bronze | Silver | Gold and above |
|---|---|---|---|---|
| Job (search fields) | $1.00 / 1,000 | $0.90 | $0.80 | $0.60 |
| Detailed job (with description, contacts, company) | $2.00 / 1,000 | $1.80 | $1.60 | $1.20 |
| Run start | $0.005 | | | |

A job whose detail request fails is billed as a plain job. In New jobs only mode, jobs already returned before are not billed. The $5 of free monthly credit on the Apify free plan covers about 2,500 detailed jobs. You can cap what a run may spend with the maximum charge setting of the run: the actor stops cleanly at that amount.

### Input

See the Input tab for every option. A few notes:

- **Markets**: AU and NZ are SEEK, SG, MY, PH and ID are JobStreet, HK and TH are Jobsdb. Category ids are the same on all eight.
- **Job URLs**: paste links such as `https://www.seek.com.au/job/95018609` (or bare ids) to fetch those jobs only, with full details. The search fields are then ignored.
- **Salary filter**: needs a salary type (per year, per month, per hour). SEEK matches on the salary range the advertiser entered, including ranges hidden from the ad.
- **Sort**: relevance is the site's order. Newest first also brings broader keyword matches to the top, because SEEK matches any of the words.

```json
{
    "markets": ["AU", "NZ"],
    "keywords": "data engineer",
    "workArrangements": ["hybrid", "remote"],
    "maxItems": 0,
    "includeDetails": true
}
```

### Output

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel. One item per job:

```json
{
    "id": "95018609",
    "url": "https://www.seek.com.au/job/95018609",
    "market": "AU",
    "site": "SEEK Australia",
    "title": "Data Engineer",
    "companyName": "Example Health Group",
    "location": "Melbourne VIC",
    "classification": "Information & Communication Technology",
    "subClassification": "Database Development & Administration",
    "workTypes": ["Full time"],
    "workArrangements": ["On-site"],
    "salaryLabel": "$120,000 – $140,000 per year",
    "salaryMin": 120000,
    "salaryMax": 140000,
    "salaryCurrency": "AUD",
    "salaryPeriod": "year",
    "listedAt": "2026-10-02T03:33:34Z",
    "detailsFetched": true,
    "description": "About the role\n\nThis is a hands-on role...",
    "expiresAt": "2026-11-01T12:59:59.999Z",
    "contactEmails": ["jobs@example.com"],
    "companyWebsite": "https://www.example.com",
    "companySize": "1,001-5,000 employees",
    "companyIndustry": "Hospitals & Healthcare",
    "companyRating": 3.7
}
```

The run also writes a `SUMMARY` record in its key-value store: for each market, the jobs SEEK reports, the unique jobs found, and how many requests and search slices it took.

### Tips

- **Faster, cheaper exports**: turn off full job details. The search fields alone (title, company, location, category, salary, teaser) are often enough for counts and benchmarks: a test export of 12,984 jobs (Australia and Malaysia) took a little over two minutes.
- **Large exports with details**: SEEK serves about 500 job details a minute per IP address, and about 4,500 per IP over a longer window. The actor keeps under the first limit on its own. For more than 4,500 detailed jobs in a run, turn on Apify Proxy in the Network section: the actor moves to a new IP when SEEK refuses (8,216 of 8,216 details on a test export, 22 minutes). Without a proxy, jobs past that point keep their search fields and are billed as plain jobs.
- **Monitoring**: keep the same search fields between runs. Changing the keywords or filters starts a new memory of seen jobs; set a Monitoring key to control this yourself.
- **A search that stays above the limit**: if one slice still holds more than 550 jobs after splitting by category, sub-category, work type, arrangement and region (rare), the log says how many jobs could not be reached. Narrow the search or split it by location.

### FAQ

#### Can I scrape all jobs on SEEK, not only the first 550?

Yes, set Max jobs per market to 0. On SEEK Australia and New Zealand the actor splits the search until each part fits under the limit and merges the results without duplicates. Check `SUMMARY` to compare with the count SEEK announces.

#### Does it work for JobStreet and Jobsdb?

Yes, they run on SEEK's platform. Pick SG, MY, PH, ID (JobStreet) or HK, TH (Jobsdb) in Markets. Their searches have no 550 cap: a test on JobStreet Malaysia returned 5,655 jobs for 5,651 announced. Salary amounts are parsed in the local currency (MYR, PHP, IDR, HKD, THB, SGD).

#### Do I need a proxy or a SEEK account?

No account. The actor reads the public JSON API the sites use, from Apify's own servers. A proxy is only needed for exports of more than about 4,500 jobs with full details in one run.

#### Is it legal to scrape SEEK?

Our Actors are ethical and do not extract any private user data, such as email addresses, gender, or location. They only extract what the user has chosen to share publicly. We therefore believe that our Actors, when used for ethical purposes by Apify users, are safe. However, you should be aware that your results could contain personal data. Personal data is protected by the GDPR in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers. Contact details in the results are only those advertisers wrote in their public job ads.

#### Can I use it through the API?

Yes. See the API tab for ready-to-use calls in Python, JavaScript and cURL, or call it from an AI agent through the Apify MCP server.

#### Something is missing or broken?

Open an issue in the Issues tab with your input, and it will be looked at quickly.

# Actor input Schema

## `markets` (type: `array`):

Job boards to search. One run can cover several.<br>• AU = seek.com.au, NZ = seek.co.nz<br>• SG, MY, PH, ID = JobStreet<br>• HK, TH = Jobsdb

## `location` (type: `string`):

A place as you would type it on the site, for example <code>Sydney NSW</code>, <code>Auckland</code>, <code>Kuala Lumpur</code>. Empty = the whole country.

## `keywords` (type: `string`):

Job title, skill or company, as in the site search box. Empty = all jobs.

## `classifications` (type: `array`):

SEEK job categories. Empty = all categories. The ids are the same on the eight markets.

## `subClassifications` (type: `array`):

Numeric sub-category ids, as found in the <code>subClassificationId</code> field of the results, for example <code>6342</code> (Nursing, general medical and surgical).

## `workTypes` (type: `array`):

Empty = all work types.

## `workArrangements` (type: `array`):

Empty = all. Jobs whose advertiser gave no arrangement only show up when this is empty.

## `postedWithinDays` (type: `string`):

Only jobs listed in this window.

## `salaryType` (type: `string`):

Needed when you set a minimum or maximum salary: the amounts are read per year, per month or per hour.

## `salaryMin` (type: `integer`):

In the market's currency, for the salary type above. SEEK matches on the advertiser's salary range, including ranges hidden from the ad.

## `salaryMax` (type: `integer`):

Same unit as the minimum.

## `sortBy` (type: `string`):

Relevance is the site's order. Newest first also brings broader keyword matches to the top, because SEEK matches any of the words. When a big search is split, the order holds inside each slice.

## `jobUrls` (type: `array`):

Links like <code>https://www.seek.com.au/job/95018609</code>, or bare job ids (read on the first market selected above). When this list is filled, the search fields are ignored and each job comes with its full detail.

## `maxItems` (type: `integer`):

Stop after this many jobs on each market. Ignored for Job URLs. <b>0 = every job of the search</b>. On SEEK Australia and New Zealand, which show at most 550, the actor splits the search by category, sub-category, work type, arrangement and region until each part fits. JobStreet and Jobsdb have no such cap.

## `includeDetails` (type: `boolean`):

Adds the full description (text and HTML), expiry date, screening questions, recruiter emails and phones found in the ad, company website, size, industry and rating. One extra request per 20 jobs; billed as a job with details.

## `mode` (type: `string`):

<b>All matching jobs</b>: every run returns everything that matches.<br><b>New jobs only</b>: a run returns and charges only jobs no previous run of the same search returned. Schedule it daily to receive new jobs.

## `registryKey` (type: `string`):

In New jobs only mode, the memory of seen jobs is tied to the search fields. Set a name here to share or reset that memory on purpose.

## `webhookUrl` (type: `string`):

Called with a POST at the end of a run that found jobs: run id, dataset id, counts per market and the first 100 jobs. A failing webhook never fails the run.

## `proxyConfiguration` (type: `object`):

Not needed for searches. Turn on Apify Proxy for runs of more than about 4,500 jobs <b>with full details</b>: SEEK stops serving details to one IP after that, and the actor then moves to a new IP. Without a proxy, the remaining jobs keep their search fields and are billed as plain jobs.

## Actor input object example

```json
{
  "markets": [
    "AU"
  ],
  "location": "",
  "keywords": "data engineer",
  "classifications": [],
  "subClassifications": [],
  "workTypes": [],
  "workArrangements": [],
  "postedWithinDays": "any",
  "sortBy": "relevance",
  "jobUrls": [],
  "maxItems": 20,
  "includeDetails": true,
  "mode": "all",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `jobs` (type: `string`):

Every job, one item per job. Download as JSON, CSV or Excel.

## `overview` (type: `string`):

Browse the jobs in the console.

## `summary` (type: `string`):

Per market: jobs SEEK reports, unique jobs found, requests and slices used to get past the 550-result cap.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "markets": [
        "AU"
    ],
    "keywords": "data engineer",
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("alexmorain/seek-jobs-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "markets": ["AU"],
    "keywords": "data engineer",
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("alexmorain/seek-jobs-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "markets": [
    "AU"
  ],
  "keywords": "data engineer",
  "maxItems": 20
}' |
apify call alexmorain/seek-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,alexmorain/seek-jobs-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/vT4Oq5nNoKpAqa6n7/builds/EtoTdmX0rECis4Wxv/openapi.json
