# Jobicy Jobs Scraper: Remote Job Listings (`mrbridge/jobicy-jobs-scraper`) Actor

Scrape remote job listings from Jobicy by search term, industry and location. One row per job with title, company, level, salary, publication time, canonical Jobicy URL and description as text and HTML. Last 7 days, contacts masked, no API key. Export to JSON, CSV or Excel.

- **URL**: https://apify.com/mrbridge/jobicy-jobs-scraper.md
- **Developed by:** [MrBridge](https://apify.com/mrbridge) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 job listings

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/actors/running/actors-in-store.md#pay-per-event

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

## Jobicy Jobs Scraper

Jobicy Jobs Scraper collects remote job listings from Jobicy (https://jobicy.com). Search by term, industry and location, and get one clean row per job, ready for JSON, CSV or Excel. No API key is needed.

To search several job boards at once from Claude or ChatGPT, use the [remote jobs MCP server](https://apify.com/mrbridge/remote-jobs-mcp).

Enter `python` as a search term and set `maxItems` to 10: the Actor returns the 10 most recent remote Python jobs with title, company, location, level, salary when stated, publication time, the canonical Jobicy URL and the job description as text and as HTML. E-mail addresses and phone numbers found in the descriptions are masked, links are kept.

### What is Jobicy Jobs Scraper?

Jobicy publishes a feed of remote jobs. The Actor reads that feed through its public API, applies your filters, removes duplicates and returns structured rows. Jobicy serves a sliding window of the last 7 days, delayed by 3 hours, newest first, so older listings are not available.

#### What data can I extract with it?

One row per job: source, job ID, title, company, company logo, location, remote flag, job types, level, industries, tags, salary (minimum, maximum, currency and period when Jobicy states them), publication time, canonical Jobicy URL, description as text and as HTML, scrape time, plus the Jobicy slug and excerpt.

#### How can I use the results?

- Feed a remote job board or a newsletter with fresh listings and a link back to each Jobicy page.
- Track which companies hire for a skill, a level or a region over the week.
- Compare stated salaries by industry, currency and period.
- Send new matches for a search term to a spreadsheet, a chatbot or a notification service.

### Data source and terms

All rows come from Jobicy (https://jobicy.com), through its public API. Jobicy asks anyone who reuses the data to follow these terms, and so does this Actor:

- **Credit Jobicy** with a direct link to the source wherever you republish the data.
- **Keep the canonical URL.** Every row carries it in the `url` field. Send applicants to that URL, never to a copy.
- **Window of 7 days, 3 hours late.** Jobicy exposes the last 7 days only, and a listing appears about 3 hours after it is published.
- **One synchronization per hour at most.** The feed is refreshed about once an hour, so a schedule faster than hourly returns the same rows. Schedule the Actor no more often than that.
- **Contacts are masked.** E-mail addresses and phone numbers found in titles, excerpts and descriptions are replaced by neutral markers before the rows are returned. Links are kept as Jobicy sends them, including the links inside `descriptionHtml`. A `mailto:` or `tel:` link in `descriptionHtml` is replaced by its masked text.

The `OUTPUT` record of each run repeats the coverage note and the attribution to give to Jobicy.

### How to use it

1. Open the Actor in Apify Console.
2. Enter one or more search terms, and optionally pick industries and locations.
3. Set `maxItems` and start the run. Rows appear in the dataset as they are delivered.

### Input

| Field | Meaning | Default |
|---|---|---|
| `searchTerms` | Up to 10 terms of 3 to 50 bytes. One request per term | empty (latest jobs) |
| `categories` | Jobicy industries. One request per industry | empty (all) |
| `locations` | Jobicy locations. One request per location | empty (all) |
| `jobTypes` | Keep jobs with one of these types, case-insensitive (for example `full-time`) | empty (all) |
| `postedWithinDays` | Keep jobs published in the last N days (1 to 365). Jobicy holds 7 days at most | empty |
| `maxItems` | Hard cap on jobs returned and billed, 1 to 10000 | 100 |
| `includeDescription` | Add the description as text and HTML | `true` |

The Console form pre-fills `searchTerms` with `python` and `maxItems` with 10. Example input:

```json
{
  "searchTerms": [
    "python"
  ],
  "maxItems": 10
}
```

Terms, industries, locations and job types are lowercased, deduplicated and sorted. The run plans one request per combination of term, location and industry (an empty list counts as one). The industries `admin` (DevOps) and `seller` (Sales) keep the legacy Jobicy names.

Invalid input ends the run successfully with one `BAD_INPUT` row in the `errors` dataset and no job. It covers an unknown industry or location, a term that is empty, shorter than 3 or longer than 50 bytes, more than 10 terms, a value of the wrong type, and more than 20 planned requests. If Jobicy itself refuses a first request as invalid (HTTP 400), the run also writes one `BAD_INPUT` row, with the HTTP status and the message of the API, and ends there with `stoppedBy` set to `badInput`.

### Output

Jobs go to the default dataset, one row per job, in the order Jobicy gives them (newest first). Problems go to a separate `errors` dataset and are never billed. The `OUTPUT` record of the key-value store summarizes the run.

| Field | Type | Meaning |
|---|---|---|
| `source` | string | Always `Jobicy` |
| `jobId` | string | Jobicy job ID |
| `title` | string | Job title |
| `company` | string | Company name |
| `companyLogo` | string or null | Logo URL |
| `location` | string or null | Places where the job can be done, as Jobicy writes them (`Anywhere` when open), with single spaces |
| `remote` | boolean | Always `true` |
| `jobTypes` | array | For example `Full-Time`, `Contract` |
| `level` | string or null | Seniority level |
| `categories` | array | Jobicy industries, as display names |
| `tags` | array | Always empty, Jobicy does not serve tags |
| `salaryMin`, `salaryMax` | number or null | Stated salary bounds |
| `salaryCurrency` | string or null | Currency code, never guessed. Null when the job states no salary amount |
| `salaryPeriod` | string or null | `hourly`, `daily`, `weekly`, `fortnightly`, `monthly` or `yearly`. Null when the job states no salary amount |
| `salaryText` | null | Always empty, the salary is structured |
| `publishedAt` | string or null | Publication time, ISO 8601 in UTC |
| `url` | string | Canonical Jobicy page of the job |
| `descriptionText` | string or null | Description as text, line breaks kept |
| `descriptionHtml` | string or null | Description as HTML |
| `scrapedAt` | string | Time the row was built, ISO 8601 in UTC |
| `jobSlug` | string or null | Jobicy slug |
| `excerpt` | string or null | Jobicy excerpt as text |

`descriptionText` and `descriptionHtml` are absent when `includeDescription` is `false`. The other fields are always present, with `null` when Jobicy gives no value.

This is one real row from the example input above, built by the Actor from a stored Jobicy response:

```json
{
  "source": "Jobicy",
  "jobId": "157196",
  "title": "Cloud Platform Engineer",
  "company": "GitLab",
  "companyLogo": "https://jobicy.com/data/server-nyc0409/galaxy/mercury/2020/12/WRILS-201207055737-109952.jpg",
  "location": "Canada, USA",
  "remote": true,
  "jobTypes": [
    "Full-Time"
  ],
  "level": "Any",
  "categories": [
    "DevOps & Infrastructure"
  ],
  "tags": [],
  "salaryMin": 115000,
  "salaryMax": 194000,
  "salaryCurrency": "USD",
  "salaryPeriod": "yearly",
  "salaryText": null,
  "publishedAt": "2026-10-26T13:22:26.000Z",
  "url": "https://jobicy.com/jobs/157196-cloud-platform-engineer-2",
  "descriptionText": "GitLab is the intelligent orchestration platform for DevSecOps. GitLab enables organizations to increase developer productivity, improve operational efficiency, reduce security and compliance risk, and accelerate digital transformation. More than 50 million registered users and more than 50% of",
  "descriptionHtml": "GitLab</a> is the intelligent orchestration platform for DevSecOps. GitLab enables organizations to increase developer productivity, improve operational efficiency, reduce security and compliance risk, and accelerate digital transformation. More than 50 million registered users and more than 50% of ",
  "scrapedAt": "2026-10-26T18:53:00.000Z",
  "jobSlug": "157196-cloud-platform-engineer-2",
  "excerpt": "GitLab is the intelligent orchestration platform for DevSecOps. GitLab enables organizations to increase developer productivity, improve operational efficiency, reduce security and compliance risk, and accelerate digital transformation. More than 50 million registered users and more than 50% of the Fortune 100* trust GitLab to ship better, more secure software faster. The same principles built into…"
}
```

The example comes from a test fixture, so the description is cut at 300 characters and the HTML lost its opening tags. A real run returns the full description.

### Limits

- `maxItems` stops the run once that many jobs have been delivered. The default is 100.
- A run sends 20 requests at most to Jobicy for its plan (terms times locations times industries). Each request is followed through up to 10 pages, and a run sends 200 requests at most. A page holds `maxItems` rounded up to the next ten, at least 20 and at most 200 listings, the same size for every page of the run (the prefill of 10 jobs asks for pages of 20).
- `postedWithinDays` has no extra effect above 7, because Jobicy holds 7 days. A larger value only logs a warning.
- Requests are spaced by at least 2 seconds, retries included. A network error, a timeout, a truncated answer, a server error (5xx) or a 429 is retried up to 3 times in total. Every attempt is cut off after 45 seconds, body included. The retry starts after the longer of Retry-After (or the backoff) and the limiter interval, counted from the start of the failed attempt.
- After 3 blocked responses in a row the run stops cleanly and ends SUCCEEDED.
- Each run is a snapshot of the feed at that moment.
- After a reboot, `jobsCharged` in `OUTPUT` counts the jobs found in the dataset as billed. A job pushed but not yet billed when the run stopped is counted once too many (one job at most). The billed events of the run are the reference.

### Billing

One event is billed per delivered job. Errors, duplicates and filtered-out listings are never billed. The Pricing tab of the Actor shows the current prices.

When the platform moves a run to another server or restarts it while it works, the run picks up where it was. It saves its progress after every page, and on a restart it first reads the jobs already in its dataset: a job already returned is neither returned nor billed again, and the `OUTPUT` counters cover the whole run. In the rare case where the run stops between saving a job and billing it, that job is delivered once and never billed.

### Run summary and early stops

`stoppedBy` in the `OUTPUT` record says why a run ended early. It keeps the first reason only, so a `pageBudget` stop hides a `maxItems` or `chargeLimit` stop that would have come later.

- `null`: all the requested work was done.
- `maxItems`: the `maxItems` cap was reached.
- `chargeLimit`: the maximum charge set for the run was reached.
- `deadline`: the run reached its internal time limit.
- `circuitOpen`: too many blocked responses in a row.
- `pageBudget`: the page budget of the run was spent.
- `badInput`: Jobicy refused the request itself as invalid (HTTP 400 on a first page). A `BAD_INPUT` row holds the status and the message of the API. A 400 on a later page is an expired cursor and only ends that walk, with an `UPSTREAM_ERROR` row.
- `fetchFailed`: the last walk executed ended on a page that could not be fetched, even after its attempts. That page and the next ones of the walk were not read. A failed walk before the last one does not set it, the run goes on with the next walk and `failedWalks` lists it. A reason already recorded (for example `maxItems`) is kept instead.

A run plans one walk per combination of term, location and industry, up to 20. Each walk follows its pages until Jobicy has no more. A walk that ends on a `FETCH_FAILED` is counted in `walksFailed` and listed in `failedWalks` (20 entries at most, in run order), each with its `walk` (the first-page request of the walk), the `lastPageRead` of that walk (0 when its first page failed), the `kind` (always `FETCH_FAILED`) and the `httpStatus` of an unexpected answer when there was one. The `coverageNote` then adds how many of the planned walks ended on an error, for example "1 of 3 walks ended on an error". A walk that ends on another error row (`TARGET_BLOCKED`, `RATE_LIMITED`, `UPSTREAM_ERROR` or `SCHEMA_CHANGED`) has its row in the `errors` dataset and is counted in `errorsByKind` only.

Two more fields show how far the run went: `pagesPlanned` is the number of pages the run planned to read at most (the page budget of every walk added up, capped by the run budget of 200), and `lastPageRead` is the number of the last page read by the last walk that read one (the counter restarts at each walk), or `null` when that walk read none. A non-empty `errorsByKind` does not always mean that the run stopped: a `LISTING_INVALID` row skips one listing and stops nothing, and a failed walk lets the other walks run.

`pagesRereadAfterResume` counts the pages read a second time because the run was moved or restarted while it was applying them, usually 0 and one page at most per restart. If Jobicy refuses the saved cursor, the walk starts again from its first page and every page it had already read counts here. These pages are also counted in `pagesRead`, and their jobs already returned in `duplicatesSkipped`.

Changes in 0.1.5: `OUTPUT` has the new field `pagesRereadAfterResume`, and the page size asked from Jobicy follows `maxItems`. Input and rows are unchanged.

Changes in 0.1.2: `stoppedBy` can also be `badInput` or `fetchFailed`, and `OUTPUT` has the new fields `lastPageRead`, `pagesPlanned`, `walksFailed` and `failedWalks`. Rows keep the same fields. `salaryCurrency` and `salaryPeriod` are null when a job has no salary amount, `location` has single spaces, and `descriptionHtml` keeps its links. The other fields keep their names and meaning.

Every business error is written to the `errors` dataset with a `kind`: `BAD_INPUT`, `TARGET_BLOCKED`, `RATE_LIMITED`, `FETCH_FAILED`, `UPSTREAM_ERROR`, `SCHEMA_CHANGED` or `LISTING_INVALID`. The `OUTPUT` record counts them in `errorsByKind`. If the platform refuses to store a row, the run ends as FAILED and no `OUTPUT` record is written.

### More job data tools

- [remote job search for AI](https://apify.com/mrbridge/remote-jobs-mcp): remote openings by skill, location or salary from public job boards, with salary trends.
- [job listings with visa sponsorship filters](https://apify.com/mrbridge/arbeitnow-jobs-scraper): job listings from Arbeitnow by keyword, location, job type and visa sponsorship.
- [remote job listings from Remotive](https://apify.com/mrbridge/remotive-jobs-scraper): remote job listings from Remotive by title, category, location and date, salary included.

### Frequently asked questions

#### Why do I get fewer jobs than `maxItems`?

Jobicy holds the last 7 days only, and your terms, industries, locations and job types narrow that window. When the feed has no more matching listings, the run ends with `stoppedBy` set to `null`.

#### Can I use Jobicy Jobs Scraper via MCP?

Yes. Any Apify Actor can be called from an MCP client through the Apify MCP server. See the [Apify MCP documentation](https://docs.apify.com/platform/integrations/mcp) for the setup. For a ready-made MCP server over remote job boards, use [Remote Jobs MCP](https://apify.com/mrbridge/remote-jobs-mcp).

#### Your feedback

We're always working on improving the performance of our Actors. So if you've got any technical feedback for Jobicy Jobs Scraper or simply found a bug, please create an issue on the Actor's [Issues tab](https://apify.com/mrbridge/jobicy-jobs-scraper/issues).

More free tools, scrapers, MCP servers and data studies from the same team: [mr-bridge.com](https://mr-bridge.com).

### Legal & responsible use

The data comes from Jobicy (https://jobicy.com). Credit Jobicy when you republish it and keep the canonical Jobicy URL of each job. Jobicy has its own terms of use, and it may restrict automated access or commercial reuse. Before you rely on the output, in particular for commercial use, confirm that your use is permitted by those terms. You remain responsible for how you use the results and for complying with the source's terms and with the laws that apply to you.

# Changelog

This Actor's version history is a separate document: https://apify.com/mrbridge/jobicy-jobs-scraper/changelog.md

# Actor input Schema

## `searchTerms` (type: `array`):

Up to 10 terms, 3 to 50 bytes each. Lowercased and deduplicated. One request per term (Jobicy tag search). Leave empty to list the latest jobs.

## `categories` (type: `array`):

Jobicy industries to keep. One request per industry. Leave empty for every industry.

## `locations` (type: `array`):

Jobicy locations (geo) to keep. One request per location. Leave empty for every location.

## `jobTypes` (type: `array`):

Keep only jobs with one of these types, for example full-time or contract (case-insensitive). Leave empty to keep all.

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

Keep only jobs published in the last N days (1 to 365). Jobicy only serves the last 7 days, so a larger value has no more effect.

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

Hard cap on the number of jobs returned (and billed) in one run.

## `includeDescription` (type: `boolean`):

Add the job description as text and as HTML. E-mail addresses and phone numbers are masked, links are kept.

## Actor input object example

```json
{
  "searchTerms": [
    "python"
  ],
  "categories": [],
  "locations": [],
  "jobTypes": [],
  "maxItems": 10,
  "includeDescription": true
}
```

# Actor output Schema

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

Direct link to all dataset items produced by the run.

## `summary` (type: `string`):

Direct link to the OUTPUT record: requests made, jobs read, filtered out, returned and billed, errors by kind, the reason of an early stop and the Jobicy attribution.

# 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 = {
    "searchTerms": [
        "python"
    ],
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("mrbridge/jobicy-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 = {
    "searchTerms": ["python"],
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("mrbridge/jobicy-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 '{
  "searchTerms": [
    "python"
  ],
  "maxItems": 10
}' |
apify call mrbridge/jobicy-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mrbridge/jobicy-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/RT9rIBxrNzvVNRV5i/builds/lS15EMQurv8Igl5Lt/openapi.json
