# JobStreet & JobsDB Scraper: Every Job, Counted (`luzivanlt/jobstreet-jobs-scraper`) Actor

Every job a JobStreet or JobsDB search lists in 6 countries, checked against the site's count. $1 per 1,000 jobs. Full description, salary and company profile.

- **URL**: https://apify.com/luzivanlt/jobstreet-jobs-scraper.md
- **Developed by:** [Luzi](https://apify.com/luzivanlt) (community)
- **Categories:** Jobs, Lead generation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

## JobStreet & JobsDB Scraper: Every Job, Counted

Get every job a JobStreet or JobsDB search lists, in Malaysia, Singapore, the
Philippines, Indonesia, Hong Kong or Thailand, checked against the site's own
count for that search, and each job with its full description, salary,
applicant count, work type, classification, expiry date, screening questions
and the hiring company's profile (industry, size, website, rating and
reviews). One row per job. No account or cookies needed.

Tested daily. Latest check: 3,906 of 3,906 jobs from six searches, one in
each country, three of them over 1,000 jobs, matching the site's count.

### What does this Actor do?

You give it keywords and a place, or links to JobStreet or JobsDB job
searches. For each search it reads the site's results and then each job's
details, and saves one row per job, until it reaches your limit or the search
has no more jobs. There is no page limit: a search of a thousand jobs is read
to its last job. The run's final status tells you whether every job was read:
"Saved 111 jobs from 1 search. That is every job the site lists for the search
(111 of 111)."

Searches are read newest first. In relevance order the site repeats some jobs
on later pages and leaves others out, so a long search read that way comes up
short; newest first, each job comes once.

Each job comes with:

- its title, link, teaser, summary and the full description, as text and as
  HTML
- the date it was listed, when it expires, and whether it has expired
- the salary, when the job shows one
- work type (full time, part time, contract, casual) and work arrangement
  (on-site, hybrid, remote)
- the classification and subclassification, with their ids
- the place: the state and country, and the district, city or region when
  the site gives them
- the advertiser, whether the site verified it and since when it advertises
  there
- the hiring company's profile, when it has one: industry, size, website,
  description, rating, number of reviews and perks, and for some companies
  their registration number
- the screening questions the employer asks applicants, when there are any
- the job's selling points, tags, logo, cover image and video
- phone numbers the ad lists, when it lists any
- how many people applied and the site's application volume label, when the
  site shows them
- whether you apply on the site or on the employer's own site
- the search it was found in, and how many jobs the site counted for it

### Why use it?

- **Six countries in one Actor.** JobStreet Malaysia, Singapore, the
  Philippines and Indonesia, and JobsDB Hong Kong and Thailand, with the same
  input and the same fields.
- **Know you have the whole search.** The run checks what it read against the
  site's own count, so a short read is never silent.
- **The company comes with the job.** Industry, size, website, rating and
  review count are on the row when the company has a profile.
- **Track a job market.** Run it daily with "Today", and collect each day's
  new jobs.
- **Use the data anywhere.** Download as JSON, CSV or Excel, or send it to
  your own tools through Apify's API and integrations.

### How to use it

1. Pick the **Country**, then type one or more **Keywords** and a
   **Location**, or paste **Search links**, or both.
2. Optionally, choose **Classifications**, **Work types**, **Work
   arrangements**, **Date listed**, a **Salary** range, **Sort by** and **Max
   jobs per search**.
3. Click **Start**. When the run ends, open the **Output** tab to view the
   jobs or download them.

Run it with no input to see a sample: up to 50 "software engineer" jobs in
Kuala Lumpur, charged as usual.

#### Links that work

A job search on `my.jobstreet.com`, `sg.jobstreet.com`, `ph.jobstreet.com`,
`id.jobstreet.com`, `hk.jobsdb.com` or `th.jobsdb.com`, such as
`https://my.jobstreet.com/data-engineer-jobs/in-Kuala-Lumpur?daterange=7` or
`https://hk.jobsdb.com/jobs?keywords=accountant&where=Kowloon`. Its keywords,
place, classification, subclassification, work type, work arrangement, date
listed and salary filters are used. A link is read newest first unless it asks
for relevance. A classification written in the link's path
(`/jobs-in-information-communication-technology`) is not read: pick it under
**Classifications** instead. Other pages (a single job, a company) and other
sites stop the run before anything is read, naming the link.

