# GCC Job Opportunities Scraper (`automation-lab/gcc-job-listings-aggregator`) Actor

Search GulfTalent and NaukriGulf by keyword and GCC country, then export normalized, source-attributed, deduplicated vacancies.

- **URL**: https://apify.com/automation-lab/gcc-job-listings-aggregator.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Jobs, Lead generation
- **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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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

## GCC Job Opportunities Scraper

Search GulfTalent and NaukriGulf in one run and export normalized **GCC job opportunities** across the United Arab Emirates, Saudi Arabia, Qatar, Kuwait, Bahrain, and Oman.

The Actor turns separate board searches into a source-attributed vacancy feed for recruiters, sales researchers, labor-market analysts, and data teams.

It accepts job titles, skills, or keywords; scopes every search to selected GCC countries; enriches public vacancy details; and conservatively deduplicates matching title–company–country records.

### What does GCC Job Opportunities Scraper do?

Use it to:

- search GulfTalent and NaukriGulf together;
- select any combination of the six GCC countries;
- run up to 10 job-title or skill queries;
- normalize different source formats into one schema;
- retain canonical source URLs and source job IDs;
- merge conservative cross-board matches;
- fetch descriptions and structured details when requested;
- cap the final dataset from 1 to 1,000 unique vacancies;
- export results as JSON, CSV, Excel, XML, or RSS through Apify;
- schedule recurring GCC jobs monitoring without maintaining two scrapers.

Bayt and AI-generated labels are intentionally not included.

### Who is it for?

GCC Job Opportunities Scraper is designed for teams that need repeatable regional vacancy data.

#### Recruiting and staffing teams

Build shortlists across two regional boards without reconciling two exports by hand.

#### Hiring-intelligence analysts

Compare vacancy demand by title, country, employer, date, and source over repeated runs.

#### B2B sales researchers

Identify companies advertising roles that may signal expansion, technology investment, or staffing needs.

#### Job-data and ETL teams

Feed normalized public vacancies into a warehouse, dashboard, spreadsheet, ATS review queue, or downstream matching service.

#### Researchers

Collect repeatable snapshots for GCC job openings, skills demand, and regional labor-market analysis.

### Why aggregate GulfTalent and NaukriGulf?

Each source has its own search and record shape.

This Actor provides one input and one stable dataset contract while preserving source provenance.

Unlike a generic web crawler, it understands:

- GulfTalent country-scoped title searches;
- NaukriGulf keyword and location search pagination;
- source job IDs and canonical vacancy links;
- board-specific posting dates and detail fields;
- GCC country codes;
- conservative duplicate identity.

A row is never presented as an exact cross-board duplicate solely because titles look similar.

The merge key also uses employer and country.

### Supported countries and sources

| Country | Input code | GulfTalent | NaukriGulf |
|---|---:|:---:|:---:|
| United Arab Emirates | `AE` | Yes | Yes |
| Saudi Arabia | `SA` | Yes | Yes |
| Qatar | `QA` | Yes | Yes |
| Kuwait | `KW` | Yes | Yes |
| Bahrain | `BH` | Yes | Yes |
| Oman | `OM` | Yes | Yes |

Supported `sources` values are:

- `gulftalent`
- `naukrigulf`

Select either board or both.

### What GCC vacancy data can you extract?

| Field | Meaning |
|---|---|
| `jobId` | Stable normalized title–company–country identifier |
| `title` | Vacancy title |
| `company` | Employer or recruiting company when disclosed |
| `country` | Selected GCC country code |
| `location` | Visible city or location text |
| `description` | Plain-text public vacancy description when enriched |
| `employmentType` | Employment type when disclosed |
| `workMode` | Workplace, hybrid, or remote label when disclosed |
| `experienceMin` / `experienceMax` | Structured experience range when available |
| `experienceText` | Source-provided experience label |
| `salaryMin` / `salaryMax` | Structured salary range when disclosed |
| `salaryCurrency` | Currency accompanying structured salary data |
| `salaryText` | Source-provided salary text |
| `skills` | Structured skill keywords when available |
| `postedAt` | Exact source posting date when available |
| `postedText` | Visible date label retained from the search result |
| `url` | Canonical primary vacancy URL |
| `primarySource` | Source used for the primary normalized record |
| `sources` | Every retained source match with source job ID and URL |
| `matchedQueries` | Input searches that produced the record |
| `scrapedAt` | Collection timestamp |

