# JobStreet Jobs Scraper (`deriverge/jobstreet-jobs-scraper`) Actor

Job ads from JobStreet in Malaysia, Singapore, the Philippines and Indonesia, with pay as numbers in the local currency, classification, work type and the full ad text. Search by keyword and location in one or more countries, or paste a JobStreet search link.

- **URL**: https://apify.com/deriverge/jobstreet-jobs-scraper.md
- **Developed by:** [deriverge s.r.o.](https://apify.com/deriverge) (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.25 / 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 Jobs Scraper

JobStreet runs job boards for Malaysia, Singapore, the Philippines and Indonesia on SEEK's job platform. One row is one ad: title, advertiser, location and area, classification, work type, work arrangement, the pay as written and as numbers in `MYR`, `SGD`, `PHP` or `IDR`, the teaser, up to three bullet points and the full ad text. Choose a **Country**, type `accountant` and click **Start**. Pay appears only when the advertiser shows it: 509 of 1,369 Malaysian `software engineer` ads had it in a September 2026 run. It costs $0.50 per 1,000 jobs on the Free plan ($0.25 on Business), and the $5 of monthly credit in Apify's Free plan covers about 10,000 jobs.

### Output fields

| Field | Description |
|---|---|
| `title`, `company`, `advertiserId` | Ad title, the employer or agency as JobStreet shows it, and its advertiser ID, which stays the same on all of its ads. |
| `site`, `countryCode` | The JobStreet site the ad comes from: `MY`, `SG`, `PH` or `ID`. |
| `location`, `area`, `locations` | Place as the ad gives it, e.g. `Bayan Lepas, Penang`, the wider area such as `Penang`, and every place of an ad that names several. |
| `classification`, `subClassification` | Job category and subcategory, e.g. `Information & Communication Technology` and `Developers/Programmers`. |
| `workTypes` | `Full time`, `Part time`, `Contract/Temp` or `Casual/Vacation`; a few ads list two. |
| `workArrangement` | `Remote`, `Hybrid` or `On-site`, filled only when the advertiser sets it. |
| `salaryText` | Pay as the ad words it, such as `RM 15,000 - RM 20,000 per month` or `Php70,000-Php80,000`. |
| `salaryMin`, `salaryMax`, `salaryPeriod`, `salaryCurrency` | The same pay as numbers, mostly `monthly`, in `MYR`, `SGD`, `PHP` or `IDR`. Dollar amounts outside Singapore come as `USD`. |
| `teaser`, `bulletPoints` | The one-line summary shown in search results and up to three selling points the advertiser picked. |
| `featured` | `true` for a paid featured ad. |
| `postedAt`, `expiresAt` | Listing date and expiry in UTC; most ads run for 30 days. |
| `description`, `descriptionHtml` | With details on: the whole ad text, plain and as HTML, for up to 450 ads per run. |
| `url`, `applyUrl` | The ad on JobStreet and its apply page. |
| `key`, `jobId` | The job ID and a key made of `seek:` plus that ID, because the ads sit on SEEK's platform. |

### How to scrape JobStreet

1. Pick the **Country**: Malaysia, Singapore, the Philippines or Indonesia. With several countries ticked, the same search runs once on each site.
2. Type **Keywords** such as `accountant`, `software engineer` or `nurse`, and a **Location** spelled the JobStreet way: `Kuala Lumpur`, `Penang`, `Metro Manila`, `Cebu` or `Jakarta`. An empty location searches the whole country.
3. Filter with **Classifications**, **Work types**, **Remote options**, **Listed in the last** (1 to 31 days), **Minimum yearly salary** in the local currency and **Sort by**. JobStreet applies them in its own search. In October 2026 a minimum of 60,000 cut Malaysian `accountant` ads from 5,718 to 2,852, and 3 of the first 10 left had no visible pay, because the filter also uses pay that employers hide.
4. A search set up on the website can be pasted into **Search links from JobStreet (optional)**, e.g. `https://my.jobstreet.com/accountant-jobs/in-Kuala-Lumpur?worktype=243` for part-time jobs. Its keywords, place and filters are kept.
5. Keep **Include full job details** on for the full text and the expiry date of the first 450 ads, then click **Start**. Ads land in the **Output** tab as they arrive; export them as CSV, Excel or JSON, or read the dataset with the API.

As API input, full-time software jobs posted in the past week in Malaysia and Singapore:

```json
{
  "keywords": "software engineer",
  "sites": ["MY", "SG"],
  "workTypes": ["full_time"],
  "postedWithinDays": "7",
  "maxItems": 1000
}
```

### Example output

A Malaysian ad from a run on 27 September 2026; `description` and `descriptionHtml` are cut after the first responsibility.

```json
{
  "key": "seek:94581153",
  "jobId": "94581153",
  "site": "MY",
  "title": ".NET Backend Lead",
  "url": "https://my.jobstreet.com/job/94581153",
  "applyUrl": "https://my.jobstreet.com/job/94581153/apply",
  "company": "Focal Consulting",
  "advertiserId": "63362011",
  "companyLogo": null,
  "location": "Kuala Lumpur",
  "locations": [
    "Kuala Lumpur"
  ],
  "area": "Kuala Lumpur",
  "countryCode": "MY",
  "classification": "Information & Communication Technology",
  "subClassification": "Developers/Programmers",
  "workTypes": [
    "Full time"
  ],
  "workArrangement": null,
  "salaryText": "RM 15,000 - RM 20,000 per month",
  "salaryMin": 15000,
  "salaryMax": 20000,
  "salaryPeriod": "monthly",
  "salaryCurrency": "MYR",
  "teaser": "Lead backend teams, architect scalable .NET systems, and drive engineering and code excellence.",
  "bulletPoints": [
    "13-Month Salary & Yearly Performance",
    "Monthly Transport Allowance",
    "Monthly Rental Subsidies"
  ],
  "featured": false,
  "postedAt": "2026-09-11T09:23:38.853Z",
  "expiresAt": "2026-10-11T08:23:00.000Z",
  "description": "Role Summary\nLead backend teams, architect scalable .NET systems, and drive engineering and code excellence.\n\nRoles & Responsibilities\n- Technical Leadership & Mentorship: Lead, mentor, and guide backend engineers while driving high engineering standards and team accountability. ...",
  "descriptionHtml": "<strong>Role Summary</strong> <br>Lead backend teams, architect scalable .NET systems, and drive engineering and code excellence.<br><br> <strong>Roles &amp; Responsibilities</strong> <ul> <li><strong>Technical Leadership &amp; Mentorship:</strong>&nbsp;Lead, mentor, and guide backend engineers while driving high engineering standards and team accountability.</li> ...",
  "searchQuery": "MY: \"software engineer\"",
  "scrapedAt": "2026-09-27T10:45:30.743Z"
}
```

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

| | Free plan | Starter | Scale | Business |
|---|---|---|---|---|
| 1,000 jobs | $0.50 | $0.40 | $0.325 | $0.25 |

You pay only for the events in the table. There is no start fee, and compute time and proxies are included.

Reading 2,000 ads costs $1.00 on the Free plan and $0.50 on Business. You are not charged for ads that **Exclude keywords** removes, for an ad that two parts of a split search both return, or for ads the new-only mode skips.

### Limits

- JobStreet's search gives at most 500 ads per query. When **Maximum jobs** asks for more, the actor walks through the 30 classifications and splits any classification over 500 by its 4 work types, yet one slice can still hold more. In September 2026 `software engineer` matched 2,659 ads in Malaysia and the split reached 1,369 of them; full-time ICT jobs alone filled one slice of 500. The run log estimates how many ads stayed out of reach.
- The numbers are read out of the pay text, so wording without figures, such as `Attractive package`, leaves them empty. `salaryText` always keeps the original.
- Several countries are read one after another and share **Maximum jobs**, so the first site can use up the whole limit.
- `workArrangement` is set on a minority of ads: 254 of 1,369 in Malaysia and 72 of 1,031 in Singapore in September 2026.
- Descriptions come from a second service that allows about 500 reads per session. The actor uses a single session per run and stops asking at 450, so later ads keep their search fields while `description`, `descriptionHtml` and `expiresAt` stay empty; the `SUMMARY` record reports them as `detailsSkipped`. A run per country or per classification keeps each part under that limit. After a "Too many requests" reply the actor waits 15 seconds, doubling up to 2 minutes, before it asks again.

### FAQ

#### Is it legal to scrape JobStreet?

JobStreet publishes these ads to anyone who opens the site, and the actor reads them through the site's public search and job detail services, slowing down when they ask. It returns job ads only, never candidate profiles. Some ads include an email address for applications: 56 of 1,369 Malaysian and 103 of 1,031 Singaporean descriptions in a September 2026 run. How you use the data is your responsibility.

#### How many ads does each JobStreet site have?

On 11 October 2026 a search without keywords matched 75,162 ads in the Philippines, 66,060 in Singapore, 58,671 in Indonesia and 51,239 in Malaysia. Narrow it with keywords, a location or a classification before a large export, because of the 500-ad limit per query.

### Related scrapers

- [SEEK Jobs Scraper](https://apify.com/deriverge/seek-jobs-scraper)
- [Foundit Jobs Scraper](https://apify.com/deriverge/foundit-jobs-scraper)

### Support

This actor is built and maintained by deriverge s.r.o., a software company based in the Czech Republic. If a run fails or a field you need is missing, please open an issue in the **Issues** tab or write to us at info@deriverge.com. We respond in English and Czech. Runs can be scheduled in Apify Console or started from the **API** tab, which has examples for Python, JavaScript and cURL and works with Make, Zapier, n8n and the Apify MCP server. If the actor saves you time, a short review helps other people find it.

# Changelog

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

# Actor input Schema

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

What to search for, as on JobStreet: a job title, skill or company, for example "accountant", "nurse" or "software engineer". Leave empty for all jobs.

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

Where, as JobStreet writes it: Kuala Lumpur, Penang, Singapore, Metro Manila, Cebu, Jakarta... Leave empty for the whole country.

## `sites` (type: `array`):

Which JobStreet site to search. Pick several to run the search in each country.

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

JobStreet search addresses with your filters, for example https://my.jobstreet.com/accountant-jobs/in-Kuala-Lumpur. Each link is its own search.

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

Keep only jobs in these SEEK classifications. Leave empty for all.

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

Keep only these work types. Leave empty for all.

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

Keep only jobs with these work arrangements. Leave empty for all.

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

Keep only recently listed jobs.

## `minSalary` (type: `integer`):

JobStreet's own salary filter, in the local currency per year. It also uses salaries employers do not show.

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

Order of the results.

## `excludeKeywords` (type: `array`):

Drop jobs whose title or company contains any of these.

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

Adds the full description (text and HTML) and the expiry date for the first 450 jobs of a run, the most one session of the job board serves. The price is the same.

## `newOnly` (type: `boolean`):

Keeps a snapshot per watch name (or per saved task) and returns only jobs that were not there before. Schedule it daily for a job alert.

## `watchName` (type: `string`):

Name of the snapshot used by the new-only mode, for example "sydney-data". Runs from a saved task get one automatically.

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

Hard cap on returned jobs. Searches with more than 500 results are split by classification and work type automatically.

## Actor input object example

```json
{
  "keywords": "accountant",
  "location": "Kuala Lumpur",
  "sites": [
    "MY"
  ],
  "sortBy": "relevance",
  "includeDetails": true,
  "newOnly": false,
  "maxItems": 20
}
```

# Actor output Schema

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

One row per job with company, location, classification, work type, salary and full description.

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

Jobs matching and returned per search, dropped rows, and request counts.

# 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 = {
    "keywords": "accountant",
    "location": "Kuala Lumpur",
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("deriverge/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 = {
    "keywords": "accountant",
    "location": "Kuala Lumpur",
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("deriverge/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 '{
  "keywords": "accountant",
  "location": "Kuala Lumpur",
  "maxItems": 20
}' |
apify call deriverge/jobstreet-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,deriverge/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/WHziQemXVdZiBTCzu/builds/2x4BgToxhXtBsxZy9/openapi.json