### Input

| Field                                           | What it does                                                                     | Default   |
| ----------------------------------------------- | -------------------------------------------------------------------------------- | --------- |
| **Country** (`market`)                          | `MY`, `SG`, `PH`, `ID` (JobStreet), `HK` or `TH` (JobsDB), for the keywords      | `MY`      |
| **Keywords** (`keywords`)                       | Job titles or skills to search for, one search each                              | —         |
| **Location** (`location`)                       | A city, district, region or state, used for every keyword. Empty = whole country | —         |
| **Classifications** (`classifications`)         | Only jobs in these classifications                                               | all       |
| **Work types** (`workTypes`)                    | `full-time`, `part-time`, `contract`, `casual`                                   | all       |
| **Work arrangements** (`workArrangements`)      | `on-site`, `hybrid`, `remote`                                                    | all       |
| **Date listed** (`datePosted`)                  | `any`, or listed in the last `1`, `3`, `7`, `14` or `31` days                    | `any`     |
| **Salary type** (`salaryType`)                  | `annual`, `monthly` or `hourly`: what the salary range is counted in             | `monthly` |
| **Salary from / to** (`salaryMin`, `salaryMax`) | Only jobs paying in this range, in the country's currency                        | —         |
| **Sort by** (`sortBy`)                          | `date` (newest first) or `relevance`                                             | `date`    |
| **Search links** (`startUrls`)                  | JobStreet or JobsDB job search links                                             | —         |
| **Max jobs per search** (`maxJobsPerSearch`)    | Stop each keyword or link after this many jobs, 1 to 10,000                      | `100`     |
| **Only new jobs** (`onlyNewItems`)              | Return only jobs no earlier run returned; newest first only (see below)          | off       |

Give at least one keyword, a location, or one link. A location with no
keywords searches every job there. Example input:

```json
{
  "market": "SG",
  "keywords": ["data engineer", "analytics engineer"],
  "workArrangements": ["hybrid", "remote"],
  "datePosted": "7",
  "maxJobsPerSearch": 500
}
```

### New items only

Turn on **Only new jobs** (`onlyNewItems`) for a scheduled run, or a re-run of
the same task. Each run then returns only the jobs it has not returned before:
it reads each search back to a day before the last run that read it, through
the site's own listed-in-the-last-days window (`daterange`), and skips the jobs an earlier run saved. Skipped jobs are neither saved
nor charged; each new job is charged as usual. It works only with **Sort by** set to `date` (newest first, the default): in relevance order the site repeats some jobs on later pages and leaves others out.

- Runs with other settings, or from another task, keep their own list, so two
  schedules on one search never skip each other's jobs.
- If a search stops at **Max jobs per search**, the jobs past that point are
  not returned later. Set the maximum above what one search gets between runs.
- The list lives in your Apify account, in a key-value store named
  `jobstreet-jobs-scraper-monitor`. Delete it to start afresh.

### Output

One row per job. An example, with made-up values and the longer lists cut:

