# SEEK, JobStreet & JobsDB Jobs Scraper (`steadyrows/seek-jobstreet-jobsdb-jobs-scraper`) Actor

Job ads from SEEK (Australia, New Zealand), JobStreet (Malaysia, Singapore, Philippines, Indonesia) and JobsDB (Hong Kong, Thailand) in one format: salary, full description, contact emails and phones, company profile.

- **URL**: https://apify.com/steadyrows/seek-jobstreet-jobsdb-jobs-scraper.md
- **Developed by:** [SteadyRows](https://apify.com/steadyrows) (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 $1.00 / 1,000 job (search row)s

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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 this does

Gets job ads from the eight SEEK group job sites in one run and one output format:

- **SEEK**: Australia, New Zealand
- **JobStreet**: Malaysia, Singapore, Philippines, Indonesia
- **JobsDB**: Hong Kong, Thailand

For each job you get the title, company, location, salary, work type, work arrangement (on-site, hybrid, remote), classification and listing date. With **details** on (the default) you also get the full description as text and HTML, the **emails and phone numbers written in the ad**, the expiry date, the employer's screening questions, and the company's website, industry, size and rating.

It reads the sites' own public search data, not rendered pages, so it needs no proxy and no browser. 1,000 jobs with full details take about four minutes; search rows alone take seconds.

### Input examples

Data analyst jobs in Sydney, with full details:

```json
{ "countries": ["au"], "keywords": ["data analyst"], "location": "Sydney", "maxJobs": 200 }
```

Daily monitoring: everything new for two keywords on three sites, posted in the last day:

```json
{ "countries": ["my", "sg", "ph"], "keywords": ["accountant", "finance manager"], "postedWithinDays": 1, "sort": "newest", "maxJobs": 500 }
```

Every nurse job in Australia (goes past the sites' 500-per-search limit automatically):

```json
{ "countries": ["au"], "keywords": ["nurse"], "maxJobs": 20000 }
```

A results page copied from the site, filters included (keyword, location, classification, salary, date, work type and sort order are read from the address):

```json
{ "searchUrls": ["https://www.seek.com.au/data-analyst-jobs/in-All-Sydney-NSW?daterange=7&salaryrange=100000-150000&salarytype=annual", "https://www.seek.com.au/jobs-in-information-communication-technology/business-systems-analysts/in-Melbourne-VIC"], "maxJobs": 500 }
```

Remote and hybrid contract roles across Australia and New Zealand, search rows only (cheaper):

```json
{ "countries": ["au", "nz"], "keywords": ["python developer"], "workTypes": ["contract"], "workArrangements": ["remote", "hybrid"], "includeDetails": false }
```

### Output

```json
{
  "id": "94853289",
  "site": "SEEK Australia",
  "country": "au",
  "title": "Data Analyst",
  "company": "The Cabinet Office",
  "location": "Sydney NSW",
  "salary": "$116,981 - $129,492 plus 12% super",
  "currency": "AUD",
  "workTypes": ["Contract/Temp"],
  "workArrangement": "Hybrid",
  "classification": "Information & Communication Technology",
  "subclassification": "Business/Systems Analysts",
  "teaser": "FTC opportunity up to 30 June 2028, based in Martin Place, Sydney CBD...",
  "listedAt": "2026-09-24T05:25:11Z",
  "promoted": false,
  "url": "https://www.seek.com.au/job/94853289",
  "keyword": "data analyst",
  "descriptionText": "The Cabinet Office\n\nData Analyst\n\nYou. At the centre of big ideas...",
  "descriptionHtml": "<strong>The Cabinet Office</strong>...",
  "expiresAt": "2026-10-08T05:25:09.000Z",
  "emails": ["recruiter@example.gov.au"],
  "phones": [],
  "appliesOnCompanySite": true,
  "screeningQuestions": [],
  "advertiserVerified": true,
  "advertiserSince": "2023-06-26T02:37:22.031Z",
  "companyWebsite": null,
  "companyIndustry": null,
  "companySize": null,
  "companyRating": null,
  "companyReviewCount": null
}
```

Fields an ad doesn't have are `null` or an empty list. About 4 in 10 ads state a salary; about 1 in 6 contain an email address.

### Limits worth knowing

- **Search URLs.** Paste the address of any results page from the eight sites; the salary range, which has no separate input field, works this way. A URL that already names a classification is split by subclassification and work type when it hits the 500 cap.
- **More than 500 jobs per search.** The sites show only 500 jobs for one search. When you ask for more, the actor repeats the search inside each job classification, then each subclassification and work type, and skips duplicates. In a test, "nurse" on SEEK Australia returned 8,971 jobs of the roughly 9,500 the site reported. A job found by two keywords or two slices is delivered (and charged) once.
- With a limit below the total, the biggest classifications for your keyword come first, so you get the closest matches.
- **Keyword matching is loose.** The sites match by meaning as well as by words, so a search can return related roles. "Most relevant first" (the default) keeps the closest matches at the top.
- Salary is the text the advertiser wrote, in the local currency of the site.
- If the details of one job can't be fetched, the job is still delivered as a search row and charged at the lower search-row price.

### Pricing

You pay per job delivered: one price for a search row, a higher one for a job with full details. Set a maximum cost per run in the run options and the actor stops cleanly when it reaches it.

| Event | Price |
|---|---|
| Job with details | $1.50 per 1,000 |
| Job, search row only | $1.00 per 1,000 |
| Run start | $0.002 |

### Support

Open an issue on the Issues tab. Broken runs get fixed first.

# Actor input Schema

## `countries` (type: `array`):

Which country sites to search. Each keyword is searched on each site.

## `keywords` (type: `array`):

Job titles, skills or company names, one search each. Leave empty to get every job in the location.

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

City, suburb or region as you would type it on the site, e.g. Sydney, Auckland, Kuala Lumpur. Leave empty for the whole country.

## `searchUrls` (type: `array`):

Results pages copied from the site's address bar, e.g. `https://www.seek.com.au/data-analyst-jobs/in-All-Sydney-NSW?daterange=7&salaryrange=100000-150000&salarytype=annual` or `https://www.seek.com.au/jobs-in-information-communication-technology/business-systems-analysts/in-Melbourne-VIC`. Keyword, location, classification, subclassification, salary, date, work type, work arrangement and sort order are all read from the URL. Each URL is one search; countries and keywords above are not needed.

## `maxJobs` (type: `integer`):

Upper limit per keyword on each site. The sites show only 500 jobs per search; when you ask for more, the actor splits the search by job classification and work type to reach the rest.

## `postedWithinDays` (type: `integer`):

Only jobs listed in the last N days. Leave empty for any time. Use 1 for a daily monitoring run.

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

Leave empty for all.

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

Leave empty for all.

## `sort` (type: `string`):

Order of results within each search. The sites match keywords loosely, so "most relevant" keeps the closest matches at the top; use "newest" with "Posted within" for monitoring.

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

Adds the full job description (text and HTML), emails and phone numbers in the ad, expiry date, screening questions, and the company's website, size and rating. Turn off for cheaper, faster search rows.

## Actor input object example

```json
{
  "countries": [
    "au"
  ],
  "keywords": [
    "data analyst"
  ],
  "searchUrls": [],
  "maxJobs": 100,
  "sort": "relevance",
  "includeDetails": true
}
```

# Actor output Schema

## `results` (type: `string`):

All rows the run collected, one per item, in the default dataset.

# 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 = {
    "countries": [
        "au"
    ],
    "keywords": [
        "data analyst"
    ],
    "searchUrls": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("steadyrows/seek-jobstreet-jobsdb-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 = {
    "countries": ["au"],
    "keywords": ["data analyst"],
    "searchUrls": [],
}

# Run the Actor and wait for it to finish
run = client.actor("steadyrows/seek-jobstreet-jobsdb-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 '{
  "countries": [
    "au"
  ],
  "keywords": [
    "data analyst"
  ],
  "searchUrls": []
}' |
apify call steadyrows/seek-jobstreet-jobsdb-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,steadyrows/seek-jobstreet-jobsdb-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/r9rntoutXL18tcVRy/builds/R6GNCKf064toJ9R4p/openapi.json
