JobThai Scraper - Thailand Job Postings
Pricing
from $1.00 / 1,000 item extracteds
JobThai Scraper - Thailand Job Postings
Scrape job postings from JobThai and get each one as JSON with salary min/max in THB, pay period, seniority, required years of experience, skills and remote status parsed by AI. Handles Thai-language postings. First 10 items enriched free.
Pricing
from $1.00 / 1,000 item extracteds
Rating
0.0
(0)
Developer
Kusol Sukhakul
Maintained by CommunityActor stats
0
Bookmarked
3
Total users
2
Monthly active users
4 days ago
Last modified
Share
Thailand Job Postings Scraper
Scrapes Thai job postings from JobThai and returns each one as structured JSON, with salary range, seniority, required experience, skills and remote status normalized by an AI step into fields you can filter and aggregate.
No setup, no API key
Run it with the defaults. Every posting comes back with the full ai block
filled in; there is no key to request and nothing to configure. You pay per
posting returned and per posting the AI step enriched successfully, at the
prices on this listing, and nothing for an AI step that fails. To see the
output before a large run, set maxItems to 10 — about $0.03 at the current
prices.
enrich: false returns the postings without the AI step, and without its
charge.
Sample output
One item, exactly as it lands in the dataset:
{"url": "https://www.jobthai.com/th/company/job/1936578","source": "jobthai","scrapedAt": "2026-09-05T08:44:49+00:00","title": "SALE & RECEPTION","company": "ANY1 Fitness & Sports (บริษัท ธนสุวรรณ กรุ๊ป จำกัด)","location": "บางแค, กรุงเทพมหานคร, TH","employmentType": "FULL_TIME","salaryText": "11000-15000 THB MONTH","postedAt": "2026-09-05T08:41:54.000Z","description": "รายละเอียดงาน / หน้าที่รับผิดชอบ:- ต้อนรับ ให้ข้อมูลเกี่ยวกับบริการ สิทธิประโยชน์ และแพ็กเกจสมาชิกแก่ลูกค้าที่เข้ามาใช้บริการ- นำเสนอขายแพ็กเกจสมาชิก/คอร์สออกกำลังกายให้บรรลุเป้าหมายยอดขาย …","jobId": "1936578","ai": {"salary_min_thb": 11000,"salary_max_thb": 15000,"salary_period": "monthly","seniority": "entry","experience_years_min": null,"skills": ["การต้อนรับ","การนำเสนอขาย","การดูแลงานเอกสาร","การลงทะเบียนสมาชิก","การรับชำระเงิน","การติดตามลูกค้า","การประสานงาน","การส่งรายงานยอดขาย"],"remote_status": "onsite"}}
Everything outside ai is read from the posting. Everything inside ai is
inferred from the posting text by the AI step. When enrichment is turned off,
fails, or times out, ai is null, an aiError field says why, and the
posting is returned anyway.
Note: the whole object above,
aiincluded, is verbatim from a livemake actor-runagainst jobthai.com and the deployed enrichment service on 2026-09-05, with the description truncated for length. Of the 3 items that run scraped, this one enriched cleanly; one of the other two hit a transient503from the enrichment service and came back withai: nulland anaiError, per the "return the raw item uncharged for AI" rule below.
Pay only for what changed
Turn on incremental and schedule the Actor daily or weekly. The first run
returns everything; each later run returns only postings that are new or
whose content changed since the last run with the same stateName, marked
changeType: "NEW" or "UPDATED". Unchanged postings are skipped: not
returned, not charged, not sent to the AI step.
{ "incremental": true, "stateName": "weekly-eng" }
- Use a different
stateNamefor each separate search or schedule. - The memory lives in a key-value store in your own Apify account and forgets postings not seen for 30 days.
- A posting whose AI step failed is not remembered, so the next run tries it again.
- Closed postings are not reported; a posting that disappears is simply not returned.
Input
| Option | Type | Default | What it does |
|---|---|---|---|
startUrls | array | JobThai job listing page | Listing or job pages to start from. Listing pages are followed to the jobs they link to. |
maxItems | integer | 100 | Hard cap on items returned. Never exceeded. Maximum 1000. |
enrich | boolean | true | Turns the paid AI step on or off. |
enrichFields | array | all fields | Restricts enrichment to named fields: salary_min_thb, salary_max_thb, salary_period, seniority, experience_years_min, skills, remote_status. |
incremental | boolean | false | Return only postings that are new or changed since the last run with the same stateName. Unchanged ones are not charged. |
stateName | string | default | Separate incremental memories, e.g. one per schedule. |
talariaToken | string (secret) | none | Not needed on Apify. Only for running the Actor outside Apify, or against your own talariaBaseUrl. |
talariaBaseUrl | string | https://talaria.skusol.com | Point the AI step at your own endpoint instead. |
requestIntervalSecs | integer | 1 | Minimum seconds between two requests to the target site. |
maxRetries | integer | 3 | Retries per page before it is skipped. |
respectRobotsTxt | boolean | true | Stops the crawl if robots.txt disallows it. |
Use cases
- Salary benchmarking. Postings state salary as free text, in several
formats and two languages.
salary_min_thb,salary_max_thbandsalary_periodgive you numbers you can average per role and per province. - Skill demand tracking. Run the same query weekly and count
skillsacross items to see which tools employers are actually asking for, rather than which ones a survey says they want. - Recruitment lead lists. Filter by
seniority,remote_statusandexperience_years_minto find the companies hiring for the roles you place, with a link back to each posting.
Pricing
Prices are set on the Apify Store listing; this table says what triggers each event.
| Event | Charged when |
|---|---|
apify-actor-start | Once, when a run starts. |
item-scraped | Once per job posting after it has been written to the dataset. A posting that fails to parse is never pushed and never charged. |
ai-enriched-item | Once per posting whose AI fields came back valid. Enrichment that fails, times out or is turned off is not charged. |
Two rules the actor holds to: nothing is charged before the thing it pays for exists, and when a run reaches its maximum cost the run ends cleanly with everything produced so far.
Limitations
- Rate. With enrichment on, throughput is bounded by the AI service. The
Actor enriches three postings at a time, roughly 15 per minute, so a
100-item run takes about 7 minutes. With
enrich: falsethe limit is the polite crawl delay, one page per second by default. - Coverage. JobThai only. Listing pages are followed one level to the job
pages they link to; pagination beyond the pages you pass in
startUrlsis not crawled. Postings missing a title or description are skipped rather than returned half-empty. - Freshness. Each item is a snapshot at
scrapedAt. Withoutincremental, a posting scraped on two runs appears, and is charged, on both; with it, only new or changed postings come back. - AI fields are inferred.
aivalues come from a language model reading the posting. A field the posting does not state comes backnullorunknownrather than a guess, but the values are not verified against any other source.salaryTextkeeps the original wording so you can check. - Personal data. Only posting content is collected: role, employer, location, salary, requirements. Contact people named on a posting are not extracted.
- robots.txt. With
respectRobotsTxton, a disallow ends the crawl instead of working around it.
Development
make actor-setup # once, needs the networkmake build # go build/vet/test, then compileall and pytest for the actormake actor-run # local run in pay-per-event test mode
The test suite runs offline. It uses fake pages, a fake enrichment service, and the Apify SDK's local pay-per-event mode, and asserts on charge counts and ordering.