```json
{
  "job_id": "95000001",
  "url": "https://my.jobstreet.com/job/95000001",
  "title": "Data Engineer",
  "company_name": "Example Sdn Bhd",
  "advertiser_id": "60000001",
  "advertiser_name": "Example Sdn Bhd",
  "advertiser_verified": true,
  "advertiser_registered_at": "2012-05-01T00:00:00.000Z",
  "is_private_advertiser": false,
  "employer_id": "7000",
  "employer_name": "Example",
  "employer_company_id": "800000",
  "employer_company_url": "https://my.jobstreet.com/companies/example-800000",
  "company_profile_id": "7000",
  "company_profile_url": "https://my.jobstreet.com/companies/example-800000",
  "company_industry": "Information & Communication Technology",
  "company_size": "101-1,000 employees",
  "company_website": "https://www.example.com",
  "company_description": "We build example things.\nSince 1999.",
  "company_rating": 4.1,
  "company_review_count": 42,
  "company_perks": ["Flexible hours", "Medical"],
  "company_logo_url": "https://image-service-cdn.seek.com.au/…",
  "company_jobs_url": "https://my.jobstreet.com/Example-jobs/at-this-company",
  "company_tags": [{ "name": "Registration No.", "value": "000000-X" }],
  "logo_url": "https://image-service-cdn.seek.com.au/…",
  "cover_image_url": "https://image-service-cdn.seek.com.au/…",
  "location": "Bayan Lepas, Penang",
  "suburb": "Bayan Lepas",
  "area": null,
  "city": null,
  "region": null,
  "state": "Penang",
  "country": "Malaysia",
  "country_code": "MY",
  "location_ids": ["1000187"],
  "locations": [
    {
      "label": "Bayan Lepas, Penang",
      "country_code": "MY",
      "hierarchy": ["Bayan Lepas", "Penang"]
    }
  ],
  "salary": "RM 6,000 – RM 8,000 per month",
  "work_type": "Full time",
  "work_type_id": "242",
  "work_arrangements": ["Hybrid"],
  "work_arrangement_ids": ["2"],
  "classification": "Information & Communication Technology",
  "classification_id": "6281",
  "subclassification": "Engineering - Software",
  "subclassification_id": "6287",
  "classifications": [
    {
      "classification": "Information & Communication Technology",
      "classification_id": "6281",
      "subclassification": "Engineering - Software",
      "subclassification_id": "6287"
    }
  ],
  "role_id": "data-engineer",
  "normalised_role_title": "Data Engineer",
  "listed_at": "2026-10-22T01:02:03.000Z",
  "listed_ago": "5h ago",
  "expires_at": "2026-11-21T12:59:59.999Z",
  "is_expired": false,
  "status": "Active",
  "is_promoted": false,
  "display_type": "standard",
  "apply_on_other_site": false,
  "is_verified": true,
  "has_role_requirements": true,
  "applicant_count": 25,
  "applicant_volume": "High application volume",
  "badges": ["On-site"],
  "contacts": [],
  "tags": ["Be an early applicant"],
  "teaser": "Join a small team building our data platform…",
  "abstract": "Hybrid role in Penang.",
  "bullet_points": ["Hybrid working", "Medical benefits"],
  "screening_questions": ["What's your expected monthly basic salary?"],
  "video_url": null,
  "details_read": true,
  "description_text": "About the role\n- Build our data platform…",
  "description_html": "<p><strong>About the role</strong></p><ul><li>Build our data platform…</li></ul>",
  "search_keyword": "data engineer",
  "search_location": "Penang",
  "search_location_resolved": "Penang",
  "search_location_id": "1000187",
  "search_market": "MY",
  "search_url": "https://my.jobstreet.com/jobs?keywords=data%20engineer&where=Penang&sortmode=ListedDate",
  "search_total": 157,
  "search_listed": 157
}
```

