# Ashby Jobs Scraper — Any jobs.ashbyhq.com Job Board (`arcaedion/ashby-jobs-scraper`) Actor

Scrape every open job from any Ashby job board (jobs.ashbyhq.com) by URL or company name. Clean, normalized jobs with salary, remote flag, department and full description, plus new-jobs-only monitoring.

- **URL**: https://apify.com/arcaedion/ashby-jobs-scraper.md
- **Developed by:** [Mathews Motta](https://apify.com/arcaedion) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 job returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Ashby Jobs Scraper — scrape any jobs.ashbyhq.com job board

Ashby jobs scraper for any company job board on `jobs.ashbyhq.com`. Give it board URLs or just the company name (`notion`) and get every open job as clean, normalized JSON - no browser, no proxy, no login. Ashby is popular with fast-growing startups, so it is a good source for tech hiring data.

### Features

- **Any Ashby board** - a full URL, or just the board name; common spellings of a company name are tried on Ashby only.
- **Rich records** - title, locations, department and team, employment type, remote flag, seniority, published compensation range, posting date, full description and apply link.
- **Filters** - keywords, exclude keywords, locations, departments, remote only, posted within N days.
- **New-jobs monitoring** - schedule it and receive only postings you have not seen before.
- **Fast** - one request per board.

### Use cases

Startup hiring intelligence, recruiting and sales prospecting, salary benchmarking, job aggregators and new-role alerts.

### Pricing

**$1.50 per 1,000 jobs, pay only for jobs returned.** There is no charge for the run itself, for failed or unresolved entries, for duplicates, or for jobs removed by your filters. Set a maximum cost on the run and it stops cleanly when the limit is reached.

### Input

```json
{
    "companies": ["https://jobs.ashbyhq.com/notion","ramp"],
    "remoteOnly": true,
    "maxJobsPerCompany": 50
}
```

Each entry in **companies** is a Ashby board URL or a bare board name. Entries that belong to another ATS are reported as errors for that entry only, and the rest of the run continues. For other applicant tracking systems, or to find a board from a website or company name, use the **Multi-ATS Jobs Scraper** (see below).

### Output

Each job is one dataset item with a stable `id`. Main fields: title, company, locations, department, team, remote, employmentType, seniority, salaryMin/salaryMax/salaryCurrency/salaryPeriod (when published), postedAt, url, applyUrl, descriptionText (and descriptionHtml on request), plus stable `id` and `scrapedAt`.

Example item (description shortened):

```json
{
    "id": "ashby:1fc309c8-da20-4ff2-84c7-8b863ece2b0a",
    "source": "ashby",
    "title": "Software Engineer, AI Connections (Developer Platform)",
    "company": "Notion",
    "companySlug": "notion",
    "url": "https://jobs.ashbyhq.com/notion/1fc309c8-da20-4ff2-84c7-8b863ece2b0a",
    "applyUrl": "https://jobs.ashbyhq.com/notion/1fc309c8-da20-4ff2-84c7-8b863ece2b0a/application",
    "locations": [
        "San Francisco, California",
        "New York, New York"
    ],
    "remote": false,
    "department": "Engineering",
    "team": "Engineering",
    "employmentType": "Full-time",
    "salaryMin": null,
    "salaryMax": null,
    "postedAt": "2026-08-24T14:44:49.699Z",
    "descriptionText": "Who We Are\nNotion is the collaborative AI workspace where teams and agents think together...",
    "scrapedAt": "2026-10-23T00:27:44.205Z"
}
```

A `SUMMARY` record in the key-value store lists, per input entry, the board that was resolved, jobs found, jobs output and any error.

### Monitor for new jobs

Turn on **Only new jobs** and give the run a **Monitor name**. The first run outputs all matching jobs and remembers them; every later run outputs only postings that appeared since. Schedule it daily or hourly and send the results to Slack, email, a webhook or a spreadsheet through Apify integrations. Use a different monitor name per company list or filter set.

### FAQ

**What counts as the board name?**
The last part of the board URL: `jobs.ashbyhq.com/notion` has the name `notion`.

**Is salary included?**
Only when the company publishes compensation on the posting; otherwise the salary fields are `null`.

**Can I scrape many companies at once?**
Yes, up to 1,000 boards per run. Boards that cannot be found are listed in the SUMMARY record and are never charged.

**Is scraping Ashby career sites legal?**
The actor reads only publicly available job postings, the same data any visitor sees, and keeps the link to the original posting in every record. You are responsible for using the data in line with applicable laws and the terms of the sites involved.

### Related actors

- **[Multi-ATS Jobs Scraper](https://apify.com/arcaedion/ats-jobs-scraper)** - Greenhouse, Lever, Ashby, SmartRecruiters, Workable, Recruitee, Personio and Workday in one actor, with automatic detection from a website or company name.
- **[Company Hiring Signals](https://apify.com/arcaedion/company-hiring-signals)** - turn a list of companies into hiring activity signals.

# Actor input Schema

## `companies` (type: `array`):

One entry per company: an <b>Ashby board URL</b> such as <code>https://jobs.ashbyhq.com/notion</code>, or just the <b>board name</b> (the last part of the URL, e.g. <code>notion</code>) - common spellings of a company name are tried on Ashby only. Boards that cannot be found are reported in the SUMMARY record and never stop the run or cost anything.

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

Only keep jobs whose <b>title or description</b> contains at least one of these words or phrases (case-insensitive). Leave empty to keep everything. Example: <code>data engineer</code>, <code>python</code>.

## `excludeKeywords` (type: `array`):

Drop jobs whose <b>title</b> (or department) contains any of these words (case-insensitive). Example: <code>intern</code>, <code>sales</code>.

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

Only keep jobs located in at least one of these places. Matched as a case-insensitive substring of the job's location text, so use whatever the company uses: <code>Berlin</code>, <code>United States</code>, <code>London</code>, <code>Remote</code>.

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

Keep only jobs that are explicitly remote - flagged by the ATS or with 'remote' in the title / location. Jobs where remote status is unknown are dropped.

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

Only keep jobs first published in the last N days. 0 disables the filter. Jobs without a publish date are dropped when this is set.

## `departments` (type: `array`):

Only keep jobs whose department or team contains one of these words (case-insensitive substring), e.g. <code>Engineering</code>, <code>Product</code>.

## `onlyNewJobs` (type: `boolean`):

Output only jobs not seen in a previous run with the same <b>Monitor name</b>. Schedule the Actor daily to get just the fresh postings. <b>The first run of a monitor outputs all matching jobs</b> (and remembers them as the baseline); every later run outputs only newly appeared ones. Already-seen and filtered-out jobs are never output or charged.

## `monitorName` (type: `string`):

Identifies the saved list of already-seen jobs for 'Only new jobs'. Use different names for different company lists or filters (e.g. <code>fintech-engineering</code>) so they track new jobs independently. State is stored per name in a named key-value store under your account.

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

Add the plain-text job description (<code>descriptionText</code>).

## `includeDescriptionHtml` (type: `boolean`):

Also add the original HTML of the description (<code>descriptionHtml</code>). Increases dataset size.

## `maxJobsPerCompany` (type: `integer`):

Cap on jobs output per company, applied after filters. 0 means unlimited. Useful for very large employers (thousands of openings) and for quick test runs.

## Actor input object example

```json
{
  "companies": [
    "https://jobs.ashbyhq.com/notion",
    "ramp"
  ],
  "keywords": [
    "data engineer",
    "machine learning"
  ],
  "excludeKeywords": [
    "intern",
    "sales"
  ],
  "locations": [
    "Berlin",
    "London"
  ],
  "remoteOnly": false,
  "postedWithinDays": 7,
  "departments": [
    "Engineering"
  ],
  "onlyNewJobs": false,
  "monitorName": "default",
  "includeDescription": true,
  "includeDescriptionHtml": false,
  "maxJobsPerCompany": 50
}
```

# Actor output Schema

## `results` (type: `string`):

One normalized record per job posting.

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

Per-company status, counts, failures and charged items for this run.

# 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 = {
    "companies": [
        "https://jobs.ashbyhq.com/notion",
        "https://jobs.ashbyhq.com/ramp"
    ],
    "maxJobsPerCompany": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("arcaedion/ashby-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 = {
    "companies": [
        "https://jobs.ashbyhq.com/notion",
        "https://jobs.ashbyhq.com/ramp",
    ],
    "maxJobsPerCompany": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("arcaedion/ashby-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 '{
  "companies": [
    "https://jobs.ashbyhq.com/notion",
    "https://jobs.ashbyhq.com/ramp"
  ],
  "maxJobsPerCompany": 10
}' |
apify call arcaedion/ashby-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,arcaedion/ashby-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/OrYcXuPUBu4lhX86v/builds/2duyQSgBE0oTmBG9w/openapi.json
