# Handshake Jobs Scraper (`fetch_cat/handshake-jobs-scraper`) Actor

Export public Handshake jobs with titles, employers, locations, pay, dates, and descriptions for recruiting research, talent intelligence, and analysis.

- **URL**: https://apify.com/fetch\_cat/handshake-jobs-scraper.md
- **Developed by:** [Hanna Nosova](https://apify.com/fetch_cat) (community)
- **Categories:** Jobs, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.02 / 1,000 job 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?

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

## Handshake Jobs Scraper

Export anonymous public Handshake job listings from public Handshake search pages and direct job URLs. Build repeatable job-market snapshots for recruiting research, talent intelligence, and vacancy analysis without a Handshake login.

### What you get

This Handshake jobs scraper exports one row for each unique anonymous public job posting. Capture canonical job identity, employer, location, classification, published compensation, dates, and descriptions that Handshake exposes publicly.

### Who is it for?

- **Recruiting teams** building a reusable public job-market snapshot.
- **Talent-intelligence analysts** comparing public roles, locations, and compensation signals.
- **Researchers and operations teams** who need structured public job data in a spreadsheet, dashboard, or workflow.

### Ready-to-run examples

Open a public example to inspect its input, run it, or reuse it as a task:

- [Export Public Handshake Job Details](https://apify.com/fetch_cat/handshake-jobs-scraper/examples/public-handshake-job-details)
- [Export Austin Finance Jobs from Handshake](https://apify.com/fetch_cat/handshake-jobs-scraper/examples/austin-finance-jobs)

#### Discover a public category in a location

```json
{
  "keywords": ["finance"],
  "locations": ["Austin, Texas"],
  "maxItems": 10,
  "includeDescriptions": true
}
```

The Actor resolves these terms only through Handshake's public sitemap. Unsupported source categories or locations fail clearly instead of silently broadening your search.

#### Collect known public job pages

```json
{
  "jobUrls": [{ "url": "https://app.joinhandshake.com/public/jobs/11369785" }],
  "maxItems": 1,
  "remoteOnly": false
}
```

### Input settings

| Input | Description |
|---|---|
| `keywords` | Public Handshake job-category terms (for example, `finance`) resolved against the source sitemap. |
| `locations` | Public location terms (for example, `Austin, Texas` or `remote`) resolved against the source sitemap. |
| `searchUrls` | Public `joinhandshake.com/find-jobs/` pages used to discover public jobs. |
| `jobUrls` | Individual public `app.joinhandshake.com/public/jobs/{id}` pages. |
| `maxItems` | Maximum unique jobs to save, from 1 to 1,000. |
| `includeDescriptions` | Include the published HTML and normalized plain-text description. |
| `remoteOnly` | Save only jobs explicitly published as remote. |
| `minSalary` | Optional minimum published salary; jobs without a comparable published value are excluded. |

### Output fields

| Group | Fields |
|---|---|
| Identity | `jobId`, `jobUrl`, `title`, `scrapedAt`, `sourceSearchUrl` |
| Employer | `employerName`, `employerWebsite`, `employerLogoUrl`, `industry` |
| Classification | `jobType`, `roleGroups`, `employmentType`, `isRemote` |
| Location | `city`, `state`, `country` |
| Compensation | `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryUnit`, `paySchedule` |
| Dates | `datePosted`, `validThrough` |
| Description & application | `descriptionHtml`, `descriptionText`, `qualifications`, `applicationUrl` |

### Example result

```json
{
  "jobId": "11369785",
  "jobUrl": "https://app.joinhandshake.com/public/jobs/11369785",
  "title": "Software Developer (WSCE)-Junior",
  "employerName": "AMEWAS",
  "isRemote": false,
  "scrapedAt": "2026-09-03T12:37:11.608Z"
}
```

### Use cases

- Compare public job demand across roles or markets.
- Create periodic snapshots using `jobId` to identify new or changed listings.
- Export public job descriptions for recruiting and labor-market research.
- Feed a dataset into an internal dashboard, spreadsheet, or AI analysis workflow.

### API usage

Use the same input object with the Apify API. Replace `APIFY_TOKEN` with your token.

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('fetch_cat/handshake-jobs-scraper').call({
  jobUrls: [{ url: 'https://app.joinhandshake.com/public/jobs/11369785' }],
  maxItems: 1,
});
console.log(await client.dataset(run.defaultDatasetId).listItems());
```

```python
from apify_client import ApifyClient
client = ApifyClient('APIFY_TOKEN')
run = client.actor('fetch_cat/handshake-jobs-scraper').call(run_input={
    'jobUrls': [{'url': 'https://app.joinhandshake.com/public/jobs/11369785'}],
    'maxItems': 1,
})
print(client.dataset(run['defaultDatasetId']).list_items().items)
```

```bash
curl -X POST "https://api.apify.com/v2/acts/fetch_cat~handshake-jobs-scraper/runs?token=APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"jobUrls":[{"url":"https://app.joinhandshake.com/public/jobs/11369785"}],"maxItems":1}'
```

For agent workflows, connect through [Apify MCP](https://mcp.apify.com/?tools=fetch_cat/handshake-jobs-scraper) and provide the same input JSON. You can also schedule runs or export the default dataset as JSON, CSV, Excel, XML, RSS, or HTML.

### Pricing

Each run has a one-time start fee plus a charge for every unique public job saved to the default dataset. Review the current result rate and tier discounts on the [Actor Pricing tab](https://apify.com/fetch_cat/handshake-jobs-scraper/pricing) before a run starts.

### Limits and responsible use

This Actor supports only anonymous public Handshake pages. It does not access accounts, institution-personalized results, applications, student data, employer administration pages, or private data. A null field means the public job page did not publish that value; the Actor never guesses it.

### FAQ

**Do I need a Handshake account?** No. This Actor only uses anonymous public job pages.

**Why did I get fewer results than `maxItems`?** A source page may expose fewer public job links, or filters such as `remoteOnly` and `minSalary` can exclude jobs. Keyword/location discovery only supports categories and locations published in Handshake's current sitemap.

**Can I use it with the API or MCP?** Yes. Use the same input object through the Apify API, schedules, or the Actor's MCP tool.

**What can I export from a public Handshake job page?** When published, rows can include job identity, title, employer, location, employment type, compensation, dates, and descriptions. Missing public values remain null.

**Does it include applications or student data?** No. Those scopes are excluded from this public-data Actor.

### Related Actors

- [LinkedIn Jobs Scraper](https://apify.com/fetch_cat/linkedin-jobs-scraper)
- [Indeed Jobs Scraper](https://apify.com/fetch_cat/indeed-jobs-scraper)
- [Google Jobs Scraper](https://apify.com/fetch_cat/google-jobs-scraper)
- [Ashby Jobs Scraper](https://apify.com/fetch_cat/ashby-jobs-scraper)
- [Greenhouse Jobs Scraper](https://apify.com/fetch_cat/greenhouse-jobs-scraper)

### Troubleshooting

**No rows were returned.** Confirm that each submitted URL is a public Handshake search page or a public job page. A public page can contain no currently available listings, and filters can remove otherwise available jobs.

**A value is blank.** Handshake does not publish every field on every job. Blank values are retained as `null` rather than guessed, including compensation, dates, qualifications, and application links.

**I received fewer rows than requested.** `maxItems` is a ceiling, not a promise that a source page contains that many public jobs. Use several public search URLs when you want to cover distinct public job collections.

### Support

For help, open an issue from this Actor's Apify page and include: the public Handshake URL submitted; the input JSON with any sensitive values removed; the run ID; when the run occurred (including timezone); the expected and actual result counts; and one affected public job URL or job ID where available. Do not send account credentials, cookies, student data, application details, or other private information.

# Actor input Schema

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

Public Handshake SEO job category terms, such as finance, nursing, or marketing. Categories are matched against Handshake's public sitemap.

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

Public sitemap locations such as Austin, Texas, remote, or Boston, MA. Combine with a category to target an available public SEO route.

## `searchUrls` (type: `array`):

Optional source-owned joinhandshake.com/find-jobs URLs. Their public listing links are collected directly.

## `jobUrls` (type: `array`):

Optional individual app.joinhandshake.com/public/jobs/{id} URLs.

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

Maximum unique public jobs to save.

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

Include public description and qualification text.

## `remoteOnly` (type: `boolean`):

Save only jobs explicitly published as remote.

## `minSalary` (type: `number`):

Exclude jobs without a published salary meeting this numeric threshold.

## Actor input object example

```json
{
  "keywords": [
    "finance"
  ],
  "locations": [
    "Austin, Texas"
  ],
  "searchUrls": [],
  "jobUrls": [],
  "maxItems": 10,
  "includeDescriptions": true,
  "remoteOnly": false
}
```

# Actor output Schema

## `overview` (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": [
        "finance"
    ],
    "locations": [
        "Austin, Texas"
    ],
    "searchUrls": [],
    "jobUrls": [],
    "maxItems": 10,
    "includeDescriptions": true,
    "remoteOnly": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("fetch_cat/handshake-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": ["finance"],
    "locations": ["Austin, Texas"],
    "searchUrls": [],
    "jobUrls": [],
    "maxItems": 10,
    "includeDescriptions": True,
    "remoteOnly": False,
}

# Run the Actor and wait for it to finish
run = client.actor("fetch_cat/handshake-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": [
    "finance"
  ],
  "locations": [
    "Austin, Texas"
  ],
  "searchUrls": [],
  "jobUrls": [],
  "maxItems": 10,
  "includeDescriptions": true,
  "remoteOnly": false
}' |
apify call fetch_cat/handshake-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fetch_cat/handshake-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/d1766lMxlCv4MyUl4/builds/5dDM5v3y2DO6JOi8m/openapi.json