| Field                      | What it holds                                                                                                                                         |
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `job_id`                   | The site's id for the job                                                                                                                             |
| `url`                      | The job's page                                                                                                                                        |
| `title`                    | The job's title                                                                                                                                       |
| `company_name`             | The company hiring, as the ad names it                                                                                                                |
| `advertiser_id`            | The site's id for the advertiser (the employer or its recruiter)                                                                                      |
| `advertiser_name`          | The advertiser's name                                                                                                                                 |
| `advertiser_verified`      | `true` when the site verified the advertiser                                                                                                          |
| `advertiser_registered_at` | When the advertiser joined the site                                                                                                                   |
| `is_private_advertiser`    | `true` for a private advertiser                                                                                                                       |
| `employer_id`              | The site's id for the employer                                                                                                                        |
| `employer_name`            | The employer's name                                                                                                                                   |
| `employer_company_id`      | The employer's company id, when it has a company page                                                                                                 |
| `employer_company_url`     | The employer's company page                                                                                                                           |
| `company_profile_id`       | The site's id for the company profile                                                                                                                 |
| `company_profile_url`      | The company's profile on the site, when it has one                                                                                                    |
| `company_industry`         | The company's industry                                                                                                                                |
| `company_size`             | The company's size ("101-1,000 employees")                                                                                                            |
| `company_website`          | The company's website                                                                                                                                 |
| `company_description`      | The company's description, one paragraph a line                                                                                                       |
| `company_rating`           | The company's rating on the site, out of 5                                                                                                            |
| `company_review_count`     | How many reviews the rating is from                                                                                                                   |
| `company_perks`            | The perks and benefits the company lists                                                                                                              |
| `company_logo_url`         | The logo on the company's profile                                                                                                                     |
| `company_jobs_url`         | The advertiser's other jobs on the site                                                                                                               |
| `company_tags`             | Facts the company lists about itself, such as its registration number                                                                                 |
| `logo_url`                 | The logo on the job ad                                                                                                                                |
| `cover_image_url`          | The cover image on the job ad                                                                                                                         |
| `location`                 | Where the job is, as the site shows it                                                                                                                |
| `suburb`                   | The district or suburb, when the site gives one                                                                                                       |
| `area`                     | The area within the city, when the site gives one                                                                                                     |
| `city`                     | The city, when the site gives one                                                                                                                     |
| `region`                   | The region, when the site gives one                                                                                                                   |
| `state`                    | The state or province                                                                                                                                 |
| `country`                  | The country                                                                                                                                           |
| `country_code`             | `MY`, `SG`, `PH`, `ID`, `HK` or `TH`                                                                                                                  |
| `location_ids`             | The site's ids for the place                                                                                                                          |
| `locations`                | Every place the ad lists, with its place names from narrow to broad                                                                                   |
| `salary`                   | The pay, as shown. Empty when the job shows none                                                                                                      |
| `work_type`                | Full time, Part time, Contract/Temp or Casual/Vacation                                                                                                |
| `work_type_id`             | The site's id for the work type                                                                                                                       |
| `work_arrangements`        | On-site, Hybrid or Remote                                                                                                                             |
| `work_arrangement_ids`     | The site's ids for them                                                                                                                               |
| `classification`           | The classification ("Information & Communication Technology")                                                                                         |
| `classification_id`        | Its id                                                                                                                                                |
| `subclassification`        | The subclassification ("Engineering - Software")                                                                                                      |
| `subclassification_id`     | Its id                                                                                                                                                |
| `classifications`          | Every classification the ad lists                                                                                                                     |
| `role_id`                  | The site's role id ("data-engineer")                                                                                                                  |
| `normalised_role_title`    | The site's name for the role                                                                                                                          |
| `listed_at`                | When the job was listed                                                                                                                               |
| `listed_ago`               | How long ago, as the site says it ("4h ago")                                                                                                          |
| `expires_at`               | When the ad expires                                                                                                                                   |
| `is_expired`               | `true` when the ad has expired                                                                                                                        |
| `status`                   | `Active` or `Expired`                                                                                                                                 |
| `is_promoted`              | `true` when the site showed the job as a promoted ad on the page that listed it, or an earlier one                                                    |
| `display_type`             | How the site lays the ad out in the results (`standard` for most)                                                                                     |
| `apply_on_other_site`      | `true` when you apply on the employer's own site                                                                                                      |
| `is_verified`              | `true` when the site marks the ad verified                                                                                                            |
| `has_role_requirements`    | `true` when the ad lists role requirements                                                                                                            |
| `applicant_count`          | How many people applied, when the site shows it                                                                                                       |
| `applicant_volume`         | The site's label for it ("High application volume")                                                                                                   |
| `badges`                   | The badges the site puts on the job ("On-site")                                                                                                       |
| `contacts`                 | Phone numbers the ad lists                                                                                                                            |
| `tags`                     | The site's labels on the ad ("Be an early applicant")                                                                                                 |
| `teaser`                   | The short text the site shows in the results                                                                                                          |
| `abstract`                 | The ad's summary                                                                                                                                      |
| `bullet_points`            | The ad's selling points                                                                                                                               |
| `screening_questions`      | The questions the employer asks applicants                                                                                                            |
| `video_url`                | The ad's video, when it has one                                                                                                                       |
| `details_read`             | `false` when the job was taken down while the run read it: the row then holds only what the results showed                                            |
| `description_text`         | The full description, as plain text                                                                                                                   |
| `description_html`         | The full description, with its formatting                                                                                                             |
| `search_keyword`           | The keyword the job was found under                                                                                                                   |
| `search_location`          | The location you searched                                                                                                                             |
| `search_location_resolved` | The place the site searched for it                                                                                                                    |
| `search_location_id`       | The site's id for that place                                                                                                                          |
| `search_market`            | `MY`, `SG`, `PH`, `ID`, `HK` or `TH`                                                                                                                  |
| `search_url`               | The search on the site                                                                                                                                |
| `search_total`             | How many jobs the site counts for the search. Empty only when a promoted job was listed and the search filters on work arrangement and salary at once |
| `search_listed`            | The site's headline number for the search                                                                                                             |

