# Wuzzuf Jobs Scraper (`automation-lab/wuzzuf-jobs-scraper`) Actor

Search Wuzzuf and extract structured Egypt and MENA vacancies with employer, location, salary, work mode, skills, requirements, dates, and URLs.

- **URL**: https://apify.com/automation-lab/wuzzuf-jobs-scraper.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Jobs
- **Stats:** 1 total users, 1 monthly users, 50.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

## Wuzzuf Jobs Scraper

Extract structured **Wuzzuf jobs** from Egypt and the wider MENA market.
Search by occupation or skill, start from a Wuzzuf search URL, apply practical
location and work-mode filters, and save clean vacancy records to an Apify
dataset.

The Actor returns job ID, title, employer, location, salary, employment type,
workplace mode, skills, requirements, posting date, description, and canonical
URL. Use it for one-time market analysis or schedule it for recurring vacancy
monitoring.

### What does Wuzzuf Jobs Scraper do?

Wuzzuf Jobs Scraper opens public Wuzzuf search pages and extracts the structured
vacancy data supplied by those pages.

It can:

- run one or many keyword searches;
- process real `wuzzuf.net/search/jobs` URLs;
- scan multiple result pages;
- deduplicate vacancies by stable Wuzzuf job ID;
- filter by area, city, or country text;
- filter by on-site, remote, or hybrid work;
- filter by employment type;
- keep vacancies posted within a recent time window;
- stop at an exact maximum number of accepted jobs;
- return full descriptions and requirements as plain text.

### Who is this Wuzzuf jobs extractor for?

#### Recruiters and staffing teams

Build a current list of vacancies by role, employer, location, seniority, or
workplace arrangement.

#### Job-market analysts

Compare requested skills, salary disclosure, workplace modes, and hiring demand
across Cairo, Alexandria, Egypt, and other MENA locations represented on
Wuzzuf.

#### Sales and workforce intelligence teams

Identify companies hiring for relevant functions and route public vacancy data
to a CRM, spreadsheet, warehouse, or lead-scoring pipeline.

#### Job seekers and career researchers

Collect a focused dataset instead of opening many result and detail pages
manually.

#### Automation teams

Schedule the Actor and compare run datasets by stable `jobId` to find newly seen,
changed, or expired vacancies in your own workflow.

### Why use this Actor?

- **Full job records:** descriptions and requirements are included, not only
  search-card snippets.
- **Stable identifiers:** each result includes its Wuzzuf job ID and canonical
  URL.
- **Useful filters:** location, workplace, job type, and posting recency ensure
  only accepted records are charged and saved.
- **MENA-aware output:** location is split into area, city, and country fields.
- **Monitoring-ready:** ISO timestamps and stable IDs work well in scheduled
  dataset comparisons.
- **Bounded execution:** `maxItems` and `maxPagesPerSearch` prevent accidental
  open-ended runs.

### What Wuzzuf job data can I extract?

| Field | Meaning |
| --- | --- |
| `jobId` | Stable Wuzzuf vacancy identifier |
| `title` | Job title |
| `company` | Employer name, `Confidential`, or `null` |
| `location` | Combined area, city, and country |
| `country`, `city`, `area` | Separate location components |
| `salary` | Range, currency, period, paid flag, and extra details |
| `jobTypes` | Full Time, Internship, Part Time, or another published type |
| `workplace` | On-site, Remote, Hybrid, or `null` |
| `careerLevel` | Published seniority level |
| `experienceYears` | Minimum and maximum experience |
| `skills` | Wuzzuf skills and keywords |
| `workRoles` | Wuzzuf role categories |
| `description` | Plain-text job description |
| `requirements` | Plain-text candidate requirements |
| `postedAt`, `expiresAt` | ISO 8601 source timestamps |
| `vacancies` | Published number of openings |
| `url` | Canonical vacancy URL |
| `searchUrl` | Search that produced the result |
| `scrapedAt` | Extraction timestamp |

### How to scrape Wuzzuf jobs

