# JobStreet Job Scraper - Deduplicated, Pay Once Per Job (SEA) (`automation_craft/jobstreet-job-scraper`) Actor

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.

- **URL**: https://apify.com/automation\_craft/jobstreet-job-scraper.md
- **Developed by:** [Automation Craft](https://apify.com/automation_craft) (community)
- **Categories:** Jobs, Lead generation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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?

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

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

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

| | Australia | New Zealand | Malaysia, Singapore, Philippines, Indonesia | Hong Kong, Thailand |
|---|---|---|---|---|
| Job title, employer, teaser, bullet points, category, work type, listing date, URL | always | always | always | always |
| Full description (HTML, text, Markdown, sections) | always with job details | always | always | always |
| Salary shown on the ad, parsed to min / max / period / currency | 56% of ads show a salary; usually per year, often "+ super" | similar to Australia | most 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 letter | appears a few hours after posting; 97% of ads | same | same | same |
| Employer industry, size, website, rating, reviews | 61% of ads link to an employer profile | similar | similar; profiles are common for larger employers | similar |
| Suburb / district, region, state | yes | yes (region) | yes (state or region) | yes (district and area) |
| Postcode | 96% of ads | 64% of ads | not published on the site | not published on the site |
| On-site / hybrid / remote | when declared by the advertiser | same | same | same |
| Screening questions | when the advertiser uses the site's apply flow | same | same | same |
| Labels in the local language | n/a | n/a | Indonesia: 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

| Input | What it does |
|---|---|
| Countries | Which sites to search. Each country is one dataset; results carry `market`, `country` and `brand`. |
| Locations | Regions 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-categories | The site's classification taxonomy (30 categories, 394 sub-categories). Labels or ids both work through the API. |
| Keywords | The site's keyword search. |
| Work type, work arrangement, salary from/to | The site's own filters. The salary filter also matches ads that hide their salary. |
| Posted within | 1 / 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 industries | Matched 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 contain | Plain-text filters over title, teaser, bullets, employer and (with job details) the full description. |
| Search URLs | Paste any search, job or company URL from SEEK, JobStreet or JobsDB (old or new domains). |
| Memory name | The 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:

| Field | Meaning |
|---|---|
| `id`, `url`, `market`, `country`, `brand` | Identity. `sourceMarket` shows where a cross-listed ad originated. |
| `title`, `normalisedRoleTitle`, `teaser`, `bulletPoints`, `descriptionText`, `descriptionHtml`, `descriptionMarkdown`, `descriptionSections` | The ad. |
| `listedAt`, `createdAt`, `updatedAt`, `expiresAt` | ISO timestamps (UTC). |
| `classification`, `subclassification` (+ ids) | The site's job taxonomy. |
| `location`, `suburb`, `area`, `city`, `state`, `stateCode`, `postcode`, `locationHierarchy` | Structured location. |
| `workType`, `workArrangement` | Full time / part time / contract / casual; on-site / hybrid / remote. |
| `salaryLabel`, `salaryMin`, `salaryMax`, `salaryPeriod`, `salaryCurrency`, `salary.includesSuper`, `salary.parseConfidence`, `salary.annualisedMin/Max` | Salary as shown and as parsed. |
| `applicantCount`, `applicantsWithResumePct`, `applicantsWithCoverLetterPct`, `applicantVolume` | Demand signals. |
| `advertiserName`, `advertiserId`, `advertiserIsVerified`, `isPrivateAdvertiser`, `isRecruitmentAgency` | Who posted it. |
| `companyName`, `companyIndustry`, `companySize`, `companyWebsite`, `companyPrimaryLocation`, `companyDescription`, `companyRating`, `companyReviewCount`, `companyAwards`, `companyProfileUrl`, `companyLogoUrl`, `companyHasProfile` | The employer. |
| `screeningQuestions`, `isLinkOut`, `isSponsored`, `isFeatured`, `tags` | Application details and ad flags. |
| `ecommerceSignals`, `seniority`, `detectedSkills`, `visaSponsorship`, `isRemoteFriendly` | Derived signals from the text. |
| `emails`, `phones` | Only when "Extract emails and phone numbers" is on. |
| `changeType`, `isDuplicate`, `firstSeenAt`, `lastSeenAt`, `contentHash`, `searchShard` | Dedup and provenance. |

Sample item from a live run:

```json
{
  "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.

```bash
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
  }'
