Gulf Jobs & Hiring Signals Monitor
Pricing
from $1.50 / 1,000 job results
Gulf Jobs & Hiring Signals Monitor
Track jobs from Greenhouse, Lever, Ashby, and Workable career boards across Saudi Arabia, the UAE, and the GCC. Get new, updated, and closed jobs between runs, plus a per-company hiring summary.
Pricing
from $1.50 / 1,000 job results
Rating
0.0
(0)
Developer
Pharaoh Data
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Know when your target companies start hiring in Saudi Arabia, the UAE, and the GCC
Point this Actor at the public career boards of the employers you care about. Each run returns clean, normalized job records from Greenhouse, Lever, Ashby, and Workable. With change tracking on, it also tells you which jobs are new, updated, or closed since the last run, plus a per-company hiring summary.
Schedule it daily and you get a hiring-signals feed you can send to a CRM, a Slack channel, a spreadsheet, or an AI agent.
Built for:
- B2B sales and partnerships teams who treat "company X just opened 5 roles in Riyadh" as a buying signal.
- Recruiters and staffing agencies who track which Gulf employers are hiring and for which teams.
- Investors and market analysts who follow hiring velocity at portfolio or competitor companies.
- Job-board and HR-tech builders who need a reliable, deduplicated feed straight from employer boards.
The Actor reads only the employer boards you list. It does not search every job site and does not claim full market coverage.
What you get
- Four job-board systems, one schema: Greenhouse (US and EU), Lever (US and EU), Ashby, and Workable. The provider is detected from the board URL.
- GCC-aware locations: each listing gets a
countryand acountrieslist for SA, AE, QA, KW, BH, and OM. Detection uses city and country names in English and Arabic (Riyadh/الرياض, Dubai/دبي, Doha/الدوحة, and more). Amman, Jordan is not confused with Oman. - Change tracking between runs: every record is labelled
new,updated(withchangedFields),unchanged, orclosed, withfirstSeenAt,lastSeenAt, andclosedAt. - "Changes only" mode: scheduled runs return just what changed, so alerts stay short and runs stay cheap.
- Hiring summary: each company's matching, new, updated, and closed counts, broken down by country and top departments, in the
HIRING_SUMMARYrecord. - Salary data where the employer publishes it: salary text plus a structured
salaryRange(min, max, currency, interval) from Lever and Ashby. Pay that an employer chose to hide is never output. - Arabic-aware filters: keywords, titles, and locations match regardless of diacritics and spelling variants (أ/إ/ا, ى/ي, ة/ه).
- Privacy by default: email addresses, phone numbers, and personal LinkedIn links inside job descriptions are redacted unless you turn this off.
- Clean, deduplicated output: one record per posting, matched by canonical URL, with links to the original listing and application page.
Quick start
- Under Employer job boards, add the public board URLs, for example:
https://jobs.lever.co/companyhttps://job-boards.greenhouse.io/company(orjob-boards.eu.greenhouse.io)https://jobs.ashbyhq.com/companyhttps://apply.workable.com/company/
- Optionally set a
companyNamelabel and a fallbackcountryfor each board. The fallback applies to listings that say only "Remote". - Choose countries, titles, locations, or keywords to narrow the results.
- Run it. For monitoring, save the configuration as a task, add a schedule (for example daily at 07:00 Riyadh time), and switch Output to Changes only.
Example input
{"sources": [{ "boardUrl": "https://apply.workable.com/foodics/", "companyName": "Foodics", "country": "SA" },{ "boardUrl": "https://jobs.ashbyhq.com/ziina", "companyName": "Ziina", "country": "AE" },{ "boardUrl": "https://job-boards.eu.greenhouse.io/tamara", "companyName": "Tamara", "country": "SA" },{ "boardUrl": "https://jobs.lever.co/kpler", "companyName": "Kpler", "country": "AE" }],"countries": ["SA", "AE", "QA", "KW", "BH", "OM"],"jobTitles": ["engineer", "manager"],"keywords": [],"locations": [],"postedWithinDays": 0,"maxResults": 1000,"trackChanges": true,"outputMode": "changes","includeClosed": true,"monitorId": "gulf-fintech-hiring","includeDescriptions": true,"redactContactDetails": true}
Input reference
| Field | Default | What it does |
|---|---|---|
sources | required | 1–100 public board root URLs. Optional per board: provider, companyName, country (fallback for location-less listings). |
countries | all six GCC | Keep listings located in these countries. Empty keeps every location worldwide. |
jobTitles | [] | Phrases matched in the title; any can match. |
locations | [] | Terms matched in the location; any can match. |
keywords | [] | Terms matched in title, description, department, company, or location; any can match. |
postedWithinDays | 0 | Keep listings published within N days. 0 disables it; listings without a date are kept. |
maxResults | 1000 | Maximum records saved per run, including closed-job records. Each record is one billable result. |
trackChanges | true | Compare with the previous run of the same monitor. |
outputMode | all | all saves every matching job with its status; changes saves only new, updated, and closed jobs. |
includeClosed | true | Save closed records for jobs an earlier run saved that their board no longer lists. |
monitorId | auto | Name for the change history. When empty it is derived from the boards and filters, so changing them starts a fresh history. |
includeDescriptions | true | Include plain-text descriptions (up to 20,000 characters). |
redactContactDetails | true | Remove emails, phone numbers, and personal LinkedIn links from descriptions. |
Filter groups combine (country AND title AND location AND keyword AND date); values within a group are "any match".
Output
Each dataset item is one job:
{"jobId": "workable:foodics:9BDF0B39E6","provider": "workable","sourceCompany": "Foodics","boardUrl": "https://apply.workable.com/foodics/","country": "SA","countries": ["SA"],"title": "AI Engineer","description": "Who Are We? We Are Foodics! a leading restaurant management ecosystem…","location": "Riyadh, Saudi Arabia","workplaceType": "","department": "Technology","employmentType": "Full-time","salary": "","salaryRange": null,"postedAt": "2026-09-29T00:00:00.000Z","jobUrl": "https://apply.workable.com/j/9BDF0B39E6","applyUrl": "https://apply.workable.com/j/9BDF0B39E6/apply","scrapedAt": "2026-10-17T16:20:14.687Z","changeType": "new","changedFields": [],"firstSeenAt": "2026-10-17T16:20:14.687Z","lastSeenAt": "2026-10-17T16:20:14.687Z","closedAt": null}
workplaceTypeisonsite,remote,hybrid, or empty when the source does not say.changeTypeisnullwhen change tracking is off. Closed records keep the last known title, location, and links, and have an empty description.- The run's
HIRING_SUMMARYrecord (default key-value store) looks like this:
{"generatedAt": "2026-10-17T16:21:09.824Z","monitorId": "gulf-fintech-hiring","outputMode": "changes","storedRecords": 2,"totals": {"sources": 4,"failedSources": 0,"matchingJobs": 66,"new": 0,"updated": 1,"unchanged": 65,"closed": 1},"companies": [{"company": "Ziina","provider": "ashby","status": "ok","listingsFetched": 13,"matchingJobs": 13,"new": 0,"updated": 1,"closed": 0,"byCountry": { "AE": 13 },"topDepartments": [{ "name": "Engineering / Internal Platform", "count": 4 }]}]}
Use it from your code, n8n, Make, or an AI agent
Run and fetch results in one call (replace the token; keep it out of shared code):
curl -X POST "https://api.apify.com/v2/acts/pharaoh_data~gulf-jobs-monitor/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"sources":[{"boardUrl":"https://jobs.ashbyhq.com/ziina","companyName":"Ziina"}],"outputMode":"changes","monitorId":"ziina-watch"}'
JavaScript (npm install apify-client):
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('pharaoh_data/gulf-jobs-monitor').call({sources: [{ boardUrl: 'https://apply.workable.com/foodics/', companyName: 'Foodics' }],outputMode: 'changes',monitorId: 'foodics-watch',});const { items } = await client.dataset(run.defaultDatasetId).listItems();const summary = await client.keyValueStore(run.defaultKeyValueStoreId).getRecord('HIRING_SUMMARY');
Python (pip install apify-client):
import osfrom apify_client import ApifyClientclient = ApifyClient(os.environ["APIFY_TOKEN"])run = client.actor("pharaoh_data/gulf-jobs-monitor").call(run_input={"sources": [{"boardUrl": "https://jobs.lever.co/kpler", "companyName": "Kpler"}],"countries": ["AE", "SA"],"outputMode": "changes",})new_jobs = [job for job in client.dataset(run["defaultDatasetId"]).iterate_items() if job["changeType"] == "new"]
- n8n / Make / Zapier: use the Apify integration's "Run Actor" action (or an HTTP request to the endpoint above), then filter on
changeType. - Alerts: add an Apify webhook on "Run succeeded" that posts the dataset to Slack, email, or your CRM.
- AI agents (MCP): connect
https://mcp.apify.com/?actors=pharaoh_data/gulf-jobs-monitorso an agent can call the Actor as a tool.
How change tracking works
- History is kept per monitor in the named key-value store
gulf-jobs-monitor-statein your Apify account, undermonitor-<monitorId>. Use a differentmonitorIdfor each independent watch list. - A job is remembered only after its record is saved. If a run stops early or reaches
maxResultsor your spending limit, unsaved jobs are reported on the next run. - Closed means a job an earlier run saved is no longer listed by a board that was read successfully in this run. A board that fails never produces false closures; its history is kept.
- A job that is still listed but no longer matches your filters is dropped from the history silently, not reported as closed. Removing a board from the input forgets its jobs.
- Updated compares title, location, department, employment type, workplace type, salary, and description (descriptions only when both runs collected them).
Coverage, limits, and responsible use
- Supported: Greenhouse Job Board API, Lever Postings API (US and EU), Ashby's public job posting API, and Workable's public jobs widget endpoint, which Workable's own careers-page widget uses. These are all public, unauthenticated endpoints that employers publish so their jobs can be listed.
- Not supported: SmartRecruiters (its API host's robots.txt disallows general crawlers), Workday, Oracle/Taleo, SuccessFactors, LinkedIn, Bayt, and other job boards. No proxies, logins, or CAPTCHA solving are used.
- Requests are sequential, with at least 0.5 seconds between requests to the same host and 1 second for Lever (Lever's published crawl delay). They time out after 30 seconds, retry at most twice on rate limits or server errors, and responses are capped at 25 MB per board.
- Up to 100 boards and 10,000 records per run; Lever boards are paginated up to 10,000 listings.
- Coverage depends on what each employer publishes. Some boards omit departments, dates, workplace type, or salary. Greenhouse publishes employment and workplace type only as optional custom fields.
- Job descriptions are the employer's content. Check the employer's terms and applicable rules (including Saudi PDPL, UAE PDPL, and GDPR when relevant) before storing or redistributing them. Workable signals
ai-train=nofor its pages, so do not use Workable content to train AI models.
Pricing
This Actor uses pay-per-event pricing: you pay per job result (one record in the dataset, including closed-job records), plus Apify's small Actor start event. If the Pricing tab also lists a Job change event, records saved in "Changes only" mode are billed at that price instead. Your Apify plan's prepaid usage applies. Check the Pricing tab for current amounts. "Changes only" mode keeps scheduled runs cheap because unchanged jobs are not saved or charged.
Typical runs finish in seconds with 512 MB of memory.
FAQ
Does it find employers for me?
No. You provide the boards. To find a company's board, open its careers page and look for a jobs.lever.co, greenhouse.io, jobs.ashbyhq.com, or workable.com link.
Why did a board fail?
Usually because the board name in the URL is wrong or the board is not public. The run log and HIRING_SUMMARY show the error for each board, and other boards still run.
Why do I see the same jobs as new again?
monitorId changed. That happens automatically if you edit boards or filters without setting a fixed monitorId, or if earlier runs stopped at maxResults before saving them.
Can I get only Saudi jobs from a global company?
Yes. Set countries to ["SA"]. Listings in London or New York are dropped; multi-location listings are kept if any location is in Saudi Arabia.
Is Arabic supported? Yes, for matching and for country detection. Titles and descriptions are returned in whatever language the employer used.