1. Open the Actor in Apify Console.
2. Enter one or more search queries such as `data analyst`.
3. Optionally add Wuzzuf search URLs.
4. Add a location, workplace, job-type, or recency filter if needed.
5. Set `maxItems` to the maximum jobs you want saved.
6. Click **Start**.
7. Open the **Dataset** tab to inspect, download, or integrate the results.

A minimal input is:

```json
{
  "searchQueries": ["data analyst"],
  "maxItems": 25
}
```

### Input parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `searchQueries` | string array | none | Titles, skills, or keywords searched on Wuzzuf |
| `startUrls` | request list | none | HTTPS Wuzzuf search result URLs |
| `location` | string | none | Case-insensitive area, city, or country substring |
| `workplace` | enum | none | `On-site`, `Remote`, or `Hybrid` |
| `jobType` | enum | none | Full Time, Part Time, Internship, Freelance / Project, or Shift Based |
| `postedWithinDays` | integer | none | Keep jobs from the last 1–365 days |
| `maxItems` | integer | `100` | Maximum accepted jobs across all searches |
| `maxPagesPerSearch` | integer | `20` | Maximum pages scanned per query or URL |

At least one `searchQueries` entry or `startUrls` entry is required.

### Search Wuzzuf Alexandria jobs

Use a location filter to collect Wuzzuf Alexandria jobs from a wider search:

```json
{
  "startUrls": [
    { "url": "https://wuzzuf.net/search/jobs/?q=software%20engineer" }
  ],
  "location": "Alexandria",
  "maxItems": 20,
  "maxPagesPerSearch": 10
}
```

The location filter checks the combined area, city, and country published by
Wuzzuf. It does not infer missing geography.

### Monitor remote Wuzzuf jobs

Create a scheduled Apify Task with input such as:

```json
{
  "searchQueries": ["software engineer", "data analyst"],
  "workplace": "Remote",
  "postedWithinDays": 30,
  "maxItems": 100,
  "maxPagesPerSearch": 20
}
```

Schedule it daily or weekly. Use `jobId` as the key when comparing datasets. The
Actor supplies snapshots; change detection, alerts, and historical retention
are configured in your downstream automation.

### Output example

A current run returns records shaped like this:

```json
{
  "jobId": "03aeedc2-994f-4e9c-a749-b782650b673a",
  "title": "Software Quality Control Engineer.",
  "company": "Softxpert Incorporation",
  "location": "Alexandria, Egypt",
  "country": "Egypt",
  "city": "Alexandria",
  "area": null,
  "salary": {
    "min": null,
    "max": null,
    "currency": null,
    "period": null,
    "additionalDetails": null,
    "isPaid": true
  },
  "jobTypes": ["Full Time"],
  "workplace": "Hybrid",
  "careerLevel": "Experienced",
  "experienceYears": { "min": 1, "max": 3 },
  "skills": ["Computer Science", "QC", "QA"],
  "workRoles": ["IT/Software Development", "Quality"],
  "description": "Create and execute software test scenarios...",
  "requirements": "Bachelor's degree in Computer Science...",
  "postedAt": "2026-07-29T11:42:50.000Z",
  "expiresAt": "2026-09-27T11:42:50.000Z",
  "vacancies": 1,
  "url": "https://wuzzuf.net/jobs/p/c0tpyxxdivc6-software-quality-control-engineer-softxpert-incorporation-alexandria-egypt",
  "searchUrl": "https://wuzzuf.net/search/jobs/?q=software%20engineer",
  "scrapedAt": "2026-08-01T07:44:24.000Z"
}
```

Source fields can be `null` when a company hides them or does not publish them.

### How much does it cost to extract Wuzzuf jobs?

The Actor uses pay-per-event pricing:

- a **$0.005 start event** once per run;
- an item event only for each accepted job saved to the dataset.

The current item tiers decrease with account tier:

| Tier | Price per saved job |
| --- | ---: |
| FREE | $0.000920 |
| BRONZE | $0.000800 |
| SILVER | $0.000624 |
| GOLD | $0.000480 |
| PLATINUM | $0.000320 |
| DIAMOND | $0.000224 |