Unavailable source fields are returned as `null` or an empty array rather than invented.

### How to run a GCC job search

1. Open the Actor input page.
2. Add one or more job titles, skills, or keywords under **Job search queries**.
3. Select the GCC country markets.
4. Select GulfTalent, NaukriGulf, or both.
5. Choose the maximum number of unique vacancies.
6. Keep **Include vacancy details** enabled for descriptions and richer fields.
7. Disable details for a faster recurring scan when search-card fields are enough.
8. Click **Start**.
9. Open the default dataset to review, filter, or export the rows.

A practical first input is:

```json
{
  "queries": ["data analyst"],
  "countries": ["AE", "SA"],
  "sources": ["gulftalent", "naukrigulf"],
  "maxItems": 20,
  "includeDetails": true
}
```

### Input parameters

#### `queries`

Required array of 1–10 non-empty strings.

Use job titles, technologies, skills, or hiring keywords such as:

- `data analyst`
- `software engineer`
- `finance manager`
- `sales manager`
- `registered nurse`

Each value can contain up to 100 characters.

#### `countries`

Required list containing one or more supported GCC codes.

The default is `AE` and `SA`.

#### `sources`

Required list containing `gulftalent`, `naukrigulf`, or both.

The default includes both boards.

#### `maxItems`

Maximum unique records saved across the complete input.

Allowed range: 1–1,000.

This is an output cap, not a promise that every search has that many live vacancies.

#### `includeDetails`

When `true`, the Actor fetches public detail records for selected vacancies.

When `false`, it returns normalized search-card records and avoids the extra per-vacancy requests.

### Output example

This shortened record comes from a real local run using `data analyst`, `AE`, and detail enrichment:

```json
{
  "jobId": "37b73a67f5c7e4078b1c1aa6",
  "title": "Data Analyst",
  "company": "Sembol Construction",
  "country": "AE",
  "location": "Abu Dhabi, UAE",
  "description": "We are seeking a highly analytical Data Analyst / Industrial Engineer...",
  "employmentType": "FULL_TIME",
  "workMode": null,
  "experienceMin": null,
  "experienceMax": null,
  "salaryMin": null,
  "salaryMax": null,
  "salaryCurrency": null,
  "skills": [],
  "postedAt": "2026-07-12T00:00:00+00:00",
  "postedText": "12 Jul",
  "url": "https://www.gulftalent.com/uae/jobs/data-analyst-606775",
  "primarySource": "gulftalent",
  "sources": [
    {
      "source": "gulftalent",
      "sourceJobId": "606775",
      "url": "https://www.gulftalent.com/uae/jobs/data-analyst-606775"
    }
  ],
  "matchedQueries": ["data analyst"],
  "scrapedAt": "2026-08-16T06:21:47.798Z"
}
```

The live source can change or remove a vacancy after collection.

### How deduplication works

The Actor first deduplicates by normalized vacancy identity.

The conservative cross-source key contains:

1. normalized title;
2. normalized company;
3. GCC country.

When both boards produce the same key, the output keeps one primary record and adds both listings to `sources`.

Different employers, different countries, or materially different titles remain separate.

This reduces obvious duplicates without claiming uncertain matches.

### How much does it cost to aggregate GCC job opportunities?

The Actor uses pay-per-event pricing:

- one `start` event per run;
- one `item` event per saved, normalized vacancy;
- no separate event for detail enrichment.

Current source configuration uses a **$0.001 start fee** and these per-vacancy tier prices:

| Apify tier | Price per vacancy |
|---|---:|
| FREE | $0.00138 |
| BRONZE | $0.00120 |
| SILVER | $0.000936 |
| GOLD | $0.00072 |
| PLATINUM | $0.00048 |
| DIAMOND | $0.000336 |

At the BRONZE rate, examples are approximately:

