Bayt Jobs Lookup: Gulf jobs scraper from $1.5/1k
Pricing
from $1.14 / 1,000 job posting returneds
Bayt Jobs Lookup: Gulf jobs scraper from $1.5/1k
Bayt jobs scraper by keyword and location: run a search on Bayt.com, one of the largest job boards in the Gulf and MENA region, and get one row per posting: title, company, location, pay (if stated), link. No login required. Pay per posting returned; empty searches are free.
Pricing
from $1.14 / 1,000 job posting returneds
Rating
0.0
(0)
Developer
Adrian Voss
Maintained by CommunityActor stats
1
Bookmarked
1
Total users
0
Monthly active users
a day ago
Last modified
Categories
Share
Bayt Jobs Lookup — Gulf & MENA Job Postings by Keyword & Location
You write job searches the way you'd type them into Bayt — accountant @ Dubai — and this actor
runs each one against Bayt.com's own search-results pages, one of the largest job boards in
the Gulf and wider MENA region, and returns one clean row per posting: title, company, location,
career level, pay range (when Bayt shows one), Bayt's own AI-written summary, and a permanent
link.
Bayt sits behind Cloudflare — a bare request gets a 403 challenge page, not the listing. This actor requests every page through Apify's UNBLOCKER proxy, which clears it cleanly (a real, server-rendered page comes back, no headless browser needed), so you never have to think about that yourself.
Who it's for
A staffing agency or in-house recruiter hiring across the UAE, Saudi Arabia, Qatar or the wider Gulf wants a live feed of what's actually open right now, by role and by city, without clicking through Bayt's own results pages by hand. A market-research or BI team tracking Gulf hiring demand for a sector or a set of employers wants the same feed at scale, across many searches at once. Both get the same shape here: paste a list of "keyword @ location" searches, get back a flat row per posting, and pay only for postings actually returned — a search that finds nothing costs nothing.
This actor is the Gulf/MENA-focused counterpart to seek-jobs-search-lookup (Australia),
stepstone-jobs-lookup (DACH) and dice-jobs-lookup (US tech): wide-net keyword + location
search rather than a per-company listing. The ATS lookups in the same family
(greenhouse-jobs-lookup, lever-jobs-lookup and friends) answer "what is this company
hiring for" — you bring the company list. This one answers "who is hiring for this role, in
this Gulf city" when you don't have the list yet.
Why this one
- Gets past Bayt's Cloudflare wall for you. A plain request to Bayt returns an HTTP 403 challenge page — confirmed directly, not assumed. This actor routes every request through Apify's UNBLOCKER proxy group, which clears it cleanly: a normal 200 response with the full, real, server-rendered listing. No headless browser is needed once past that wall, since Bayt's own job cards are already in the HTML it sends back.
postedAtis a real timestamp, not a guess. Bayt embeds an exact Unix-epoch instant on every posting's "posted X ago" badge — this actor reads that directly, sopostedAtis an absolute date, not a same-day approximation reverse-engineered from relative text (the best several sibling job-board actors on other sites can do).postedAgostill carries Bayt's own human wording ("2 days ago") alongside it.- A real summary, not a blank field. Bayt writes its own short AI summary of each posting and
puts it right on the search card — this actor reads it into
description(truncated to 500 characters), rather than leaving the field empty because a detail-page fetch wasn't worth doubling the request cost, which is the honest trade-off some sibling actors on sparser cards had to make. - Honest about what Bayt's card genuinely doesn't have. There is no employment-type
(full-time/part-time/contract) field on any individual posting — Bayt only exposes that as a
sidebar filter facet describing the whole result set, never a fact about one specific job — so
employmentTypeis alwaysnullhere rather than guessed from the facet list. There's no structured remote/work-arrangement signal either (Bayt's "remote" toggle is a search filter, not a field to read back), soremoteis title-only detection, same as every sibling job-board actor falls back to when a site gives it nothing better. - Location narrows honestly, in two layers. Bayt's own URL structure filters by whole
country, not by city — a search for
@ Dubaiactually fetches the UAE-wide listing. This actor then keeps only the rows whose own displayed location actually mentions "Dubai", so you still get city-accurate results without this actor pretending Bayt's URL scheme does something it doesn't. - You are never billed for the same posting twice. Every posting is deduplicated by Bayt's own job ID across the pages of one search and, by default, across every search in the run — an overlapping pair of searches returns, and bills, each posting once.
What you get
One row per job posting by default. (Turn off "One row per job posting" in the Input tab to get
one row per search instead, with the whole posting list nested in jobs.) Every row carries
these fields:
| Field | Type / format | Description |
|---|---|---|
query | text | The search line you passed in, unchanged. |
found | boolean | true if the search returned at least one posting. false rows are never charged. |
status | text | OK, NOT_FOUND (no postings for that search), BAD_FORMAT (a blank line), or BLOCKED. |
searchKeywords | text | The keywords actually sent to Bayt. |
searchLocation | text | The location text from your search line (or the run-level default). |
jobCount | number | How many postings this search returned after your filters — this is exactly what you're charged for. |
totalAvailable | number | Bayt's own total-match count for the country-level page this search resolved to, when Bayt's page includes it — best-effort, sometimes null (see FAQ). |
truncated | boolean | true if more postings were available than you asked for, or if paging stopped early (a mid-run Cloudflare re-challenge). |
jobs | array | The full posting list. Present in every row; it's what gets expanded into separate rows in "one row per posting" mode. |
jobId | text | Bayt's own numeric posting ID — stable, and what deduplication keys on. |
title | text | Job title. |
company | text | Hiring company, or literally "Confidential Company" for postings Bayt itself doesn't name. |
location | text | Location as Bayt prints it on the card, e.g. "Sharjah, UAE". |
remote | boolean | true if the title itself reads as remote — see "Why this one" for why there's no location-based half to this check on Bayt. |
salaryText | text | The pay range exactly as Bayt's chip shows it (e.g. "AED 7,345 - AED 11,018"). Present on roughly 6 in 10 postings in this actor's testing — Bayt shows a range for some postings and not others. |
employmentType | text | Always null — see "Why this one". Kept as a column for schema consistency with this portfolio's other search-shaped job-board actors. |
postedAt | date (ISO) | The exact instant Bayt's own timestamp encodes — see "Why this one". |
postedAgo | text | Bayt's own words for the same thing ("2 days ago"). |
url | link | Permanent link to the posting on bayt.com. |
description | text | Bayt's own short AI-written summary of the posting, truncated to 500 characters. |
careerLevel | text | Bayt's own seniority + experience line, e.g. "Mid career · 2-5 Years of Experience", when shown. |
isFeatured | boolean | true if Bayt marked this posting "Featured" in the results. |
scrapedAt | date (ISO) | When this actor fetched the row. |
A search that returns no postings comes back as a single found: false row with a
status/message explaining why, and is never charged. So does a blank line.
Pricing
- Job posting returned: $1.5 per 1,000 job postings
Plus a $0.00005 start fee per run. Each event above is billed independently, only when it actually returns data — misses (found:false) are never charged.
Pay-per-event, per job posting returned:
- Job posting returned: $1.5 per 1,000 job postings, less on paid Apify plans.
Plus a $0.00005 start fee per run. Misses (found: false) are never charged.
You're charged per posting returned, not per search — a search that returns 12 postings costs twelve, a search that returns none costs nothing, and a blank line costs nothing.
Getting past Bayt's Cloudflare wall needs Apify's UNBLOCKER proxy group, already configured by
default — there's nothing for you to set up, but it is a real, metered cost on this actor's own
side, which is reflected in the price: this is a little higher per posting than a plain-HTTP
job-board actor like dice-jobs-lookup or seek-jobs-search-lookup, which need no proxy at all.
1,000 postings through this actor: ~$1.50 if every search finds results, less on a paid Apify plan. Because you pay per posting, "Most postings to return per search" is your budget control: leave it at 50 and a ten-search run costs at most 500 postings' worth.
How to use
- In the Apify Console. Open the actor page and click Start — the
searchesfield is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found. - Via the API. Call it directly with a POST request — no Console needed once you have an API token:
curl "https://api.apify.com/v2/acts/accountable_eel~bayt-jobs-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \-X POST \-H "Content-Type: application/json" \-d '{"searches":["accountant @ Dubai"]}'
- On a schedule. Save this actor as an Apify Task with the input you want, then add a Schedule (hourly, daily, weekly) so it runs on its own — no server of your own required.
Paste one search per line:
accountant @ Dubaisales managercivil engineer @ Riyadh
A line with no @ location uses the location you set once in 🔍 Search settings — leave that
blank too and the search covers Bayt's "international" (all-country) listing.
🔍 Search settings:
| Input | What it does |
|---|---|
defaultLocation | Location for any line that doesn't name one. Write it the way Bayt does — "Dubai", "Riyadh", "Doha", or a country name. |
maxJobsPerQuery | Most postings to return per search. Default 50. |
🎯 Narrow the results — applied here, to the postings after they arrive. They combine with AND across fields and OR within a field:
| Input | What it does |
|---|---|
titleKeywords | Keep only titles containing one of these. |
excludeTitleKeywords | Drop titles containing one of these. Applied after the include list. |
companies | Keep only these companies — partial names match. |
excludeCompanies | Drop these companies — useful for filtering out recruitment agencies you already know. |
locations | Narrow a wide search to particular cities — applied on top of whatever your search line already narrowed. |
remoteOnly | Keep only roles whose title reads as remote. |
skipDuplicateJobs | On by default. Each posting is returned, and billed, once per run even if two searches overlap. |
Input
{"searches": ["accountant @ Dubai"]}
One search per line. Write it as "keywords @ location", or just the keywords and set a location below. Bayt is a Gulf/MENA board — locations are city or country names, e.g. "Dubai", "Riyadh", "Doha". Accepted formats: accountant @ Dubai, sales manager, civil engineer @ Riyadh.
Output
| query | found | status | searchKeywords | searchLocation | jobCount | totalAvailable | truncated | jobs | jobId | title | company | location | remote | salaryText | employmentType | postedAt | postedAgo | url | description | careerLevel | isFeatured | scrapedAt |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| accountant @ Dubai | true | OK | accountant | Dubai | 50 | <all postings found (full list)> | 5481491 | Senior Accountant | eliteUSA | Dubai, UAE | false | 2026-09-08T09:52:33.000Z | 7 hours ago | https://www.bayt.com/en/uae/jobs/senior-accountant-5481491/ | An exceptional opportunity awaits a detail-oriented Senior Accountant in Dubai. This role demands expertise in maintaining financial records, managing invoicing, and ensuring compliance with UAE accounting standards. The ideal candidate will thrive in a fast-paced environment, ensuring timely and accurate financial reporting while collaborating across departments. | Mid career | false | 2026-09-08T17:44:18.881Z |
A miss comes back as a row with "found": false and is never charged.
Use it from Clay, n8n, Make, or an AI agent
This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.
curl "https://api.apify.com/v2/acts/accountable_eel~bayt-jobs-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \-X POST \-H "Content-Type: application/json" \-d '{"searches":["accountant @ Dubai"]}'
n8n. Add an HTTP Request node: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~bayt-jobs-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body Content Type JSON, JSON Body {"searches":["accountant @ Dubai"]} (swap in an expression from an earlier node for a real value).
Clay. Add an "HTTP API" column: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~bayt-jobs-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body {"searches":["{{search}}"]}, mapping the row's search into the searches array.
MCP. In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "Bayt Jobs Scraper | Gulf Jobs API | Apify" — the agent will find and run this actor.
Tips
- Run "Try it first" on a handful of searches you already know return results for, to sanity-check the shape before spending on a full list.
- Keep
maxJobsPerQuerymodest (the default 50 is a sensible ceiling) — you pay per posting returned, so a broad keyword search with no location can otherwise return far more rows than a narrower one, at proportionally higher cost. - A search line's location only narrows Bayt's request down to a whole country — use the
locationsfilter (or just trust the automatic per-search narrowing this actor already applies) when you specifically want one city, not a whole country's worth of postings. remoteOnlyonly catches roles whose title literally says "remote" — Bayt gives this actor nothing else to check a posting's work arrangement against.- If you need more than the summary in
description,urllinks straight to the posting on bayt.com for anything you've shortlisted.
vs. alternatives
| What it costs | What you get | Trade-off | |
|---|---|---|---|
This actor (bayt-jobs-lookup) | $0.0015 per posting returned (less on paid Apify plans), $0.00005 actor start, nothing for a search that finds nothing | One row per Bayt posting — title, company, location, career level, pay range (when listed), Bayt's own AI summary, and link — filtered by title keyword, company, location, or remote-only | Gulf/MENA listings only. No employment-type field — Bayt never puts one on the card (see "Why this one"). Location narrows to country level via Bayt's own URL scheme, then to city level client-side. |
| blackfalcondata/bayt-scraper | Pay-per-result on Apify (163 u30, rated 5.00 on 1 review) | Also scrapes Bayt search results | A single review to judge reliability against. This actor prices per posting rather than a flat run fee, dedupes across overlapping searches, and reads an exact posted timestamp rather than only relative text. |
| TheirStack | $0.005–$0.03 per company | A job-postings dataset with history, normalised across many ATS platforms and job boards | Broader coverage across many sources and platforms, and it keeps history. This reads Bayt's own search pages live, at a fraction of that price per row, for the Gulf/MENA region specifically. |
| Doing it yourself | Your time + a Cloudflare-clearing proxy, tracking Bayt's own markup as it changes, and handling pagination and dedup by hand | The same data | The Cloudflare-clearing proxy wiring, card parsing, pagination, and dedup this actor already does are the maintenance burden it absorbs. |
Prices for third-party tools are their published figures as of September 2026 and are not tracked here — check the vendor before relying on the comparison.
FAQ
Why is a row empty, or why does found say false?
Either the input line is blank (status: BAD_FORMAT), Bayt/Cloudflare blocked the request
(status: BLOCKED, HTTP 403/429/503), the request failed after retries
(status: REQUEST_FAILED), or the search genuinely has no matching postings right now
(status: NOT_FOUND). Check the message column for the specific reason. None of these are
billed.
Am I charged for a miss? No. You're only charged for postings actually returned. A blocked search, a search with zero matches, or a blank input line all produce a row (unless you turn on "Hide rows with no result") and none of them cost anything.
Why is employmentType always empty?
Bayt's search-results card never carries a full-time/part-time/contract field for an individual
posting — "Employment type" only exists as a sidebar filter facet describing counts across the
whole result set. Rather than guess a specific posting's employment type from a facet that
describes hundreds of postings at once, this field is always null. It's kept as a column for
schema consistency with this portfolio's other search-shaped job-board actors.
Is postedAt an exact timestamp?
Yes. Unlike some sibling job-board actors that only have relative text ("2 days ago") to work
from, Bayt embeds an exact Unix-epoch instant directly in the page for every posting, and this
actor reads that value rather than approximating a date from the relative wording. postedAgo
still carries Bayt's own human-readable phrase alongside it.
Why is totalAvailable sometimes empty?
It's read from a "N jobs found" counter Bayt prints on the page — present on some fetches and not
on others in this actor's own live testing, for reasons not yet fully pinned down. When it's
missing, jobCount (what you're actually charged for) and every posting field are unaffected —
only the "how many more are out there" context is unavailable for that search.
Does a search for a specific city actually only search that city?
Bayt's own URL scheme narrows by whole country, not by city — a search for "@ Dubai" fetches the
UAE-wide listing from Bayt. This actor then automatically keeps only the postings whose own
displayed location mentions "Dubai", so your results are still city-accurate; it just means the
totalAvailable count reflects the whole country's total, not a city-specific one.
Does this handle Cloudflare's block on Bayt?
Yes, automatically. Every request goes through Apify's UNBLOCKER proxy group by default — there's
nothing for you to configure. If Bayt still re-challenges a session mid-run, that shows up as a
BLOCKED status on the affected search rather than a silent failure.
Do I need to configure proxies? No. UNBLOCKER is the default proxy group for this actor specifically, because a plain request to Bayt is blocked by Cloudflare — this is different from some sibling job-board actors that need no proxy at all. You don't need to change anything to use it.
Can I schedule this to re-check the same searches on a cadence? Yes — set up an Apify Task with a schedule (daily, weekly, whatever cadence fits) and point it at this actor with a saved input. Each run is a fresh fetch against Bayt's live listings.
Can an AI agent call this directly? Yes. It's registered on the Apify MCP server — an agent in Claude, Cursor, or another MCP client can find and run it by name ("Bayt Jobs Scraper | Gulf Jobs API | Apify"), or you can call the REST endpoint shown above from any script or workflow tool.
Related actors
- Dice Jobs Lookup — the same keyword + location search shape, for US tech roles on Dice.
- SEEK Jobs Search Lookup — the same shape again, for Australia's largest general job board.
- StepStone Jobs Lookup — the same shape for the DACH region.
- ATS Jobs Unified Lookup — once you have a specific company in mind rather than a keyword search, pull its open postings directly from its own ATS.