At the FREE item rate, 100 saved jobs cost about **$0.10** including the start
event, and 1,000 saved jobs cost about **$0.93**. Filtered-out, duplicate, and
failed records are not item events. Your exact total follows your active Apify
pricing tier and accepted result count.

### Tips for reliable and efficient runs

- Start with `maxItems` between 20 and 100 while refining filters.
- Increase `maxPagesPerSearch` when a narrow client-side filter needs to scan
  deeper result pages.
- Prefer a specific query instead of scanning a broad query with many filters.
- Use stable query sets in scheduled Tasks so datasets remain comparable.
- Keep `jobId`, `postedAt`, and `expiresAt` in downstream tables.
- Treat missing salary as undisclosed, not as zero.
- Avoid launching many overlapping runs against the same searches.

### Pagination, deduplication, and limits

Wuzzuf currently returns about 15 jobs per search page. The Actor advances the
source `start` parameter and reuses one healthy browser session.

Jobs are deduplicated across all supplied queries and URLs by `jobId`. A duplicate
is neither saved nor charged again.

`maxItems` is global for the run. `maxPagesPerSearch` applies independently to
each query or start URL.

### Failure behavior and limitations

- Wuzzuf protects pages with a browser challenge, so the Actor uses an Apify
  datacenter proxy session and a browser.
- If the challenge cannot be completed after bounded session rotation, the run
  fails instead of returning a misleading empty success.
- Only public Wuzzuf search pages are supported; profile, login, application,
  and private employer pages are not.
- The Actor does not apply to jobs or contact employers.
- Source data can change or disappear between runs.
- Filters operate on values Wuzzuf publishes in each record.
- `postedWithinDays` uses the source posting timestamp.
- The Actor provides snapshots. It does not itself send alerts or calculate a
  historical diff.

### Export Wuzzuf jobs to Excel, CSV, or JSON

Open the run dataset and select a download format in Apify Console. Available
formats include JSON, CSV, Excel, XML, and RSS.

For recurring pipelines, use the dataset API rather than downloading manually.
Stable IDs make database upserts straightforward.

### Integrate with Google Sheets, Make, Zapier, or webhooks

Common workflows include:

1. schedule the Actor daily;
2. wait for the run-success webhook;
3. fetch the default dataset;
4. upsert rows into a spreadsheet, CRM, or warehouse by `jobId`;
5. notify a channel only for IDs not seen in the previous dataset.

Apify integrations can connect runs with Make, Zapier, Slack, Google Sheets,
webhooks, and custom services.

### Run through the Apify API with cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~wuzzuf-jobs-scraper/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "searchQueries": ["data analyst"],
    "location": "Cairo",
    "maxItems": 50
  }'
```

The response contains the run ID and links to its storage.

### Run with JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/wuzzuf-jobs-scraper').call({
  searchQueries: ['data analyst'],
  location: 'Cairo',
  maxItems: 50,
});

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

### Run with Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("automation-lab/wuzzuf-jobs-scraper").call(run_input={
    "searchQueries": ["data analyst"],
    "location": "Cairo",
    "maxItems": 50,
})

items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)
```

### Use Wuzzuf Jobs Scraper with MCP

Add the Apify MCP server to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/wuzzuf-jobs-scraper"
```

#### Claude Desktop

Add this remote MCP server to your Claude Desktop configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/wuzzuf-jobs-scraper"
    }
  }
}
```

#### Cursor

Open **Cursor Settings → MCP**, add a remote server named `apify`, and use:

```text
https://mcp.apify.com?tools=automation-lab/wuzzuf-jobs-scraper
```

#### VS Code

Add an HTTP MCP server to your VS Code MCP configuration with the same URL:

```json
{
  "servers": {
    "apify": {
      "type": "http",
      "url": "https://mcp.apify.com?tools=automation-lab/wuzzuf-jobs-scraper"
    }
  }
}
```

Example prompts:

- “Run Wuzzuf Jobs Scraper for data analyst roles in Cairo and return 25 jobs.”
- “Collect remote software engineer jobs posted in the last 30 days.”
- “Extract Wuzzuf software jobs in Alexandria and summarize common skills.”

### Responsible use and legality

This Actor extracts public vacancy information. You are responsible for your
use of the data and for complying with Wuzzuf's terms, applicable laws,
copyright, database rights, privacy obligations, and employment regulations.

Do not use the Actor to collect private account data, overwhelm the source,
republish protected content without permission, discriminate against
candidates, or send unsolicited messages. Store only the fields your workflow
needs and delete data when it is no longer required.

### Troubleshooting

#### Why did a run fail on a Wuzzuf challenge?

The Actor rotates a bounded datacenter proxy/browser session automatically.
Retry only after checking the run log for a temporary upstream challenge. If
failures persist, reduce overlapping runs and report the run ID.

#### Why did a filtered run return fewer jobs than `maxItems`?

`maxItems` is a maximum, not a guaranteed count. The source may have fewer
matching records, or `maxPagesPerSearch` may stop scanning prior to enough jobs
pass a narrow filter. Increase the page limit carefully or make the query more
specific.

#### Why is salary `null`?

Many employers do not disclose salary. The Actor preserves that absence rather
than inventing a value.

#### Can I scrape a single job URL?

Not as an input mode. Use a Wuzzuf search URL or query, then identify the job by
its canonical `url` or stable `jobId` in the output.

### Frequently asked questions

#### Does it cover Wuzzuf Egypt and MENA vacancies?

It returns locations represented in Wuzzuf search results, including Egypt and
other MENA markets. Coverage follows the live public source and the searches
you provide.

#### Can I monitor new Wuzzuf jobs?

Yes. Save the input as an Apify Task, schedule it, and compare dataset rows by
`jobId`. The Actor creates the snapshots; your integration controls retention,
diffs, and alerts.

#### Are filtered-out jobs charged?

No. The item event is emitted only for accepted, unique records pushed to the
default dataset.

#### Does it require my Wuzzuf account?

No. The supported workflow uses public search pages and does not accept Wuzzuf
credentials.

#### What happens when two queries return the same job?

The Actor saves and charges that job once per run.

### Related Actors

Explore other public-data automation from
[automation-lab on Apify](https://apify.com/automation-lab). Combine compatible
Actors through datasets, schedules, webhooks, and your own data pipeline.

# Actor input Schema

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

Job titles, skills, or keywords to search on Wuzzuf. You can combine these with Wuzzuf search URLs.

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

Optional Wuzzuf search result pages. Only https://wuzzuf.net/search/jobs URLs are accepted.

## `location` (type: `string`):

Keep jobs whose area, city, or country contains this text, for example Cairo, Alexandria, Egypt, or Saudi Arabia.

## `workplace` (type: `string`):

Optionally keep only on-site, remote, or hybrid vacancies.

## `jobType` (type: `string`):

Optionally keep only vacancies with this employment type.

## `postedWithinDays` (type: `integer`):

Keep only jobs posted within this many days, from 1 to 365.

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

Stop after saving this many unique jobs across all searches.

## `maxPagesPerSearch` (type: `integer`):

Safety limit for pages scanned per query or start URL. Each page normally contains 15 jobs.

## Actor input object example

```json
{
  "searchQueries": [
    "software engineer"
  ],
  "startUrls": [],
  "maxItems": 10,
  "maxPagesPerSearch": 20
}
```

# Actor output Schema

## `dataset` (type: `string`):

Default dataset with every extracted vacancy.

# 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 = {
    "searchQueries": [
        "software engineer"
    ],
    "startUrls": [],
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/wuzzuf-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 = {
    "searchQueries": ["software engineer"],
    "startUrls": [],
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/wuzzuf-jobs-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "software engineer"
  ],
  "startUrls": [],
  "maxItems": 10
}' |
apify call automation-lab/wuzzuf-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=automation-lab/wuzzuf-jobs-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/6sUWUerLTIbGWYMxA/builds/y4Iw1fHxqz71vmHYJ/openapi.json
