# JobsDB Job Scraper (`parsebird/jobsdb-job-scraper`) Actor

Scrape job listings from JobsDB (Thailand and Hong Kong): titles, companies, salaries, locations, work types, classifications, and posting dates.

- **URL**: https://apify.com/parsebird/jobsdb-job-scraper.md
- **Developed by:** [ParseBird](https://apify.com/parsebird) (community)
- **Categories:** Jobs, Lead generation, Developer tools
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.89 / 1,000 job scrapeds

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### JobsDB Job Scraper — Thailand & Hong Kong Job Listings from JobsDB.com

Scrape job listings from [JobsDB](https://www.jobsdb.com/) across Thailand ([th.jobsdb.com](https://th.jobsdb.com/)) and Hong Kong ([hk.jobsdb.com](https://hk.jobsdb.com/)). Extract job titles, companies, salaries, locations, work types, classifications, and posting dates. Search by keyword, location, and country, or supply your own JobsDB search URL. Export as JSON, CSV, or Excel.

<table><tr>
<td style="border-left:4px solid #1C1917;padding:12px 16px;font-weight:600">
Search JobsDB Thailand or Hong Kong by keyword, city, and posting recency, and get structured job data — including classifications, work arrangements, and company metadata — ready for analysis, monitoring, or integration.
</td>
</tr></table>

##### Copy to your AI assistant

Copy this block into ChatGPT, Claude, Cursor, or any LLM to start using this actor.

```
Apify Actor: parsebird/jobsdb-job-scraper — scrapes JobsDB.com job listings (Thailand and Hong Kong). $0.00099/result on the Free plan ($0.99/1000), $0.00089/result on Bronze/Silver/Gold plans ($0.89/1000). Call via ApifyClient: client.actor("parsebird/jobsdb-job-scraper").call(run_input={"keyword": "software engineer", "country": "hk", "results_wanted": 20}). Inputs: startUrl (string, optional — direct JobsDB search URL, overrides keyword/location/country), keyword (string, default "developer"), location (string, optional), country (enum: th|hk, default "th"), posted_date (enum: anytime|24h|7d|30d, default "anytime"), results_wanted (integer, default 20), maxJobs (integer, default 20 — compatible alias for results_wanted, the higher of the two is used), maxPagesPerList (integer, default 50), collectDetails (boolean, default true — compatibility no-op), proxyConfiguration (object, optional). Output: dataset with id, url, title, company, location, workType, classification, salary, postedAt_relative, postedAt_iso, description_text, description_html, source, list_url, scrapedAt, advertiser, branding, bulletPoints, classifications, employer, isFeatured, locations, roleId, solMetadata, tags, teaser, tracking, workTypes, workArrangements. API docs: https://docs.apify.com/api/v2 Token: https://console.apify.com/settings/integrations
```

### What is JobsDB Job Scraper?

**JobsDB Job Scraper** is an [Apify Actor](https://apify.com/actors) that extracts job listings from [JobsDB](https://www.jobsdb.com/) — the leading job site in Thailand and Hong Kong, part of the SEEK network. It pulls structured data directly from JobsDB's own job-search results, including salaries, work types, classifications, company metadata, work arrangements (on-site/hybrid/remote), and listing tags.

Think of it as a **JobsDB API alternative** — there is no official public API for third parties, but this scraper delivers the same structured job data programmatically. It's built for recruitment analytics, salary benchmarking, and labor market research across Thailand and Hong Kong.

### What can JobsDB Job Scraper do?

- 🔍 **Keyword + location search** — search any job title, skill, or phrase, scoped to a city/region or country-wide
- 🌏 **Two country sites** — switch between Thailand (`th.jobsdb.com`) and Hong Kong (`hk.jobsdb.com`) with a single `country` parameter
- 📅 **Recency filtering** — restrict results to jobs posted in the past 24 hours, 7 days, or 30 days
- 🔗 **Direct search URLs** — paste any JobsDB search URL into `startUrl` to reuse filters already applied on the site
- 🏷️ **Rich listing metadata** — classifications, sub-classifications, work arrangements, bullet-point highlights, and urgency tags
- ⏱️ **Scheduling & API access** — run on autopilot with [Apify Schedules](https://docs.apify.com/platform/schedules) and pull results via the [Apify API](https://docs.apify.com/api/v2) or client libraries
- 📊 **Multiple export formats** — download as JSON, CSV, Excel, XML, HTML, or RSS

### What data can you extract from JobsDB.com?

| Field | Description |
|-------|-------------|
| `id` | JobsDB listing identifier |
| `url` | Job ad URL |
| `title` | Job title |
| `company` | Employer display name |
| `location` | Primary location label |
| `workType` | Primary work type (e.g. Full time) |
| `classification` | Main job classification description |
| `salary` | Salary label when available |
| `postedAt_relative` | Relative posting age (e.g. "3d ago") |
| `postedAt_iso` | ISO posting datetime when available |
| `description_text` | Listing teaser/summary text |
| `classifications` | Classification and sub-classification objects |
| `locations` | Full locations array with hierarchy and country code |
| `workArrangements` | Work arrangement data (e.g. on-site, hybrid) |
| `tags` | Listing tags like "Expiring soon" or "Be an early applicant" |
| `isFeatured` | Featured flag for listing prominence |

Additional fields: `advertiser`, `branding`, `bulletPoints`, `companyProfileStructuredDataId`, `displayStyle`, `displayType`, `employer`, `listingDate`, `listingDateDisplay`, `roleId`, `solMetadata`, `teaser`, `tracking`, `workTypes`, `list_url`, `scrapedAt`.

### How to scrape JobsDB.com

1. **Go to JobsDB Job Scraper** on [Apify Store](https://apify.com/parsebird/jobsdb-job-scraper) and click **Try for free**
2. **Enter a keyword** — e.g. "software engineer", "marketing", "data analyst"
3. **Pick a country** — Thailand or Hong Kong
4. **Optionally set a location** — e.g. "Bangkok" or "Quarry Bay" — and a posting-date filter
5. **Set results wanted** — start with 20 for a quick test, increase for larger datasets
6. **Run the Actor** — click **Start** and wait for results
7. **Export your data** — download as JSON, CSV, or Excel, or access via the [Apify API](https://docs.apify.com/api/v2)

### Input parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `startUrl` | string | No | — | Direct JobsDB search URL. When provided, it overrides keyword/location/country |
| `keyword` | string | No | `developer` | Search keyword for job discovery |
| `location` | string | No | — | Region or city filter for matching jobs |
| `country` | string | No | `th` | Country site selector: `th` (Thailand) or `hk` (Hong Kong) |
| `posted_date` | string | No | `anytime` | Posting time window: `anytime`, `24h`, `7d`, `30d` |
| `results_wanted` | integer | No | `20` | Preferred maximum number of jobs to collect |
| `maxJobs` | integer | No | `20` | Maximum number of jobs to collect (compatible alias) |
| `maxPagesPerList` | integer | No | `50` | Safety cap for pages to process |
| `collectDetails` | boolean | No | `true` | Compatibility toggle retained for existing workflows |
| `proxyConfiguration` | object | No | — | Proxy settings for improved reliability on larger runs |

### Output example

```json
{
  "id": "90538991",
  "url": "https://hk.jobsdb.com/job/90538991",
  "title": "Software Engineer",
  "company": "OpenRice",
  "location": "Quarry Bay, Eastern District",
  "workType": "Full time",
  "classification": "Information & Communication Technology",
  "salary": "",
  "postedAt_relative": "3d ago",
  "postedAt_iso": "2026-02-24T11:03:36.000Z",
  "description_text": "OpenRice is seeking an energetic and passionate talent to be part of the dynamic team.",
  "description_html": null,
  "source": "jobsdb",
  "list_url": "https://hk.jobsdb.com/api/jobsearch/v5/search?siteKey=HK-Main&keywords=software+engineer&page=1&pageSize=20",
  "scrapedAt": "2026-02-28T10:20:00.000Z",
  "companyProfileStructuredDataId": 408363,
  "displayType": "standard",
  "isFeatured": false,
  "listingDate": "2026-02-24T11:03:36Z",
  "roleId": "software-engineer",
  "workTypes": ["Full time"],
  "workArrangements": {
    "data": [{ "id": "1", "label": { "text": "On-site" } }]
  }
}
```

Download results in JSON, CSV, Excel, XML, HTML, or RSS, or access via the [Apify API](https://docs.apify.com/api/v2).

### Use cases

- 📊 **Recruitment intelligence** — build fresh hiring datasets by role, city, and industry across Thailand and Hong Kong
- 💰 **Salary benchmarking** — compare compensation ranges where salary labels are published
- 🎯 **Sales prospecting** — find companies actively hiring and enrich outreach lists with role and classification context
- 📈 **Labor market research** — track classification mix, work arrangements (remote/hybrid/on-site), and posting volume
- 📅 **Job market monitoring** — schedule recurring runs and combine with `posted_date` to track new postings only
- 🔌 **Pipeline integration** — feed job data into Google Sheets, Slack, Zapier, Make, or custom systems via [Apify Integrations](https://docs.apify.com/platform/integrations)

### How it works

1. The Actor resolves your `country`, `keyword`, and `location` into a JobsDB search request (or parses your `startUrl` directly, filling in the required site key if it's missing)
2. It pages through JobsDB's job-search results, 20 jobs per page, up to `maxPagesPerList` or until the requested number of jobs is reached
3. If `posted_date` is set, JobsDB's own recency filter narrows results server-side before pagination even starts
4. Every job is pushed to the dataset as it's collected, so partial results are available even if a run is stopped early

### How to use via API — Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

run = client.actor("parsebird/jobsdb-job-scraper").call(run_input={
    "keyword": "data analyst",
    "location": "Bangkok",
    "country": "th",
    "posted_date": "7d",
    "maxJobs": 40,
})

for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"{job['title']} at {job['company']} — {job['location']} — {job.get('salary') or 'N/A'}")
```

### How to use via API — JavaScript

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

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });

const run = await client.actor('parsebird/jobsdb-job-scraper').call({
    keyword: 'data analyst',
    location: 'Bangkok',
    country: 'th',
    posted_date: '7d',
    maxJobs: 40,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach(job => {
    console.log(`${job.title} at ${job.company} — ${job.location} — ${job.salary || 'N/A'}`);
});
```

### How much does it cost to scrape JobsDB.com?

JobsDB Job Scraper uses [pay-per-event pricing](https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event) — you pay a fixed price per job scraped. Platform usage (compute, proxy) is not charged separately.

**How much does it cost to scrape 1,000 JobsDB jobs?**

$0.99 on the Free plan, or $0.89 on Bronze, Silver, and Gold Apify plans. New users get a free trial with platform credit to try the Actor before committing.

**How much does it cost to scrape 100 JobsDB jobs?**

Around $0.10 on the Free plan — a quick export covering one keyword and city.

### Pricing

| Event | Price per event (Free) | Price per event (Bronze/Silver/Gold) | Price per 1,000 |
|-------|------------------------|----------------------------------------|------------------|
| `job-scraped` | $0.00099 | $0.00089 | **$0.99 / $0.89** |

Each job pushed to the dataset counts as one event.

### Is it legal to scrape JobsDB.com?

This Actor extracts publicly available data from [JobsDB](https://www.jobsdb.com/) — the same job listing data any visitor can see on the search results pages. No login or authentication is used.

Web scraping of publicly available data is generally legal in the United States and the European Union, as established by the [hiQ Labs v. LinkedIn ruling](https://en.wikipedia.org/wiki/HiQ_Labs_v._LinkedIn). For more information, see Apify's guide on [the legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

Users are responsible for ensuring their use of extracted data complies with applicable laws and JobsDB's Terms of Service in their jurisdiction.

### Related Actors

Looking for more job scraping and data extraction tools? Check out these ParseBird actors:

- [Workopolis Job Scraper](https://apify.com/parsebird/workopolis-job-scraper) — Scrape Canadian job listings from Workopolis.com
- [Naukri Jobs Scraper](https://apify.com/parsebird/naukri-jobs-scraper) — Scrape job listings from Naukri.com across India
- [Hiring.cafe Jobs Scraper](https://apify.com/parsebird/hiring-cafe-scraper) — Scrape job listings from Hiring.cafe with 20+ filters
- [Bayt Jobs Scraper](https://apify.com/parsebird/bayt-jobs-scraper) — Scrape Middle East job listings from Bayt.com

Browse all [ParseBird actors on Apify Store](https://apify.com/parsebird).

### FAQ

**What's the difference between `results_wanted` and `maxJobs`?**
They do the same thing — `maxJobs` is kept as a compatible alias for users migrating input JSON from other JobsDB scrapers. If both are set, the Actor uses whichever value is higher.

**Does `collectDetails` fetch full job description pages?**
No. JobsDB's search results already include everything this Actor outputs per job (including the teaser text in `description_text`), so no extra detail-page requests are made. The toggle is kept for input compatibility with existing workflows; `description_html` is a reserved field and always returns `null`.

**Does `posted_date` filter jobs on JobsDB's own server, or after the fact?**
On JobsDB's server — `posted_date` maps to JobsDB's native recency filter, so filtered runs are faster and cheaper since only matching jobs are ever fetched.

**Can I use my own search URLs?**
Yes. Paste a JobsDB search URL into `startUrl` (e.g. `https://hk.jobsdb.com/jobs?siteKey=HK-Main&keywords=project+manager`) and the Actor will use it directly, ignoring `keyword`, `location`, and `country`.

**What happens if a search returns no jobs?**
The Actor finishes successfully with an empty dataset and logs a warning — this isn't treated as an error.

**Why is `salary` sometimes an empty string?**
Not every JobsDB employer publishes a salary range. An empty `salary` means the source listing didn't provide one.

**Can I schedule recurring runs?**
Yes. Use [Apify Schedules](https://docs.apify.com/platform/schedules) to run daily, weekly, or at any interval, and combine with `posted_date` to track only new postings.

**Can I access the data via API?**
Yes. Use the [Apify API](https://docs.apify.com/api/v2) or the official [Python](https://docs.apify.com/api/client/python) and [JavaScript](https://docs.apify.com/api/client/js) client libraries to run the Actor and retrieve results programmatically.

**What export formats are supported?**
JSON, CSV, Excel (XLSX), XML, HTML, and RSS. Download directly from the Apify Console or via the API.

**Is there a free trial?**
Yes. New Apify users get free platform credit to try JobsDB Job Scraper before committing to a paid plan.

**I found an issue or have a feature request.**
Open an issue on the [Issues tab](https://apify.com/parsebird/jobsdb-job-scraper/issues) or contact ParseBird via the Apify Console.

# Actor input Schema

## `keyword` (type: `string`):

Search keyword, job title, or skill phrase for job discovery.

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

Region or city to filter jobs (e.g. "Bangkok", "Quarry Bay"). Leave empty for the whole country.

## `country` (type: `string`):

JobsDB country site to search.

## `posted_date` (type: `string`):

Only return jobs posted within this recency window.

## `startUrl` (type: `string`):

Direct JobsDB search URL (e.g. https://hk.jobsdb.com/jobs?siteKey=HK-Main\&keywords=project+manager). Overrides keyword, location, and country when set.

## `results_wanted` (type: `integer`):

Preferred maximum number of jobs to collect.

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

Maximum number of jobs to collect. Compatible alias for results\_wanted — the higher of the two is used.

## `maxPagesPerList` (type: `integer`):

Safety cap on how many search-result pages to fetch. Each page returns up to 20 jobs.

## `collectDetails` (type: `boolean`):

Compatibility toggle retained for workflows migrating from other JobsDB scrapers. This Actor's listing data already includes everything JobsDB exposes per job, so this toggle does not change output.

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

Proxy settings for improved reliability on larger runs.

## Actor input object example

```json
{
  "keyword": "developer",
  "location": "",
  "country": "th",
  "posted_date": "anytime",
  "startUrl": "",
  "results_wanted": 20,
  "maxJobs": 20,
  "maxPagesPerList": 10,
  "collectDetails": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

# 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 = {
    "keyword": "developer",
    "country": "th",
    "posted_date": "anytime",
    "results_wanted": 20,
    "maxJobs": 20,
    "maxPagesPerList": 10,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("parsebird/jobsdb-job-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 = {
    "keyword": "developer",
    "country": "th",
    "posted_date": "anytime",
    "results_wanted": 20,
    "maxJobs": 20,
    "maxPagesPerList": 10,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("parsebird/jobsdb-job-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 '{
  "keyword": "developer",
  "country": "th",
  "posted_date": "anytime",
  "results_wanted": 20,
  "maxJobs": 20,
  "maxPagesPerList": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call parsebird/jobsdb-job-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,parsebird/jobsdb-job-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/wE7BB9TFxHlkl7YJZ/builds/ZA4yQe0n6SlDQxwdy/openapi.json