- 10 saved vacancies: $0.013 total;
- 25 saved vacancies: $0.031 total;
- 100 saved vacancies: $0.121 total.

These examples include the one-time start event.

Actual Apify platform usage and proxy costs are operational costs to the Actor owner and are not separately billed as Actor events to the user.

### Recurring monitoring and data workflows

#### Scheduled hiring-market snapshots

Schedule the Actor daily or weekly with stable input.

Store each run’s dataset ID and compare `jobId`, `postedAt`, and `sources` in your own workflow.

The Actor does not itself maintain cross-run history or send alerts.

#### Spreadsheet review

Export the default dataset as CSV or Excel.

Filter by country, company, source, or posting date.

#### Warehouse ingestion

Pull dataset items through the Apify API after each scheduled run.

Use `jobId` as the normalized identity and preserve `sources` for provenance.

#### Sales-research pipeline

Search role families associated with expansion, then join disclosed employer names to your existing company-enrichment process.

#### Candidate sourcing review

Search several skills or titles, retain canonical vacancy links, and review source requirements before outreach or application.

### Run with the Apify API

Set `APIFY_TOKEN` in your environment.

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~gcc-job-listings-aggregator/runs?waitForFinish=300" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "queries": ["data analyst"],
    "countries": ["AE", "SA"],
    "sources": ["gulftalent", "naukrigulf"],
    "maxItems": 20,
    "includeDetails": true
  }'
```

Fetch the resulting default dataset using the run’s `defaultDatasetId`.

#### JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const run = await client.actor('automation-lab/gcc-job-listings-aggregator').call({
  queries: ['software engineer'],
  countries: ['AE'],
  sources: ['gulftalent'],
  maxItems: 50,
  includeDetails: true,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/gcc-job-listings-aggregator').call(run_input={
    'queries': ['finance manager', 'sales manager'],
    'countries': ['AE', 'SA', 'QA', 'KW', 'BH', 'OM'],
    'sources': ['gulftalent', 'naukrigulf'],
    'maxItems': 100,
    'includeDetails': False,
})
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

### Use with Apify MCP

Add the Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/gcc-job-listings-aggregator"
```

#### Claude Desktop, Cursor, and VS Code setup

