JobStreet Job Scraper - Deduplicated, Pay Once Per Job (SEA) avatar

JobStreet Job Scraper - Deduplicated, Pay Once Per Job (SEA)

Pricing

Pay per event

Go to Apify Store
JobStreet Job Scraper - Deduplicated, Pay Once Per Job (SEA)

JobStreet Job Scraper - Deduplicated, Pay Once Per Job (SEA)

Scrape JobStreet jobs in Malaysia, Singapore, Philippines and Indonesia: title, company, salary, full description, applicants, employer industry. Complete past the 550-result wall, deduplicated across runs, billed once per job. Also covers SEEK and JobsDB.

Pricing

Pay per event

Rating

0.0

(0)

Developer

Automation Craft

Automation Craft

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 days ago

Last modified

Share

Get every matching job from JobStreet (my.jobstreet.com, sg.jobstreet.com, ph.jobstreet.com and id.jobstreet.com) as clean JSON, CSV or Excel: title, employer, salary, full description, applicant numbers, employer industry and size, exact posting dates and structured locations. Built to be complete and fair:

  • Complete. JobStreet stops every search at 550 results, even when it reports thousands. This Actor detects that wall and automatically splits the search (by sub-category, work type, salary band and region) until every matching job is reached. Most other scrapers silently return the first 550.
  • Deduplicated, billed once. Duplicates inside a run are removed. Give your search a memory name and jobs you already received are skipped in every later run. You never pay twice for the same job.
  • Filter by employer, not just by job. Industry (the site's own employer taxonomy), employer name, rating, recruitment agencies on or off, private advertisers on or off.
  • Honest about what you get. Every run ends with a summary of coverage and how often each field was populated. The table below tells you what to expect per market before you spend a cent.

Also covers SEEK (Australia, New Zealand) and JobsDB (Hong Kong, Thailand): pick any of the eight markets in the "Countries" dropdown. If you mostly need those markets, the sibling listings JobStreet Job Scraper and JobsDB Job Scraper are the same engine with those defaults.

30-second start

  1. Pick Countries (🇲🇾 Malaysia, 🇸🇬 Singapore, 🇵🇭 Philippines, 🇮🇩 Indonesia are preselected) and, if you like, Locations from the list or type your own ("Kuala Lumpur").
  2. Pick Job categories (for example "Marketing & Communications") and/or type Keywords ("digital marketing").
  3. Optional: Employer industries (for example "Online Media & eCommerce", "Specialty Retail").
  4. Choose Posted within (last 24 hours, 3, 7, 14 or 30 days).
  5. Give it a Memory name if you will run it again and only want new jobs.
  6. Start. Download JSON, CSV or Excel from the Dataset tab, or read it through the API.

Prices: $0.60 per 1,000 jobs found, plus $0.30 per 1,000 for full job details and $0.10 per 1,000 for employer profiles (only when the employer actually has one). A complete record therefore costs $1.00 per 1,000 jobs. Duplicates, filtered-out jobs and empty profiles are free. There is no start fee.

What you get, per market

AustraliaNew ZealandMalaysia, Singapore, Philippines, IndonesiaHong Kong, Thailand
Job title, employer, teaser, bullet points, category, work type, listing date, URLalwaysalwaysalwaysalways
Full description (HTML, text, Markdown, sections)always with job detailsalwaysalwaysalways
Salary shown on the ad, parsed to min / max / period / currency56% of ads show a salary; usually per year, often "+ super"similar to Australiamost ads show a salary, usually per month (RM, S$, PHP, Rp)many ads show a salary per month (HK$, THB)
Applicant count, share with resume and cover letterappears a few hours after posting; 97% of adssamesamesame
Employer industry, size, website, rating, reviews61% of ads link to an employer profilesimilarsimilar; profiles are common for larger employerssimilar
Suburb / district, region, stateyesyes (region)yes (state or region)yes (district and area)
Postcode96% of ads64% of adsnot published on the sitenot published on the site
On-site / hybrid / remotewhen declared by the advertisersamesamesame
Screening questionswhen the advertiser uses the site's apply flowsamesamesame
Labels in the local languagen/an/aIndonesia: yes (set Label language)Thailand and Hong Kong: yes

Things this Actor deliberately does not do: it does not reveal salary ranges the advertiser chose to hide, does not collect recruiter contact details from profile pages, does not log in or touch anything behind a login, and does not cover Zhaopin (China), which runs on a different platform.

How the filters map to the site

InputWhat it does
CountriesWhich sites to search. Each country is one dataset; results carry market, country and brand.
LocationsRegions and cities exactly as the site names them (dropdown), or anything you would type into the site's location box. Unresolved entries appear in unresolvedLocations in the run summary.
Job categories / sub-categoriesThe site's classification taxonomy (30 categories, 394 sub-categories). Labels or ids both work through the API.
KeywordsThe site's keyword search.
Work type, work arrangement, salary from/toThe site's own filters. The salary filter also matches ads that hide their salary.
Posted within1 / 3 / 7 / 14 / 30 days use the site's filter. Any other number of days through the API is applied exactly. postedAfter / postedBefore are exact ISO timestamps.
Employer industriesMatched against the employer's company profile. Decide with "Employers without a known industry" whether profile-less employers are excluded (precise) or included (complete).
Must contain / must not containPlain-text filters over title, teaser, bullets, employer and (with job details) the full description.
Search URLsPaste any search, job or company URL from SEEK, JobStreet or JobsDB (old or new domains).
Memory nameThe key that makes repeat runs return only new jobs.

Output

One item per job. Nested objects for developers (salary, classifications, descriptionSections) and flat fields for spreadsheets (salaryMin, salaryMax, state, postcode, companyIndustry...). The last item of every run is a run-summary with coverage, fill rates, filter counts and charges.

Most useful fields:

FieldMeaning
id, url, market, country, brandIdentity. sourceMarket shows where a cross-listed ad originated.
title, normalisedRoleTitle, teaser, bulletPoints, descriptionText, descriptionHtml, descriptionMarkdown, descriptionSectionsThe ad.
listedAt, createdAt, updatedAt, expiresAtISO timestamps (UTC).
classification, subclassification (+ ids)The site's job taxonomy.
location, suburb, area, city, state, stateCode, postcode, locationHierarchyStructured location.
workType, workArrangementFull time / part time / contract / casual; on-site / hybrid / remote.
salaryLabel, salaryMin, salaryMax, salaryPeriod, salaryCurrency, salary.includesSuper, salary.parseConfidence, salary.annualisedMin/MaxSalary as shown and as parsed.
applicantCount, applicantsWithResumePct, applicantsWithCoverLetterPct, applicantVolumeDemand signals.
advertiserName, advertiserId, advertiserIsVerified, isPrivateAdvertiser, isRecruitmentAgencyWho posted it.
companyName, companyIndustry, companySize, companyWebsite, companyPrimaryLocation, companyDescription, companyRating, companyReviewCount, companyAwards, companyProfileUrl, companyLogoUrl, companyHasProfileThe employer.
screeningQuestions, isLinkOut, isSponsored, isFeatured, tagsApplication details and ad flags.
ecommerceSignals, seniority, detectedSkills, visaSponsorship, isRemoteFriendlyDerived signals from the text.
emails, phonesOnly when "Extract emails and phone numbers" is on.
changeType, isDuplicate, firstSeenAt, lastSeenAt, contentHash, searchShardDedup and provenance.

Sample item from a live run:

{
"id": "94222698",
"url": "https://my.jobstreet.com/job/94222698",
"shareUrl": "https://my.jobstreet.com/job/94222698?tracking=SHR-WEB-SharedJob-asia-5",
"market": "MY",
"countryCode": "MY",
"country": "Malaysia",
"brand": "JobStreet",
"sourceMarket": "MY",
"title": "Marketing Executive",
"normalisedRoleTitle": "Marketing Executive",
"teaser": "Plan and execute social media campaigns, recruit influencers and affiliates, and support offline marketing activities.",
"bulletPoints": [
"Competitive salary with big fat bonuses !",
"Support dynamic team in innovative business solutions !",
"Real growth, not just talk - you’ll get hands-on exposure !"
],
"descriptionText": "About the role\nThis role involves managing social media content across multiple platforms, executing marketing campaigns, and supporting product launches and promotional activities. You will coordinate content creation, monitor performance metrics, conduct market research, and maintain campaign documentation.\nKey responsibilities\n- Plan and schedule social media content across Instagram, TikTok, a ...",
"status": "Active",
"isExpired": false,
"isLinkOut": false,
"isFeatured": false,
"isSponsored": false,
"adType": "ORGANIC",
"displayTags": [],
"tags": [],
"roleId": "marketing-executive",
"hasRoleRequirements": true,
"screeningQuestions": [
"How many years' experience do you have as a Business Operations Executive?",
"Are you willing to undergo a pre-employment background check?"
],
"videoUrl": null,
"listedAt": "2026-08-26T11:40:43.598Z",
"listedAtDisplay": "4d ago",
"createdAt": "2026-08-26T11:40:18.295Z",
"updatedAt": "2026-08-26T11:40:43.598Z",
"expiresAt": "2026-09-25T13:59:59.999Z",
"classificationId": "6008",
"classification": "Marketing & Communications",
"subclassificationId": "6009",
"subclassification": "Brand Management",
"classifications": [
{
"classificationId": "6008",
"classification": "Marketing & Communications",
"subclassificationId": "6009",
"subclassification": "Brand Management"
}
],
"location": "Petaling Jaya, Selangor",
"locationLabel": "Petaling Jaya, Selangor",
"suburb": "Petaling Jaya",
"area": null,
"city": "Petaling",
"state": "Selangor",
"stateCode": null,
"postcode": null,
"locationHierarchy": [
"Petaling Jaya Selangor",
"Selangor"
],
"workType": "Full time",
"workTypes": [
"Full time"
],
"workTypeId": 242,
"workArrangement": "On-site",
"workArrangements": [
"On-site"
],
"salary": {
"label": "RM 4,000 – RM 4,500 per month",
"currency": "MYR",
"min": 4000,
"max": 4500,
"period": "month",
"includesSuper": null,
"isDisclosed": true,
"parseConfidence": 0.85,
"annualisedMin": 48000,
"annualisedMax": 54000
},
"salaryLabel": "RM 4,000 – RM 4,500 per month",
"salaryMin": 4000,
"salaryMax": 4500,
"salaryCurrency": "MYR",
"salaryPeriod": "month",
"applicantCount": 141,
"applicantsWithResumePct": 100,
"applicantsWithCoverLetterPct": 29,
"applicantVolume": "high",
"advertiserId": "63022078",
"advertiserName": "Glowith Global Sdn Bhd",
"advertiserIsVerified": true,
"advertiserRegistrationDate": "2025-04-23T11:49:39.338Z",
"isPrivateAdvertiser": false,
"isRecruitmentAgency": false,
"companyName": "Glowith Global Sdn Bhd",
"companyId": null,
"companySlug": null,
"companyProfileUrl": null,
"companyJobsUrl": "https://my.jobstreet.com/jobs?companyprofilestructureddataid=3151002",
"companyLogoUrl": "https://bx-branding-gateway.cloud.seek.com.au/6e76a485-8ff9-4ac5-ab4a-7c64f6a3074f.1/jdpLogo",
"companyCoverUrl": "https://image-service-cdn.seek.com.au/080a89f74c544035b8da82afbb6b9db52c37bcb9/8f50f8545b48866f30b0f8b02b06fdae349eb650",
"companyIndustry": null,
"companyIndustryRaw": null,
"companySize": null,
"companyWebsite": null,
"companyPrimaryLocation": null,
"companySpecialities": null,
"companyDescription": null,
"companyRating": null,
"companyReviewCount": null,
"companySalaryRating": null,
"companyAwards": [],
"companyHasProfile": false,
"companyOrgId": "3151002",
"phoneNumberOnAd": null,
"ecommerceSignals": [
"e-commerce",
"marketplace"
],
"seniority": "mid",
"detectedSkills": [
"TikTok",
"Canva",
"social media",
"influencer"
],
"visaSponsorship": null,
"isRemoteFriendly": false,
"detailFetched": true,
"companyProfileFetched": false,
"contentHash": "e6079cec68327d39",
"searchShard": "root/sub6009",
"searchRank": 1,
"isDuplicate": false,
"changeType": "NEW",
"firstSeenAt": "2026-08-31T08:54:14.180Z",
"lastSeenAt": "2026-08-31T08:54:14.180Z",
"scrapedAt": "2026-08-31T08:54:14.180Z"
}

Using the API

Same input as the form. Ids and labels are interchangeable.

curl -X POST "https://api.apify.com/v2/acts/automation_craft~jobstreet-job-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"markets": ["MY"],
"classifications": ["6008"],
"postedWithinDays": "7",
"companyIndustries": ["Online Media & eCommerce", "Specialty Retail"],
"unknownIndustryPolicy": "exclude",
"dedupMemoryName": "ecommerce-marketing-weekly",
"includeDetails": true,
"includeCompanyProfile": true,
"maxItems": 500
}'
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation_craft/jobstreet-job-scraper').call({
searchUrls: ['https://my.jobstreet.com/digital marketing-jobs'.replace(' ', '-')],
postedWithinDays: '3',
dedupMemoryName: 'daily-digital marketing'.replace(' ', '-'),
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const jobs = items.filter((i) => i.type !== 'run-summary');
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("automation_craft/jobstreet-job-scraper").call(run_input={
"markets": ["MY"], "keywords": "digital marketing", "postedWithinDays": "7", "maxItems": 200})
items = [i for i in client.dataset(run["defaultDatasetId"]).iterate_items() if i.get("type") != "run-summary"]

Scheduling: create a Schedule in Apify (daily or weekly) with a memory name set; each run then delivers only the jobs that appeared since the previous run.

Notes on the 550-result wall

JobStreet returns at most 550 results per distinct search and then silently returns empty pages, no matter how many jobs it says exist. This Actor probes the total, and when a search is over the wall it splits it into narrower searches (sub-category, then work type, then salary band, then region) and merges the results, removing duplicates. The run summary reports slices, uniqueJobsSeen and slicesTruncated (which should be empty). Very broad searches (for example a whole country with no filters) can take a few minutes; narrow them with a category or a time window when you can.

Fair use

This Actor reads publicly available listings and the public employer profiles the site publishes, at a polite request rate (4 per second by default). It never logs in. Use the data in line with the site's terms and the laws that apply to you.

Support

Something missing or wrong? Open an issue on the Actor's Issues tab. Fixes usually ship within a day.