```

```javascript
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');
```

```python
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.

# Actor input Schema

## `markets` (type: `array`):

Which JobStreet sites to search. All eight SEEK-platform markets are available in every listing.

## `locationsDropdown` (type: `array`):

Regions, cities and states exactly as they appear on the site. Pick as many as you like. Leave empty for the whole country.

## `locations` (type: `array`):

Any suburb, city, state, region or postcode as you would type it on JobStreet, e.g. "Kuala Lumpur". Prefix with a country code to pin it: "AU: Newcastle NSW". Unresolvable entries are listed in the run summary, never silently dropped.

## `keywords` (type: `string`):

Search words, exactly as on the site, e.g. "digital marketing". Optional.

## `classifications` (type: `array`):

Job families as defined by the site (30). Leave empty for all.

## `subclassifications` (type: `array`):

Narrower than categories (394). If you pick a sub-category you do not need its parent category.

## `workTypes` (type: `array`):

Full time, part time, contract or casual. Leave empty for all.

## `workArrangements` (type: `array`):

On-site, hybrid or remote (as declared by the advertiser). Leave empty for all.

## `salaryMin` (type: `integer`):

Minimum salary in the local currency. Uses the site's own salary filter, which also matches ads whose salary is hidden.

## `salaryMax` (type: `integer`):

Maximum salary in the local currency.

## `salaryType` (type: `string`):

How the salary above is expressed. Annual is usual in Australia and New Zealand, monthly in Asia.

## `postedWithinDays` (type: `string`):

Only jobs listed in this window. 1, 3, 7, 14 and 30 use the site's own filter; any other number of days (via the API) is applied exactly.

## `postedAfter` (type: `string`):

Optional exact start date/time (ISO 8601). Overrides "Posted within".

## `postedBefore` (type: `string`):

Optional exact end date/time (ISO 8601).

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

Relevance (site default) or newest first. Only matters when you cap the number of results.

## `companyIndustries` (type: `array`):

