MyCareersFuture Scraper: Singapore Jobs, Salaries, UEN
Pricing
Pay per event
MyCareersFuture Scraper: Singapore Jobs, Salaries, UEN
Pull Singapore job listings from MyCareersFuture with salary, skills, company and UEN. Search, scrape URLs, or watch for new posts.
Pricing
Pay per event
Rating
0.0
(0)
Developer
Arkis
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Security
Limited permissionsShare
MyCareersFuture Jobs + Monitor
This Actor pulls job listings from MyCareersFuture, Singapore's government jobs board. Every result is a full job record: title, company, UEN, SGD salary range, skills, the full description text, closing date, industry (SSIC) code, vacancies, years of experience, education level, region and map coordinates. You can search by keyword, scrape a list of job URLs, or run it on a schedule to return only new listings since the last run. It works over plain HTTP, so runs are fast and cheap. Pricing is $0.002 per job returned, plus the small platform Actor start fee.
Two optional add-ons are off by default: job change alerts for monitor runs, and company profiles for the employers in your results. Each costs $0.002 per item it produces. If you leave them off, nothing changes.
Use cases
1. Recruiter and BD hiring signals
Recruiters can see who's hiring for a role this week. BD teams can match new openings to their CRM by UEN.
A company that posts many jobs, or suddenly starts hiring for a new function, is a good sales or recruiting lead. Run a scheduled monitor for a category (for example Information Technology with positionLevels: ["Manager", "Middle Management"]) or for one competitor's UEN. Send the new jobs to your CRM or Slack through an Apify integration. The companyUen, ssicCode/ssicDescription (industry), companyWebsite, vacancies, views and numberOfApplications fields help you rank leads.
2. Salary research and talent mapping
Pull every posting for a role family (search: "data engineer", maxItems: 5000). Then compare salaryMin/salaryMax by positionLevel, employmentType, educationLevel, minimumYearsExperience, region and skills. MyCareersFuture requires employers to state a salary range, which makes it a useful public source of Singapore pay data.
3. Job alerts
Job seekers and career coaches can schedule mode: "monitor" hourly or daily with their own filters. Each run outputs only postings that are newer than the previous run. Connect the dataset to email, Telegram or a webhook and you have your own job alert.
Input examples
Search with filters
{"mode": "search","search": "product designer","categories": ["Design"],"employmentTypes": ["Full Time", "Permanent"],"minSalary": 5000,"maxSalary": 12000,"maxItems": 300}
One employer's jobs
{ "mode": "search", "postedCompanyUen": "200310022N", "maxItems": 1000 }
Specific job URLs, with the raw description HTML
{"mode": "urls","startUrls": [{ "url": "https://www.mycareersfuture.gov.sg/job/information-technology/java-full-stack-developer-digiworld-technologies-ed8e29d03d2ebf3280cc359c745bc20a" }],"includeDescription": true}
You only need includeDescription if you want the descriptionHtml field. Every result already has descriptionText without it.
Monitor (schedule this)
{"mode": "monitor","search": "software engineer","positionLevels": ["Senior Executive", "Manager"],"postedAfter": "2026-11-01","maxItems": 500}
Monitor with job change alerts and company profiles (both paid add-ons)
{"mode": "monitor","postedCompanyUen": "200310022N","maxItems": 500,"emitJobChanges": true,"enrichCompanyProfiles": true}
Input reference
| Field | Type | Notes |
|---|---|---|
mode | search | urls | monitor | Default search. |
search | string | Free-text keywords. Leave empty to get all jobs, newest first. |
categories, employmentTypes, positionLevels | string[] | Exact MyCareersFuture labels, e.g. "Information Technology", "Full Time", "Professional". |
minSalary / maxSalary | integer (SGD/month) | minSalary is sent to the API. maxSalary is applied by the Actor after fetching. |
postedCompanyUen | string | Employer UEN. |
startUrls | URL list | For urls mode. The 32-hex job id at the end of each URL is used. |
maxItems | integer | Default 500. With emitJobChanges, counts new jobs and change items together. Company profiles don't count. |
postedAfter | ISO date | Keeps only jobs posted on or after this date (day precision, Singapore time). |
includeDescription | boolean | Default false. Only adds the raw descriptionHtml field. Every job already gets a detail fetch, so you get the description text, closing date, SSIC code and everything else either way. |
emitJobChanges | boolean | Default false. Paid add-on, monitor mode only. Also outputs previously seen jobs that changed. See below. |
enrichCompanyProfiles | boolean | Default false. Paid add-on, any mode. Saves one company profile per unique UEN to the companies dataset. See below. |
proxy | proxy configuration | Optional. The API normally works without a proxy. |
How the monitor works
The query parameters (keywords, filters, salary bounds, UEN) are hashed into a key in the named key-value store mycareersfuture-monitor. Changing any filter starts a separate history. The key holds:
- the job IDs seen in earlier runs (up to the 20,000 most recent),
- a watermark: the newest
postedAtdate covered so far, lastRunAt: when the monitor last ran.
The monitor only outputs jobs that are newer than the previous run. It never returns older backlog.
- First run (no saved state): outputs up to
maxItemsof the newest matching jobs and sets the watermark to the newest posting date. IfmaxItemscuts off partway through that day, the Actor keeps reading the rest of that day's listings without outputting them. Those jobs are recorded as seen so the next run doesn't return them as "new". It reads at most 50 pages this way, and these list calls aren't charged. - Later runs: output only jobs that are not in the seen set and were posted on or after the watermark date. Results come newest first, so paging stops at the first page where every job is already seen or older than the watermark. Older jobs that were never seen, for example because they fell outside the first run's
maxItems, are not output. - Limits: if
maxItemsor your spending limit stops a later run before all new jobs are output, the remaining new jobs are not marked as seen. The watermark also isn't moved past them, so the next run delivers them.
postedAfter still applies as an extra lower bound. Posting dates are day precision (Singapore time), so a job posted later on the watermark day still counts as new.
Optional add-ons
Both are off by default. You only pay for them when you turn them on, and only for the items they actually produce.
Job change alerts (emitJobChanges, $0.002 per changed job)
Search results are sorted by posting date, so a job that gets a pay rise, closes early or is reposted usually doesn't show up near the top again. With emitJobChanges: true in monitor mode, the Actor:
- Runs the normal new-job catch-up first (charged as
job, same as before). - Re-fetches the most recently seen jobs for this query by ID. It checks up to
min(1000, maxItems)of them, newest first, and logs the exact number. Jobs that return 404 are skipped. - Compares each one with the snapshot saved last time. The tracked fields are
salaryMin,salaryMax,salaryType,status,closingDate,repostCount,numberOfApplications,vacancies,editCountandtitle. - Outputs a changed job to the default dataset with
itemType: "job-change", achangeslist, the previous snapshot inbefore, and all the normal job fields. It charges onejob-changeevent for each item.
Things to know:
- Snapshots are stored in the same monitor key-value record as the seen IDs, capped at the same 20,000 jobs.
- The first run with the toggle on has no change charges. No snapshots exist yet, so it only records them. Jobs seen before you turned the toggle on get a free baseline snapshot the first time they're re-checked.
viewsis stored but never triggers a change by itself. It moves on almost every run.numberOfApplicationsdoes trigger one, so busy postings can show up as changed on most runs. Keep that in mind on hourly schedules.- Limits:
maxItemsand your spending limit cover new jobs and change items together. If a limit stops the run before a change is output, that job keeps its old snapshot, so the change is reported on the next run. - New jobs get
itemType: "job"when this toggle is on. Every other field is the same as before. - The toggle is ignored in
searchandurlsmode.
Example change item (job fields shortened):
{"itemType": "job-change","changes": [{ "field": "salaryMax", "before": 6000, "after": 7000 },{ "field": "closingDate", "before": "2026-11-19", "after": "2026-12-03" }],"before": { "title": "Java Full-Stack Developer", "salaryMin": 3000, "salaryMax": 6000, "status": "Open", "closingDate": "2026-11-19", "numberOfApplications": 12, "views": 140 },"id": "ed8e29d03d2ebf3280cc359c745bc20a","title": "Java Full-Stack Developer","salaryMax": 7000,"closingDate": "2026-12-03","...": "all other job fields"}
Company profiles (enrichCompanyProfiles, $0.002 per unique company per run)
After the jobs are processed, the Actor takes the unique employer UENs from the jobs it output this run. It uses the hiring company's UEN, or the posting company's UEN if there isn't one. It fetches each company's MyCareersFuture profile once and saves it to a separate named dataset called companies, so your job dataset keeps the same shape.
Each record has itemType: "company-profile", uen, name, descriptionText, descriptionHtml, website, employeeCount, ssicCode/ssicDescription (SSIC 2020 when available), logoUrl, registeredAddress (formatted from the address with purpose registered), the raw addresses list, lastSyncDate, jobsInRun (how many of this run's output jobs came from that company), source and scrapedAt.
- Charged once per UEN per run, not once per job. A 404 or failed lookup isn't charged.
- It respects your spending limit and logs how many companies were enriched.
- The data is company-level only, taken from the public MCF profile. No contact details or personal data are collected.
- The
companiesdataset is a named dataset, so it stays in your account and collects records across runs. Find it under Storage → Datasets in Apify Console, or callGET /v2/datasets/{your-username}~companies/items. Each record has ascrapedAttimestamp, so you can deduplicate byuen.
Output
Each dataset item is one full job record. Search, monitor and URL modes all fetch every job's detail page, so you get the full set of fields by default. Sample:
{"id": "ed8e29d03d2ebf3280cc359c745bc20a","jobPostId": "MCF-2026-1967545","url": "https://www.mycareersfuture.gov.sg/job/information-technology/java-full-stack-developer-digiworld-technologies-ed8e29d03d2ebf3280cc359c745bc20a","title": "Java Full-Stack Developer","companyName": "DIGIWORLD TECHNOLOGIES PTE. LTD.","companyUen": "202003576E","postedCompanyName": "DIGIWORLD TECHNOLOGIES PTE. LTD.","companyWebsite": "www.digiworld.sg","companyLogoUrl": "https://static.mycareersfuture.gov.sg/images/company/logos/baa07d84dc07725220e9c1495111df86/DIGIWORLD%20TECHNOLOGIES%20PTE.%20LTD..jpg","companyEmployeeCount": null,"ssocCode": "21522","occupationId": "OCC014584","ssicCode": "62011","ssicDescription": "DEVELOPMENT OF SOFTWARE AND APPLICATIONS (EXCEPT GAMES AND CYBERSECURITY)","salaryMin": 3000,"salaryMax": 6000,"salaryCurrency": "SGD","salaryType": "Monthly","isHideSalary": false,"employmentType": "Contract","positionLevel": "Professional","categories": ["Information Technology"],"skills": ["JSP", "REST APIs development", "Java Applications", "Hibernate Framework", "JPA", "Backend Development"],"keySkills": [],"minimumYearsExperience": 4,"educationLevel": "Bachelor's degree or equivalent","flexibleWorkArrangements": [],"workingHours": null,"shiftPattern": null,"address": "10 UBI CRESCENT, UBI TECHPARK, Singapore 408564","districts": ["D14 Geylang, Eunos"],"region": "Central","lat": 1.32627524038924,"lng": 103.896130679533,"vacancies": 4,"postedAt": "2026-11-05","originalPostedAt": "2026-11-05","updatedAt": "2026-11-05T07:11:06.000Z","closingDate": "2026-11-19","numberOfApplications": 0,"views": 1,"repostCount": 0,"editCount": 0,"isPostedOnBehalf": false,"status": "Open","descriptionText": "We are looking for a Java Full-Stack Developer with 4–6 years of experience in developing web-based applications ...","source": "mycareersfuture","scrapedAt": "2026-11-05T07:34:25.571Z"}
descriptionHtml (the raw HTML of the description) is added only when includeDescription is true. All other fields come back by default. When a job is posted on behalf of another employer, companyName/companyUen refer to the hiring company and postedCompanyName is the agency.
Pricing (pay per event)
| Event | Price |
|---|---|
Actor start (apify-actor-start, charged by the Apify platform) | about $0.01 per GB of memory |
job: charged per job scraped and saved to the dataset | $0.002 |
job-change: optional, per changed job output (emitJobChanges, monitor only) | $0.002 |
company-profile: optional, per unique company UEN enriched per run (enrichCompanyProfiles) | $0.002 |
1,000 jobs cost about $2, plus the start fee. The detail fetch for each job is included in the per-job price. The Actor respects your maximum spend per run and stops cleanly when the limit is reached. A monitor run that finds no new jobs costs only the start fee. If you leave both add-ons off, you are never charged for job-change or company-profile. With emitJobChanges on, re-checking unchanged jobs is free. You pay only for jobs that changed.
Output fields
| Field | Description |
|---|---|
id, jobPostId, url | Job identifiers and the public job page |
title, categories, skills, keySkills | Role, MCF categories, all listed skills, and the skills the employer marked as key |
companyName, companyUen, postedCompanyName | Hiring company, its UEN, and the posting agency if different |
companyWebsite, companyLogoUrl, companyEmployeeCount | Company website, logo image URL and headcount (when MCF has them) |
ssocCode, occupationId | Occupation code (SSOC) and MCF occupation id |
ssicCode, ssicDescription | Industry code (SSIC 2020) and its description |
salaryMin, salaryMax, salaryCurrency, salaryType, isHideSalary | Advertised salary range, and whether the employer hides it on the site |
employmentType, positionLevel, minimumYearsExperience, educationLevel | Role terms and requirements (education is decoded from the SSEC code) |
flexibleWorkArrangements, workingHours, shiftPattern | Working arrangements, when stated |
address, districts, region, lat, lng | Location, district, region and map coordinates |
vacancies | Number of openings |
postedAt, originalPostedAt, updatedAt, closingDate, status | Posting dates and status |
numberOfApplications, views, repostCount, editCount | Engagement and posting history reported by MCF |
isPostedOnBehalf | true when an agency posted on behalf of the hiring company |
descriptionText, descriptionHtml | Job description as plain text (always), and raw HTML (only with includeDescription) |
source, scrapedAt | Provenance |
Notes
- Every job gets a detail request. Up to about 6 run at a time, with exponential backoff on HTTP 429 and 5xx responses.
- Results are deduplicated by job ID within a run.
Legal
This Actor reads publicly available job listings. It does not log in or access private data. It is not affiliated with MyCareersFuture, Workforce Singapore or the Singapore Government. You are responsible for making sure your use of the data complies with the MyCareersFuture terms of use, Singapore's PDPA and any other law that applies to you.
Support
Found a bug or need a field that is missing? Open an issue on the Actor's Issues tab.