# AI Training Jobs Scraper - Mercor, Alignerr, micro1, Outlier (`thirdwatch/ai-training-jobs-scraper`) Actor

Scrape AI training and expert gig listings from Mercor, Alignerr, micro1, Handshake AI and Outlier in one feed: title, hourly pay in USD, domain, eligible countries, skills, posting date and apply link.

- **URL**: https://apify.com/thirdwatch/ai-training-jobs-scraper.md
- **Developed by:** [Thirdwatch](https://apify.com/thirdwatch) (community)
- **Categories:** Jobs, AI
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 results

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

## AI Training Jobs Scraper - Mercor, Alignerr, micro1, Outlier

### What you get

> **Thirdwatch portfolio:** 8,800+ users across 140+ public Actors, 2M+ records delivered, >95% run success. [Explore all Thirdwatch Actors](https://apify.com/thirdwatch).

One feed of **AI training jobs** and expert gig listings from the five largest platforms: **Mercor jobs**, **Alignerr jobs**, **micro1 jobs**, **Handshake AI** fellowship opportunities and **Outlier AI jobs**. Every listing comes back in the same shape: title, hourly pay in USD, a normalized domain (software engineering, medicine, law, languages and more), eligible countries, skills, posting date and the apply link.

Use it to find well-paid AI trainer and data-annotation work, track pay rates by domain, or power a job board or newsletter for AI training gigs.

### Why use this AI training jobs scraper

- **Five platforms, one schema.** Stop checking five boards. Mercor, Alignerr, micro1, Handshake AI and Outlier listings share the same fields, so you can sort and filter them together.
- **Pay you can compare.** Pay strings like `$85-120/hr` or `Up to $130/hr` become numeric `payMinUsdHourly` / `payMaxUsdHourly` fields. Per-task, one-time and yearly rates keep their own `payPeriod` and are never mixed into hourly figures.
- **Clean Alignerr results.** Alignerr publishes the same role once per city (5,600+ postings for about 530 distinct roles). By default each role appears once, with `postingCount` showing how many postings it covers.
- **Normalized domains.** Every listing is mapped to one of 11 domains, so "physician", "RN" and "medical coder" all land in `medicine-health`.
- **Useful filters.** Keywords, domains, minimum hourly pay, country eligibility and posting age.
- **Works with empty input.** Run it with no settings and you get a balanced sample from all five platforms.

### Scrape AI training jobs in minutes

1. Open the Actor and pick the platforms you want (all five are selected by default).
2. Optionally add keywords, domains, a minimum hourly rate, a country or a posting window.
3. Set **Max results** and click **Start**. Download the results as JSON, CSV or Excel, or read them through the API.

```json
{
  "platforms": ["mercor", "alignerr", "micro1", "handshake", "outlier"],
  "domains": ["software-engineering", "stem-math"],
  "minHourlyPayUsd": 50,
  "postedWithinDays": 30,
  "maxResults": 100
}
```

### Input parameters

| Field | Type | Description |
|---|---|---|
| `platforms` | array | `mercor`, `alignerr`, `micro1`, `handshake`, `outlier`. Default: all five. |
| `keywords` | array | Keep listings whose title, skills or category contain any of these words. |
| `domains` | array | `software-engineering`, `stem-math`, `science`, `medicine-health`, `law`, `finance`, `language-translation`, `audio-voice`, `creative-writing`, `generalist`, `other`. |
| `minHourlyPayUsd` | integer | Keep listings whose top hourly rate is at least this. Listings without an hourly rate are excluded. |
| `country` | string | Country name or ISO code (`United States`, `IN`, `GBR`). Drops listings that list eligible countries without it; listings with no stated restriction are kept. |
| `postedWithinDays` | integer | Keep listings posted in the last N days. Listings without a posting date are excluded. |
| `maxResults` | integer | Total listings to return. Default 100. Spread evenly across platforms, then topped up from platforms with more listings. |
| `includeDescriptions` | boolean | Add the listing description, trimmed to about 4,000 characters. Default `false`. |
| `collapseDuplicates` | boolean | Show each Alignerr role once (default `true`). Turn off to get every city posting with its own location. |

### Output fields

| Field | Description |
|---|---|
| `platform` | `mercor`, `alignerr`, `micro1`, `handshake` or `outlier`. |
| `id` | The platform's listing ID. |
| `title` | Listing title. |
| `url` | Apply / listing page. |
| `companyName` | Client company, when the platform names it. Usually empty because most platforms do not name their AI lab clients. |
| `payMinUsdHourly`, `payMaxUsdHourly` | Hourly pay range in USD. Only one end is set when the platform shows "up to" pay. Empty for non-hourly pay. |
| `payRaw` | Pay as published, e.g. `$85-120/hr`, `Up to $18/hour`, `$400/task`. |
| `payPeriod` | `hour`, `task`, `one-time`, `month` or `year`. |
| `commitment` | E.g. `hourly`, `part-time`, `full-time`, `task-based`, `contract`. |
| `hoursPerWeek` | Expected weekly hours, when published (Mercor). |
| `workArrangement` | `remote`, `hybrid` or `onsite`, when known. |
| `eligibleCountries` | ISO 3166 alpha-2 codes of countries the listing is open to. Empty means no restriction was stated. |
| `locations` | Location text as published. |
| `domain` | Normalized domain (see input list). |
| `sourceCategory` | The platform's own category label. |
| `skills` | Skills listed by the platform (micro1, Outlier). |
| `postedAt` | Posting date, ISO 8601 UTC. |
| `postingCount` | Number of platform postings this row covers (Alignerr city duplicates). |
| `description` | Listing description, when `includeDescriptions` is on. |
| `scrapedAt` | When the listing was collected. |

#### Example result

```json
{
  "platform": "mercor",
  "id": "list_AAABoZQFI1_FwyFlEzJGgZW-",
  "title": "US Patent Attorney — Prosecution & Litigation",
  "url": "https://work.mercor.com/jobs/list_AAABoZQFI1_FwyFlEzJGgZW-",
  "companyName": null,
  "payMinUsdHourly": 110.0,
  "payMaxUsdHourly": 125.0,
  "payRaw": "$110-125/hour",
  "payPeriod": "hour",
  "commitment": "hourly",
  "hoursPerWeek": 20,
  "workArrangement": "remote",
  "eligibleCountries": ["US"],
  "locations": ["Remote"],
  "domain": "law",
  "sourceCategory": "Law",
  "skills": [],
  "postedAt": "2026-10-31T22:12:07Z",
  "postingCount": 1,
  "description": null,
  "scrapedAt": "2026-11-02T09:00:00Z"
}
```

### Common use cases

- **Job seekers and AI trainers:** find the best-paid remote AI training work in your field and country, and get new listings daily with a schedule.
- **Job boards and newsletters:** feed a niche "AI trainer jobs" board or weekly digest from one dataset.
- **Pay benchmarking:** compare hourly rates for coding, medicine, law or language experts across platforms.
- **Recruiting and market research:** see which domains AI labs are hiring experts for, and how that changes week to week.

### Compared to alternatives

- **vs single-platform scrapers:** one run covers Mercor, Alignerr, micro1, Handshake AI and Outlier with a shared schema, so there is nothing to merge.
- **vs building your own:** no endpoints or page changes to track across five sites; you consume one dataset.
- **Pay per result:** you pay only for listings returned, so a run that finds nothing costs nothing.

### Limitations

- **Outlier** shows a small, location-dependent set of open roles (often fewer than 10). The Actor checks every location Outlier offers, but the listings available can still differ from what you see in your own browser.
- **Handshake AI** needs one page per listing, so runs that include it take a little longer. Handshake publishes only the top hourly rate, not a range, and `id` is the opportunity page slug.
- **Alignerr** list results do not include the client city; with `collapseDuplicates` on, `locations` shows `Remote` and `postingCount` shows how many city postings were merged. Turn it off for per-city rows.
- **micro1** does not publish descriptions in its job feed, so `description` stays empty for micro1 rows.
- **Pay:** "up to" rates fill only `payMaxUsdHourly`. Non-hourly pay (per task, one-time, yearly) is kept in `payRaw` / `payPeriod` and left out of the hourly fields.
- **Domains** are assigned from the title, the platform's category and the listed skills. A few multi-discipline roles may land in a neighbouring domain.
- If one platform cannot be reached during a run, the Actor logs a warning and returns results from the others.

### FAQ

**Do I need an account or cookies?**

No. The Actor reads public listings only. There is no login to configure.

**How fresh is the data?**

Each run reads the live listings at that moment. Schedule the Actor daily to track new roles.

**Can I get only new listings?**

Set `postedWithinDays` to `1` or `2` and run it on a daily schedule.

**What happens when nothing matches my filters?**

The run finishes with an empty dataset and a status message suggesting wider filters. You are not charged for empty results.

### Related guides and Actors

- [Upwork Jobs Scraper](https://apify.com/thirdwatch/upwork-jobs-scraper) — Thirdwatch
- [LinkedIn Jobs Scraper](https://apify.com/thirdwatch/linkedin-jobs-scraper) — Thirdwatch
- [Wellfound Scraper](https://apify.com/thirdwatch/wellfound-jobs-scraper) — Thirdwatch
- [RemoteOK Scraper](https://apify.com/thirdwatch/remoteok-jobs-scraper) — Thirdwatch

Last verified: 2026-11

More scrapers at [thirdwatch.dev](https://thirdwatch.dev).

# Actor input Schema

## `platforms` (type: `array`):

Which platforms to collect listings from. Leave empty to search all five.

## `keywords` (type: `array`):

Optional. Keep listings whose title, skills or category contain any of these words, e.g. "python", "physician", "spanish". Case-insensitive.

## `domains` (type: `array`):

Optional. Keep only listings in these normalized domains.

## `minHourlyPayUsd` (type: `integer`):

Optional. Keep listings whose top hourly rate is at least this amount. Listings without an hourly rate are excluded when this is set.

## `country` (type: `string`):

Optional. Country name or ISO code, e.g. "United States", "IN", "GBR". Drops listings that name eligible countries without this one; listings with no stated restriction are kept.

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

Optional. Keep listings posted in the last N days. Listings without a posting date are excluded when this is set.

## `maxResults` (type: `integer`):

Maximum listings to return in total. Results are spread evenly across the selected platforms, then topped up from platforms with more listings.

## `includeDescriptions` (type: `boolean`):

Add the listing description (trimmed to about 4,000 characters) where the platform publishes one. micro1 descriptions are not included.

## `collapseDuplicates` (type: `boolean`):

Alignerr posts the same role once per city. When on (recommended), each role appears once with a postingCount. Turn off to get every city posting with its own location.

## Actor input object example

```json
{
  "platforms": [
    "mercor",
    "alignerr",
    "micro1",
    "handshake",
    "outlier"
  ],
  "keywords": [],
  "domains": [],
  "maxResults": 20,
  "includeDescriptions": false,
  "collapseDuplicates": true
}
```

# Actor output Schema

## `results` (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 = {
    "keywords": [],
    "maxResults": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("thirdwatch/ai-training-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 = {
    "keywords": [],
    "maxResults": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("thirdwatch/ai-training-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 '{
  "keywords": [],
  "maxResults": 20
}' |
apify call thirdwatch/ai-training-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,thirdwatch/ai-training-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/GbucU3Em8UCgNGdKR/builds/4SYe85uSWqH1Q59mX/openapi.json