Use the same HTTP MCP server configuration in Claude Desktop, Cursor, or VS Code:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/gcc-job-listings-aggregator"
    }
  }
}
```

Example prompts:

- “Search GulfTalent and NaukriGulf for data analyst jobs in the UAE and Saudi Arabia. Return 30 enriched vacancies.”
- “Export 20 GulfTalent software engineer jobs in the UAE with descriptions and source links.”
- “Create a lightweight six-country feed for finance manager and sales manager openings without detail enrichment.”

### Reliability, retries, and limits

The Actor uses lightweight HTTP/API contexts through Apify datacenter proxy sessions.

It does not launch a browser and does not enable an automatic residential fallback.

A blocked or transient source request is retried once with a fresh datacenter session.

If one selected source fails, other valid source/country/query scopes can still produce useful records.

If every selected search fails, the run fails instead of reporting a false empty result.

A valid search with no matching NaukriGulf records succeeds with an empty dataset.

Optional detail failures preserve the useful search-card record.

Source sites can change their public pages, APIs, availability, and data fields without notice.

### Tips for useful results

- Start with specific job titles rather than long natural-language sentences.
- Use `includeDetails: false` for frequent broad snapshots.
- Use `includeDetails: true` when descriptions, skills, or exact dates matter.
- Keep the same input between scheduled snapshots for comparable results.
- Select only the countries relevant to the workflow.
- Use source-specific runs when diagnosing a board or comparing coverage.
- Treat salary fields as optional because many employers do not publish salary data.
- Follow each canonical URL to verify time-sensitive vacancy status.

### Responsible use and legality

This Actor accesses public vacancy search and detail surfaces.

Public availability does not remove your responsibilities.

You should:

- comply with applicable laws and source terms;
- collect only data needed for a legitimate purpose;
- respect intellectual-property and database rights;
- avoid republishing full descriptions without permission;
- protect personal data that may appear in public listings;
- avoid discriminatory profiling or automated employment decisions;
- honor deletion, correction, and retention obligations;
- use reasonable schedules and result limits.

The Actor is a collection tool, not legal advice.

### Troubleshooting and FAQ

#### Why did I receive fewer rows than `maxItems`?

`maxItems` is a cap.

The selected queries, countries, and sources may expose fewer live unique vacancies, or duplicates may merge.

#### Why is a field `null`?

The source did not disclose that field, the search card did not contain it, or optional detail enrichment was unavailable.

#### Why did the run fail instead of returning zero rows?

All selected source searches failed or returned an invalid upstream shape.

The Actor fails closed so a source outage is not mistaken for a genuine zero-result market.

#### Why are two similar jobs separate?

Deduplication is intentionally conservative.

Title, company, and country must normalize to the same key before records merge.

#### Does it include Bayt?

No.

The supported scope is GulfTalent and NaukriGulf.

#### Does it translate titles or add AI labels?

No.

All output comes from normalized public source fields.

#### Does it track new, changed, and expired jobs across runs?

Not internally.

Schedule repeated runs and compare stable `jobId` values in your database, automation, or dataset-diff workflow.

#### Does it require my own job-board account?

No.

It accesses public search and vacancy surfaces through Apify Proxy.

### Related Automation Lab Actors

- [Naukrigulf Jobs Scraper](https://apify.com/automation-lab/naukrigulf-jobs-scraper) — a dedicated NaukriGulf workflow with source-specific search and detail fields.
- [Company Career Page Jobs Scraper](https://apify.com/automation-lab/company-career-page-jobs-scraper) — normalize public employer career-page listings supplied by URL.
- [Dataset Dedup](https://apify.com/automation-lab/dataset-dedup) — remove duplicate records in a downstream dataset workflow.

### Summary

GCC Job Opportunities Scraper combines GulfTalent and NaukriGulf searches into one typed, source-attributed vacancy feed.

Use it for one-time GCC job search, recurring hiring-market snapshots, spreadsheet exports, and data-pipeline ingestion while retaining the canonical board evidence behind every row.

# Actor input Schema

## `queries` (type: `array`):

Job titles, skills, or keywords to search. Each query is searched across every selected country and source.

## `countries` (type: `array`):

Country markets to search: United Arab Emirates, Saudi Arabia, Qatar, Kuwait, Bahrain, and Oman.

## `sources` (type: `array`):

Select GulfTalent, NaukriGulf, or both. Every output row identifies the source listing and URL.

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

Maximum number of normalized, deduplicated job records saved across all selected searches.

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

Enrich selected rows with public descriptions, employment details, experience, skills, salary, and exact posting dates when the source provides them. Disable for faster recurring scans.

## Actor input object example

```json
{
  "queries": [
    "data analyst"
  ],
  "countries": [
    "AE",
    "SA"
  ],
  "sources": [
    "gulftalent",
    "naukrigulf"
  ],
  "maxItems": 20,
  "includeDetails": true
}
```

# Actor output Schema

## `overview` (type: `string`):

Open the default dataset overview containing normalized GCC job opportunity records.

# 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 = {
    "queries": [
        "data analyst"
    ],
    "countries": [
        "AE",
        "SA"
    ],
    "sources": [
        "gulftalent",
        "naukrigulf"
    ],
    "maxItems": 20,
    "includeDetails": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/gcc-job-listings-aggregator").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 = {
    "queries": ["data analyst"],
    "countries": [
        "AE",
        "SA",
    ],
    "sources": [
        "gulftalent",
        "naukrigulf",
    ],
    "maxItems": 20,
    "includeDetails": True,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/gcc-job-listings-aggregator").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 '{
  "queries": [
    "data analyst"
  ],
  "countries": [
    "AE",
    "SA"
  ],
  "sources": [
    "gulftalent",
    "naukrigulf"
  ],
  "maxItems": 20,
  "includeDetails": true
}' |
apify call automation-lab/gcc-job-listings-aggregator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/gcc-job-listings-aggregator"
        }
    }
}

```

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/RsV0gettOojCtrfvQ/builds/RPuUMftSHc4Kx9hxg/openapi.json