Only jobs from employers in these industries (the site's own employer-profile taxonomy). About half of all ads link to an employer profile, so also decide below what to do with employers whose industry is unknown.

## `companyIndustriesCustom` (type: `array`):

Extra industry names not in the list, matched loosely (case and punctuation ignored).

## `unknownIndustryPolicy` (type: `string`):

Applies only when you filter by industry. "Exclude" keeps results precise; "Include" keeps every job whose employer has no profile (industry will be empty).

## `companyNames` (type: `array`):

Employer or advertiser names to keep (partial match, case-insensitive).

## `excludeCompanyNames` (type: `array`):

Employer or advertiser names to drop (partial match).

## `companyUrls` (type: `array`):

Paste company profile URLs (e.g. https://my.jobstreet.com/companies/<name>-<id>) to get every live job at those employers.

## `advertiserIds` (type: `array`):

Advertiser account ids (advanced; found in the output field advertiserId).

## `minCompanyRating` (type: `number`):

Keep only employers rated at least this (1 to 5) by their reviews on the site.

## `excludeRecruitmentAgencies` (type: `boolean`):

Drop ads from recruiters and staffing agencies (industry "Employment Services" or a recruiter-like name).

## `excludePrivateAdvertisers` (type: `boolean`):

Drop anonymous "Private Advertiser" ads.

## `includeKeywords` (type: `array`):

Keep only jobs containing at least one of these words (checked in the fields chosen below).

## `excludeKeywords` (type: `array`):

Drop jobs containing any of these words.

## `keywordFields` (type: `array`):

Where the text filters look.

## `searchUrls` (type: `array`):

Paste search result URLs from any SEEK-platform site (SEEK, JobStreet, JobsDB, old or new domains). Filters in the URL are applied. Job URLs (/job/123) and company URLs also work.

## `includeDetails` (type: `boolean`):

Full description (HTML, text and Markdown), applicant count, screening questions, exact dates, suburb/state/postcode. $0.30 per 1,000 jobs.

## `includeCompanyProfile` (type: `boolean`):

Industry, size, website, HQ, description, rating, review count, awards. $0.10 per 1,000 jobs, charged only when the employer actually has a profile.

## `extractContacts` (type: `boolean`):

Regex extraction from the description. Off by default. Free.

## `labelLanguage` (type: `string`):

Category and location labels in English or the site's local language where it has one (Indonesia, Thailand, Hong Kong).

## `includeRawData` (type: `boolean`):

Attach the untouched search card, job details and company profile JSON under "raw". Free, but large.

## `dedupMemoryName` (type: `string`):

Give your search a name, e.g. "my-weekly-marketing-run". Jobs delivered under this name are remembered and never delivered or charged again in later runs. Leave empty to only remove duplicates within one run.

## `emitDuplicates` (type: `boolean`):

Return jobs the memory already knows, marked isDuplicate = true and changeType = DUPLICATE or UPDATED. Never charged.

## `resetDedupMemory` (type: `boolean`):

Forget everything stored under the memory name before running.

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

Stop after this many jobs (0 = no limit). Applies to new, unique jobs after filters.

## `maxRequestsPerSecond` (type: `number`):

Politeness cap towards the site. 4 is a safe default; raise to 8 for large runs.

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

Not required: the site serves this data to datacenter IPs. Enable only if your own runs get blocked.

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

Fetch specific jobs by id (advanced).

## Actor input object example

```json
{
  "markets": [
    "MY",
    "SG",
    "PH",
    "ID"
  ],
  "locations": [],
  "salaryType": "annual",
  "postedWithinDays": "any",
  "sortBy": "relevance",
  "unknownIndustryPolicy": "exclude",
  "excludeRecruitmentAgencies": false,
  "excludePrivateAdvertisers": false,
  "keywordFields": [
    "title",
    "teaser",
    "bullets",
    "company",
    "description"
  ],
  "includeDetails": true,
  "includeCompanyProfile": true,
  "extractContacts": false,
  "labelLanguage": "en",
  "includeRawData": false,
  "emitDuplicates": false,
  "resetDedupMemory": false,
  "maxItems": 100,
  "maxRequestsPerSecond": 4,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `jobs` (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 = {
    "markets": [
        "MY",
        "SG",
        "PH",
        "ID"
    ],
    "locations": [],
    "keywords": "",
    "postedWithinDays": "any",
    "keywordFields": [
        "title",
        "teaser",
        "bullets",
        "company",
        "description"
    ],
    "includeDetails": true,
    "includeCompanyProfile": true,
    "dedupMemoryName": "",
    "maxItems": 100,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation_craft/jobstreet-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 = {
    "markets": [
        "MY",
        "SG",
        "PH",
        "ID",
    ],
    "locations": [],
    "keywords": "",
    "postedWithinDays": "any",
    "keywordFields": [
        "title",
        "teaser",
        "bullets",
        "company",
        "description",
    ],
    "includeDetails": True,
    "includeCompanyProfile": True,
    "dedupMemoryName": "",
    "maxItems": 100,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("automation_craft/jobstreet-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 '{
  "markets": [
    "MY",
    "SG",
    "PH",
    "ID"
  ],
  "locations": [],
  "keywords": "",
  "postedWithinDays": "any",
  "keywordFields": [
    "title",
    "teaser",
    "bullets",
    "company",
    "description"
  ],
  "includeDetails": true,
  "includeCompanyProfile": true,
  "dedupMemoryName": "",
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call automation_craft/jobstreet-job-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation_craft/jobstreet-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/5X1gVs9NQAqyqhkhW/builds/CxVPptgZTcnyLVGC6/openapi.json