Not included: the apply link and an email address (the sites show them only
to signed-in members), and salary estimates for a job that shows no salary.

### How much does it cost?

No surcharges and no paid options; an item that fails is not charged.

You pay for what you get:

- **$1 per 1,000 jobs** ($0.001 a job). Each job is charged once per run, even when two of your searches list it.
- No start fee, and nothing per search.

So a search that lists 400 jobs costs $0.40. If you set a maximum cost for a run, the Actor stops when it reaches it and keeps every job saved so far.

### How long does a run take?

About 50 jobs in 15 to 25 seconds; 3,906 jobs from six searches in 18 minutes
(about 3.6 jobs a second). One search of 10,000 jobs takes about 45 minutes,
inside the default 1-hour timeout; for several large searches in one run,
raise the run's timeout.

### Good to know

- **The site decides what matches.** Its count includes jobs that only
  loosely match a keyword; the Actor returns what the site lists.
- **Counts move.** The count for a busy search changes while it is read, so a
  search can read a job or two short of it, or past it. The final status says
  so, by search.
- **Relevance order is not checked.** Sorted by relevance, the site repeats
  jobs on later pages and leaves others out, so a search read that way is not
  checked against the count; use newest first (the default) to read a search
  whole.
- **One job, one row.** A job found again in the same run, under the same or
  another search, is saved and charged once. It still counts toward each
  search that lists it, so every search is checked against its own count.
- **A job taken down mid-run** keeps the fields the results showed (title,
  company, place, salary, teaser) and has `details_read` set to `false`.
- **A search that cannot be read** is reported in the run's status; the other
  searches carry on. The run fails only when none could be read.
- **Labels are in English**, in every country. The job's own text (title,
  description) is in whatever language the employer wrote it.
- **Running it daily?** Remove repeats by `job_id`.

### More Actors from us

