# MyCareersFuture Jobs Scraper (`khadinakbar/mycareersfuture-jobs-scraper`) Actor

Scrape public Singapore MyCareersFuture.gov.sg jobs by keyword, UEN, filters, or job UUID/URL. Returns salary, company UEN, skills, and location. HTTP-only, no login, MCP-ready.

- **URL**: https://apify.com/khadinakbar/mycareersfuture-jobs-scraper.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** Jobs, Lead generation, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 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.

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

## MyCareersFuture Jobs Scraper

Extract **public Singapore job listings** from MyCareersFuture into structured JSON for recruiting shortlists, salary research, employer hiring intel, and MCP/API agents. Search by keyword, filter by employer ACRA UEN or taxonomy, or paste a job UUID. Each row includes title, SGD salary band, posted company name and UEN, skills, location, and a canonical job link — HTTP-only against the public v2 API, with no Singpass and no login.

Run it on Apify for scheduling, API access, Residential proxy fallback, and Pay per event billing with a clear `maxItems` cost cap.

### Best fit

Choose this Actor when you need public MyCareersFuture postings with **SGD salary bands** and **ACRA UEN** on the employer. It works well for Singapore software, healthcare, finance, and government-board monitoring workflows where FCF-style salary disclosure and company identity matter.

For multi-market Indeed jobs, continue with [Indeed Job Scraper](https://apify.com/khadinakbar/indeed-job-scraper) when the next step is Indeed search cards.
For Google Jobs cards across countries, then use [Google Jobs Scraper](https://apify.com/khadinakbar/google-jobs-scraper) for SERP-style job discovery.
For LinkedIn job cards with salary and skills context, continue with [LinkedIn Jobs Scraper](https://apify.com/khadinakbar/linkedin-jobs-scraper) when the source board is LinkedIn.
For India tech hubs, continue with [Naukri Jobs Scraper](https://apify.com/khadinakbar/naukri-jobs-scraper) when the workflow moves to Naukri.com.

### Workflow story

A Singapore talent-intel analyst sets `search` to `software engineer`, `maxItems` to `10`, and keeps `sortBy` on `new_posting_date`. The Actor pages the public MyCareersFuture jobs API, writes one validated row per UUID with salaryMin/salaryMax, postedCompanyUen, skills, and jobUrl, then the analyst filters UENs into a watchlist and exports CSV into their compensation sheet.

### How it works

1. Collects keyword, UEN, UUID/URL, or taxonomy/salary filter inputs
2. Calls the public MyCareersFuture `v2/jobs` search and optional `v2/jobs/{uuid}` detail endpoints over HTTPS
3. Normalizes rows (HTML→text, public fields only), charges `job-scraped`, then `pushData`
4. Writes `OUTPUT` and `RUN_SUMMARY` with an honest outcome (`COMPLETE`, `PARTIAL`, `VALID_EMPTY`, `INVALID_INPUT`, or `UPSTREAM_FAILED`)

### Input example

```json
{
  "search": "software engineer",
  "maxItems": 5,
  "sortBy": "new_posting_date"
}
```

Employer UEN mode:

```json
{
  "companyUens": ["201816453D"],
  "maxItems": 20
}
```

| Field | What it controls |
|---|---|
| `search` / `searchQueries` | Keyword search against titles, skills, and descriptions |
| `companyUens` | ACRA UEN list — jobs where posted company UEN matches |
| `jobIds` / `startUrls` | Exact 32-character job UUIDs or UUID job URLs (prefer UUID page links) |
| `categories` / `employmentTypes` / `positionLevels` | Exact MyCareersFuture enum labels |
| `salaryFrom` / `salaryTo` | Monthly SGD salary filter bounds |
| `sortBy` | `new_posting_date` (default) or `min_monthly_salary` |
| `maxItems` | Hard unique-job cap (default 50; prefill 5) |
| `fetchDetails` / `includeScreeningQuestions` | Optional detail re-fetch / screening questions |

### Output fields

| Field | Description |
|---|---|
| `title` + `jobUrl` | Public job title and MyCareersFuture page |
| `salaryMin` / `salaryMax` / `salaryType` | Advertised SGD salary band when published |
| `postedCompanyName` + `postedCompanyUen` | Posting employer and ACRA UEN |
| `categories` / `employmentTypes` / `positionLevels` | Taxonomy labels |
| `skills` | Skill labels (key-skill flags when present) |
| `postedDate` / `expiryDate` | Posting and expiry dates |
| `source` / `scrapedAt` | Provenance (`mycareersfuture-v2`) and scrape time |

### Example output

You can download the dataset in JSON, HTML, CSV, or Excel.

```json
{
  "uuid": "8914f4821a02ec72243d855f62a79072",
  "jobPostId": "MCF-2026-1579008",
  "title": "Software Engineer",
  "jobUrl": "https://www.mycareersfuture.gov.sg/job/8914f4821a02ec72243d855f62a79072",
  "salaryMin": 5000,
  "salaryMax": 8000,
  "salaryType": "Monthly",
  "postedCompanyName": "Example Pte Ltd",
  "postedCompanyUen": "201816453D",
  "categories": ["Information Technology"],
  "employmentTypes": ["Full Time"],
  "positionLevels": ["Professional"],
  "skills": [{ "skill": "JavaScript", "isKeySkill": true }],
  "postedDate": "2026-09-01",
  "expiryDate": "2026-10-01",
  "source": "mycareersfuture-v2",
  "scrapedAt": "2026-09-21T12:00:00.000Z"
}
```

### Pricing

#### Startup billing and empty runs

The `apify-actor-start` event costs **$0.00005 per startup unit**. Apify charges one startup unit per GB of allocated memory, with a minimum of one unit, so a 2 GB run incurs two units. This startup charge still applies when input is invalid, no results are found, or an upstream request fails. Statements about free, unbilled, or skipped results refer only to the corresponding result event; they do not waive the startup charge. Apify platform usage is included in the event prices and is not passed through as an additional customer charge. Check the live [Pricing tab](https://apify.com/khadinakbar/mycareersfuture-jobs-scraper/pricing) for current events, tiers, and rates. Result limits cap result events, not the entire run cost.

This Actor uses **Pay per event** with **platform usage included**. The live Pricing tab is the source of truth.

- `apify-actor-start`: **$0.00005** per run
- `job-scraped`: **$0.003** per unique persisted job row

A five-job sample is about **$0.015** in result events with Apify platform usage included. Duplicate UUIDs and rows past `maxItems` are billed once per unique saved job.

### API example

```bash
curl "https://api.apify.com/v2/acts/khadinakbar~mycareersfuture-jobs-scraper/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"search":"software engineer","maxItems":5,"sortBy":"new_posting_date"}'
```

### Best results

- Prefer `maxItems` ≤ 20 while testing filters so you can validate enums before a larger harvest.
- Category / employment / position values work best when they match MyCareersFuture labels exactly (for example `Information Technology`, `Full Time`); mismatched enums finish as `INVALID_INPUT`.
- Copy the **UUID** from the job page URL (`/job/<32-hex>`). Prefer UUID detail links for the public API detail path.
- Leave `fetchDetails` off for lean search harvests; enable it when you want the freshest detail payload or screening questions.
- Empty but valid searches finish successfully with `VALID_EMPTY` and zero `job-scraped` charges.
- Hitting `maxItems` finishes as `PARTIAL` by design — raise the cap when you need a larger sample.

### Use with AI agents (Apify MCP)

> Search MyCareersFuture for software engineer jobs in Singapore. Return title, salaryMin, salaryMax, postedCompanyName, postedCompanyUen, and jobUrl. Cap at 5 jobs.

Connect via <https://mcp.apify.com>. Tool name shape: `apify--mycareersfuture-jobs-scraper`. Read `OUTPUT.outcome` and `itemsPushed` before treating an empty dataset as an outage. Cost signal: about **$0.003** per saved job with Apify platform usage included.

### Builder's note

I built this around the public MyCareersFuture `v2/jobs` JSON surface because I found that salary bands and ACRA UEN already arrive without a browser. I learned that enum-exact filters, UUID-only detail URLs, and honest `PARTIAL` when `maxItems` stops pagination matter more for callers than fighting Cloudflare. My goal was one validated public job row per UUID with PDPA-safe fields only.

### Legal disclaimer

MyCareersFuture, SkillsFuture Singapore, and related Government of Singapore marks are trademarks of their respective owners. This independent Actor is not affiliated with, associated with, or endorsed by SkillsFuture Singapore, MyCareersFuture, GovTech, or the Government of Singapore. SkillsFuture Singapore and MyCareersFuture are trademarks of their respective owners. This independent Actor is not affiliated with, associated with, or endorsed by SkillsFuture Singapore or the Government of Singapore.

You remain responsible for complying with applicable laws, site terms, and your own data-use policies.

**PDPA:** Output is limited to public job and company fields. Recruiter personal emails and internal user identifiers stay out of the billed row. Use results for lawful recruiting research and salary analysis only.

For feedback or custom workflows, use the Actor **Issues** tab on Apify.

# Changelog

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

# Actor input Schema

## `search` (type: `string`):

Keyword matched against MyCareersFuture job titles, skills, and descriptions — for example 'software engineer' or 'registered nurse'. Leave empty when using only UEN, jobIds, startUrls, or taxonomy filters. Do not paste a full job URL here; use startUrls or jobIds instead.

## `searchQueries` (type: `array`):

Optional list of keyword searches run one after another. Each query is paginated until maxItems is reached across the whole run. Prefer this for multi-niche batches; use search for a single keyword.

## `companyUens` (type: `array`):

ACRA Unique Entity Numbers to list that employer's public MyCareersFuture postings, for example 201816453D. Returns only jobs where postedCompany.uen matches. Maximum 20 per run.

## `jobIds` (type: `array`):

Exact 32-character MyCareersFuture job UUIDs to fetch as detail rows. Do not pass MCF-YYYY-###### posting numbers — those cannot be resolved via the public API. Copy the UUID from the job page URL.

## `startUrls` (type: `array`):

MyCareersFuture job page URLs containing a 32-character UUID, for example https://www.mycareersfuture.gov.sg/job/<uuid>. MCF-YYYY-###### URLs are rejected with INVALID_INPUT because the public API cannot resolve posting numbers.

## `categories` (type: `array`):

Exact MyCareersFuture category labels, for example 'Information Technology' or 'Healthcare / Pharmaceutical'. Values must match the site enum exactly (HTTP 400 otherwise). Combine with search or use filters-only.

## `employmentTypes` (type: `array`):

Exact employment-type labels such as 'Full Time', 'Part Time', 'Permanent', 'Contract', or 'Internship'. Must match MyCareersFuture enum strings.

## `positionLevels` (type: `array`):

Exact seniority labels such as 'Fresh/entry level', 'Executive', 'Professional', 'Manager', or 'Senior Management'. Must match MyCareersFuture enum strings.

## `salaryFrom` (type: `integer`):

Lower bound for the advertised monthly SGD salary filter sent to the MyCareersFuture API. Leave empty for no minimum. This filters search results; it does not invent missing salaries.

## `salaryTo` (type: `integer`):

Upper bound for the advertised monthly SGD salary filter. Leave empty for no maximum. Combine with salaryFrom for a band.

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

Search sort order passed to the MyCareersFuture API. Default new_posting_date is best for monitoring fresh openings. min_monthly_salary sorts by advertised minimum SGD salary. Only these two values are accepted by the live public API.

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

Hard cap on unique job rows charged and saved for the entire run (across all queries). Default 50 keeps quality tests cheap; raise for bulk harvests. Hitting the cap finishes as PARTIAL.

## `fetchDetails` (type: `boolean`):

When true, each search/UEN hit is re-fetched via GET /v2/jobs/{uuid}. Search payloads are already rich; enable only when you need the freshest detail payload. Increases request count.

## `includeScreeningQuestions` (type: `boolean`):

When true, detail payloads are fetched so screeningQuestions can be attached when MyCareersFuture exposes them. Extra detail call per job; leave false for lean search harvests.

## Actor input object example

```json
{
  "search": "software engineer",
  "sortBy": "new_posting_date",
  "maxItems": 5,
  "fetchDetails": false,
  "includeScreeningQuestions": false
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset items with title, salary, company UEN, skills, location, and job URL.

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

Compact OUTPUT record with outcome, itemsPushed, chargedEventCounts, and warnings.

## `runSummary` (type: `string`):

Detailed RUN_SUMMARY diagnostics for integrations.

# 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 = {
    "search": "software engineer",
    "sortBy": "new_posting_date",
    "maxItems": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/mycareersfuture-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 = {
    "search": "software engineer",
    "sortBy": "new_posting_date",
    "maxItems": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/mycareersfuture-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 '{
  "search": "software engineer",
  "sortBy": "new_posting_date",
  "maxItems": 5
}' |
apify call khadinakbar/mycareersfuture-jobs-scraper --silent --output-dataset

```

## MCP server setup

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