# Tunisia Tanitjobs Jobs Scraper (`scraper_guru/tunisia-tanitjobs-jobs-scraper`) Actor

Scrape public Tanitjobs Tunisia listings with employer, location, contract, experience, education, dates, and job descriptions.

- **URL**: https://apify.com/scraper_guru/tunisia-tanitjobs-jobs-scraper.md
- **Developed by:** [LIAICHI MUSTAPHA](https://apify.com/scraper_guru) (community)
- **Security:** Limited permissions
- **Stats:** 5 total users, 2 monthly users, 75.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Tunisia Tanitjobs Jobs Scraper

Collect publicly visible job listings from [Tanitjobs Tunisia](https://www.tanitjobs.com/jobs/). The Actor captures the listing URL and source page for traceability, and can optionally open job detail pages for additional fields.

### Important access note

Tanitjobs currently serves a Cloudflare security-verification page to some automated and browser requests. This Actor detects that response and does not solve or bypass the challenge. A successful local test crawl depends on Tanitjobs making the public page accessible to the Actor. The parser and crawler behavior can be tested offline with the included fixtures.

### Features

- Crawl the jobs feed or user-supplied Tanitjobs search pages.
- Follow observed result-page pagination, within a configurable page limit.
- Deduplicate listings by Tanitjobs job ID.
- Optionally enrich results from job detail pages.
- Extract job title, company, location/governorate, contract, work mode, salary, vacancy count, experience, education, languages, description, source date text, expiry date text, and keywords when present.
- Preserve source date text as published; dates are not guessed or silently normalized.
- Save run diagnostics in the `STATS` key-value record.

### Use cases

- Build a dated snapshot of public job advertisements on Tanitjobs.
- Explore advertised roles by Tunisian governorate, contract, and employer.
- Prepare a source-specific job-market report. This dataset is not a census of Tunisia's labor market and should not be combined with other portals as if the sources covered the same population.

### Input

```json
{
  "startUrls": [{"url": "https://www.tanitjobs.com/jobs/"}],
  "maxItems": 100,
  "maxPages": 10,
  "includeDetails": true,
  "maxConcurrency": 1
}
```

- `startUrls`: optional Tanitjobs `/jobs/` search pages or `/job/{id}/` detail pages.
- `maxItems`: maximum unique records to save (1-5,000).
- `maxPages`: maximum listing pages followed for each listing start URL (1-100).
- `includeDetails`: open job detail pages for fields not present in listing cards.
- `maxConcurrency`: capped at 3; default is 1 to keep requests conservative.

### Output

One dataset item per unique job listing. Fields that Tanitjobs does not provide remain `null` or an empty array. `date_posted_raw` and `expiration_date_raw` retain source text, which may be relative (for example, “Il'y a 2 jours”) or a local date format.

```json
{
  "listing_id": "1980860",
  "job_title": "COMPTABLE FOURNISSEUR",
  "company_name": "Infopro digital",
  "location": "Ariana, Tunisie",
  "governorate": "Ariana",
  "contract_type": "CDI, SIVP",
  "work_mode": null,
  "salary": null,
  "vacancies": 1,
  "experience_level": "1 à 3 ans",
  "education_level": "Licence, Bac + 3",
  "languages": "Français",
  "description": "Description as published by the employer...",
  "date_posted_raw": "Il'y a 2 jours",
  "expiration_date_raw": "29/10/2026",
  "keywords": ["Comptabilité", "CDI"],
  "job_url": "https://www.tanitjobs.com/job/1980860/comptable-fournisseur/",
  "source_page_url": "https://www.tanitjobs.com/jobs/",
  "scraped_at": "2026-10-02T12:00:00.000Z"
}
```

### Local development

```bash
npm install
npm test
apify run --input='{"maxItems":5,"maxPages":1,"includeDetails":false}'
```

### FAQ

#### Why did the run fail with a security verification message?

Tanitjobs or its security provider did not serve the public listing to that request. The Actor does not solve challenges or disguise automated access. Retry only when the page is accessible through normal, permitted means, or use an authorized data feed from the site.

#### Does this contain every job in Tunisia?

No. It contains records collected from Tanitjobs pages visited during a particular run. Listings can be duplicated, edited, removed, or expire, and many employers use other channels.

#### Are dates normalized?

No. Date strings are retained in `*_raw` fields to avoid converting relative or ambiguous dates into misleading timestamps.

# Actor input Schema

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

Optional Tanitjobs /jobs/ search pages or /job/ detail pages. Defaults to the public jobs feed.

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

Maximum unique job records to save across all start URLs.

## `maxPages` (type: `integer`):

Maximum number of search-result pages to follow per listing start URL.

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

Visit each unique job page for description, experience, education, languages, vacancies, and expiry date when available.

## `maxConcurrency` (type: `integer`):

Keep low to limit requests to Tanitjobs.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.tanitjobs.com/jobs/"
    }
  ],
  "maxItems": 20,
  "maxPages": 2,
  "includeDetails": true,
  "maxConcurrency": 1
}
```

# Actor output Schema

## `jobs` (type: `string`):

No description

## `runStats` (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 = {
    "startUrls": [
        {
            "url": "https://www.tanitjobs.com/jobs/"
        }
    ],
    "maxItems": 20,
    "maxPages": 2,
    "includeDetails": true,
    "maxConcurrency": 1
};

// Run the Actor and wait for it to finish
const run = await client.actor("scraper_guru/tunisia-tanitjobs-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 = {
    "startUrls": [{ "url": "https://www.tanitjobs.com/jobs/" }],
    "maxItems": 20,
    "maxPages": 2,
    "includeDetails": True,
    "maxConcurrency": 1,
}

# Run the Actor and wait for it to finish
run = client.actor("scraper_guru/tunisia-tanitjobs-jobs-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 '{
  "startUrls": [
    {
      "url": "https://www.tanitjobs.com/jobs/"
    }
  ],
  "maxItems": 20,
  "maxPages": 2,
  "includeDetails": true,
  "maxConcurrency": 1
}' |
apify call scraper_guru/tunisia-tanitjobs-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scraper_guru/tunisia-tanitjobs-jobs-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/bSHCAM6uEl8FSloaM/builds/5YSBjVWhJCKCcKbb9/openapi.json