- [Airbnb Scraper: Every Stay, Past the 15-Page Limit](https://apify.com/luzivanlt/airbnb-listings-scraper): Every stay of an Airbnb search, past the 15 pages Airbnb shows, checked against its count.
- [Alibaba Products Scraper: Price Tiers & Suppliers](https://apify.com/luzivanlt/alibaba-products-scraper): Alibaba.com products by keyword or link, with price tiers in US dollars on every row.
- [AliExpress Product Scraper: Search Results & Prices](https://apify.com/luzivanlt/aliexpress-products-scraper): Every product of an AliExpress search to its last page, with exact sold counts and ratings.
- [Amazon Product Scraper: Search Results & Prices](https://apify.com/luzivanlt/amazon-products-scraper): Every product on Amazon's search pages to the last page, sponsored marked, with monthly sales.
- [App Store Reviews Scraper: All Reviews, Not 500](https://apify.com/luzivanlt/app-store-reviews-scraper): Every written App Store review of an app, not just the newest 500.
- [Woolworths Coles ALDI Scraper: AU Grocery Prices](https://apify.com/luzivanlt/au-supermarkets-scraper): Woolworths, Coles and ALDI products for any search in one run, every results page to the end.

### Use it from an AI agent or the API

One call starts a run and returns its items (Apify waits up to 300 seconds; for a
longer run, start it with `POST /v2/acts/…/runs` and read its dataset):

```text
POST https://api.apify.com/v2/acts/luzivanlt~jobstreet-jobs-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>
```

With the sample input as its JSON body:

```json
{
  "market": "MY",
  "keywords": ["software engineer"],
  "location": "Kuala Lumpur",
  "datePosted": "any",
  "salaryType": "monthly",
  "sortBy": "date",
  "maxJobsPerSearch": 50
}
```

Its inputs, in the order of the input form:

| Input                                    | What it takes                                                                                                                                                                                                                                              | Default     |
| ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| `market` (Country)                       | Which site to search: JobStreet Malaysia, Singapore, the Philippines or Indonesia, or JobsDB Hong Kong or Thailand.                                                                                                                                        | `"MY"`      |
| `keywords` (Keywords)                    | Job titles or skills to search for, one search per keyword (e.g. "data engineer").                                                                                                                                                                         | —           |
| `location` (Location)                    | Where the jobs are, as you would type it on the site: a city, district, region or state (e.g. "Kuala Lumpur", "Penang", "Cebu" or "Kowloon").                                                                                                              | —           |
| `classifications` (Classifications)      | Only jobs in these classifications, for the keywords above.                                                                                                                                                                                                | —           |
| `workTypes` (Work types)                 | Only these work types, for the keywords above: full time, part time, contract/temp or casual/vacation.                                                                                                                                                     | —           |
| `workArrangements` (Work arrangements)   | Only jobs on-site, hybrid or remote, for the keywords above.                                                                                                                                                                                               | —           |
| `datePosted` (Date listed)               | Only jobs listed in this time, for the keywords above: any time, today, or the last 3, 7, 14 or 30 days.                                                                                                                                                   | `"any"`     |
| `salaryType` (Salary type)               | What the salary range below is counted in: annually, monthly or hourly.                                                                                                                                                                                    | `"monthly"` |
| `salaryMin` (Salary from)                | Only jobs paying at least this, in the country's currency (RM, S$, ₱, Rp, HK$ or ฿), for the keywords above.                                                                                                                                               | —           |
| `salaryMax` (Salary to)                  | Only jobs paying at most this, in the country's currency, for the keywords above.                                                                                                                                                                          | —           |
| `sortBy` (Sort by)                       | The order the jobs are read in: newest first, or relevance.                                                                                                                                                                                                | `"date"`    |
| `startUrls` (Search links)               | Links to JobStreet or JobsDB job searches (my., sg., ph. or id.jobstreet.com; hk. or th.jobsdb.com), e.g. https://my.jobstreet.com/data-engineer-jobs/in-Kuala-Lumpur?daterange=7.                                                                         | —           |
| `maxJobsPerSearch` (Max jobs per search) | Stop each keyword or link after this many jobs, from 1 to 10,000.                                                                                                                                                                                          | `100`       |
| `onlyNewItems` (Only new jobs)           | Turn this on for a scheduled run, or a re-run of the same task: each run then returns only the jobs it has not returned before, reading each search back to a day before the last run that read it, through the site's own listed-in-the-last-days window. | —           |

Apify's MCP server, `https://mcp.apify.com`, lists it as `luzivanlt/jobstreet-jobs-scraper`. To give an
AI agent this Actor as a tool, add the server to the agent's MCP config:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=luzivanlt/jobstreet-jobs-scraper"
    }
  }
}
```

The client signs in with OAuth, or add `"headers": { "Authorization": "Bearer <APIFY_TOKEN>" }`.

Charged per job delivered; the sample input above costs at most $0.05.

### FAQ

**Do I need a JobStreet or JobsDB account, or cookies?**
No. The Actor reads what anyone can see on the sites without signing in.

**Which countries does it cover?**
JobStreet Malaysia, Singapore, the Philippines and Indonesia, and JobsDB Hong
Kong and Thailand. Not Vietnam.

**Can I run it from my own code, on a schedule, or with other apps?**
Yes. Like any Apify Actor, you can start it through the Apify API, run it on a
schedule, and connect it to other apps with Apify's integrations and webhooks.

### Is it legal to scrape JobStreet and JobsDB?

This Actor reads only public job ads. An ad can list a phone number or name a
person; treat those as personal data. Check the sites' terms and the laws that
apply to you (such as Malaysia's PDPA, Singapore's PDPA or the GDPR) before
you use the data. If you are unsure, ask a lawyer.

### Support

Found a problem or missing a feature? Open an issue on the **Issues** tab and
include the run's link.

***

This Actor is not affiliated with, endorsed by or sponsored by JobStreet,
JobsDB or SEEK.

# Changelog

This Actor's version history is a separate document: https://apify.com/luzivanlt/jobstreet-jobs-scraper/changelog.md

# Actor input Schema

## `market` (type: `string`):

Which site to search: JobStreet Malaysia, Singapore, the Philippines or Indonesia, or JobsDB Hong Kong or Thailand. Applies to the keywords below; a search link carries its own country. Default: Malaysia (MY). Example: HK, to search JobsDB Hong Kong.

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

Job titles or skills to search for, one search per keyword (e.g. "data engineer"). Leave empty and give a location to get every job there. Each keyword uses the Country, Location and filters below; paste links under Search links. A job two keywords both list is saved and charged once.

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

Where the jobs are, as you would type it on the site: a city, district, region or state (e.g. "Kuala Lumpur", "Penang", "Cebu" or "Kowloon"). Used for every keyword, up to 200 characters; with no keywords, it searches every job there. Empty = the whole country. A search link keeps its own place.

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

Only jobs in these classifications, for the keywords above. Pick one or more; leave empty for every classification. A search link keeps its own classification and subclassification. Example: Information & Communication Technology.

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

Only these work types, for the keywords above: full time, part time, contract/temp or casual/vacation. Pick one or more; leave empty for all of them. A search link keeps its own work type. Example: full-time and contract.

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

Only jobs on-site, hybrid or remote, for the keywords above. Pick one or more; leave empty for all of them. A search link keeps its own work arrangement. Example: hybrid and remote, to leave out on-site jobs.

## `datePosted` (type: `string`):

Only jobs listed in this time, for the keywords above: any time, today, or the last 3, 7, 14 or 30 days. A search link keeps its own date range. Default: any time. Example: "7" for jobs listed in the last 7 days.

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

What the salary range below is counted in: annually, monthly or hourly. Used only when Salary from or Salary to is set. Default: monthly. Example: annual, with Salary from 60000, for jobs paying at least 60,000 a year.

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

Only jobs paying at least this, in the country's currency (RM, S$, ₱, Rp, HK$ or ฿), for the keywords above. A whole number from 0, counted in the Salary type (monthly by default). Leave empty for no lower bound. Example: 5000 for jobs paying at least RM 5,000 a month in Malaysia.

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

Only jobs paying at most this, in the country's currency, for the keywords above. A whole number from 0, counted in the Salary type (monthly by default), and not below Salary from. Leave empty for no upper bound. Example: 9000.

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

The order the jobs are read in: newest first, or relevance. Newest first reads every job of a long search exactly once; in relevance order the site repeats some jobs on later pages and skips others, so a search read by relevance may come up short of the site's count. With a limit, the order decides which jobs you get. A search link that asks for relevance keeps it. Default: newest first. Example: relevance, to get the best matches first when you set a low limit.

## `startUrls` (type: `array`):

Links to JobStreet or JobsDB job searches (my., sg., ph. or id.jobstreet.com; hk. or th.jobsdb.com), e.g. https://my.jobstreet.com/data-engineer-jobs/in-Kuala-Lumpur?daterange=7. The link's country, keywords, place and filters are used. The link needs keywords or a place; a single job or a company page is refused.

## `maxJobsPerSearch` (type: `integer`):

Stop each keyword or link after this many jobs, from 1 to 10,000. Default 100. Each job is charged once ($1 per 1,000 jobs), so this caps what one search costs: 100 jobs cost at most $0.10. Example: 1000.

## `onlyNewItems` (type: `boolean`):

Turn this on for a scheduled run, or a re-run of the same task: each run then returns only the jobs it has not returned before, reading each search back to a day before the last run that read it, through the site's own listed-in-the-last-days window. Skipped jobs are neither saved nor charged; each new job is charged as usual. Works only with Sort by date (newest first). Runs with other settings, or from another task, keep their own list. Off by default.

## Actor input object example

```json
{
  "market": "MY",
  "keywords": [
    "software engineer"
  ],
  "location": "Kuala Lumpur",
  "datePosted": "any",
  "salaryType": "monthly",
  "sortBy": "date",
  "maxJobsPerSearch": 50
}
```

# Actor output Schema

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

Every job the run saved, one row per job.

## `allFields` (type: `string`):

The same rows with every field.

## `runReport` (type: `string`):

What happened to each input: items saved, nothing found, refused by the site, stopped at your limit, or the error.

# 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 = {
    "market": "MY",
    "keywords": [
        "software engineer"
    ],
    "location": "Kuala Lumpur",
    "maxJobsPerSearch": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("luzivanlt/jobstreet-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 = {
    "market": "MY",
    "keywords": ["software engineer"],
    "location": "Kuala Lumpur",
    "maxJobsPerSearch": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("luzivanlt/jobstreet-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 '{
  "market": "MY",
  "keywords": [
    "software engineer"
  ],
  "location": "Kuala Lumpur",
  "maxJobsPerSearch": 50
}' |
apify call luzivanlt/jobstreet-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,luzivanlt/jobstreet-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/0QrrhI1hCPfcjOC5P/builds/x7YpqPHgsfOBBNGXd/openapi.json
