# Ashby Jobs Scraper & API \[$0.9💰] Filters · Emails (`memo23/ashby-jobs-scraper`) Actor

Scrape every open job from any company on Ashby (jobs.ashbyhq.com) live via the public posting API — one request returns the whole board: title, full description, compensation, location, department and apply URL. Filter by title, location, department, type or date. Emails optional.

- **URL**: https://apify.com/memo23/ashby-jobs-scraper.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** Jobs, Agents, AI
- **Stats:** 22 total users, 2 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.90 / 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.

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

## Ashby Jobs Scraper & API — Any Company

Scrape **every open job from any company hosted on [Ashby](https://www.ashbyhq.com/)** (`jobs.ashbyhq.com`) — title, full description, compensation, location, department, and apply URL — straight from Ashby's public posting API. One request per company returns the whole board, fully detailed. No login, no anti-bot, no browser.

Every row is fetched **live from Ashby at run time** — not served from a pre-indexed job database — so closed roles disappear instantly, new postings appear the moment they're published, and any company on Ashby is covered, not just the ones a database happens to index.

![How Ashby Jobs Scraper works](https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-ashby.png)

***

### Why use this scraper

- **Complete boards in one call.** Ashby returns every open role for a company in a single API response — no pagination, no per-job detail fetches. Scraping OpenAI's 700+ roles is one request.
- **Full job detail, not just titles.** Each row carries the entire job: `descriptionHtml` + plain text, compensation range, all locations, employment type, workplace type, and the apply URL.
- **Fast and cheap.** No proxies required (the API has no anti-bot), so runs are quick and your cost stays low.
- **Normalized schema.** Output uses a consistent ATS schema that matches our other ATS scrapers (Lever, Greenhouse, SmartRecruiters) — write one parser, reuse it everywhere.
- **Flexible input.** Paste board URLs, individual job URLs, or just bare company slugs.
- **Contact emails on demand.** Flip on `enrichEmails` to turn a board into a lead list with a public contact address per company — billed only when an email is actually found.

***

### Overview

[Ashby](https://www.ashbyhq.com/) is a modern all-in-one recruiting platform used by hundreds of high-growth tech companies (Ramp, Notion, Linear, Vanta, Replit, Cursor, OpenAI, and many more). Each customer gets a public job board at `https://jobs.ashbyhq.com/{company}`.

This actor reads each company's board through Ashby's official, auth-free **posting API** and emits one clean row per open job. Because the API already includes the full job description and compensation inline, there's no second request per job — making this one of the fastest and cheapest job scrapers you can run.

***

### Supported inputs

| Input type | Example | Notes |
|---|---|---|
| **Board URL** | `https://jobs.ashbyhq.com/ramp` | The company's public Ashby board |
| **Job URL** | `https://jobs.ashbyhq.com/ramp/{jobId}` | The org slug is extracted; the whole board is scraped |
| **Bare org slug** | `ramp`, `notion`, `linear` | The part after `jobs.ashbyhq.com/` |

Mix any of these in one run. Provide them in **Start URLs** (URLs) and/or **Organization slugs** (bare slugs).

> **How do I find a company's Ashby slug?** Visit the company's careers page. If it redirects to (or embeds) `jobs.ashbyhq.com/{something}`, that `{something}` is the slug.

***

### Use cases

- **Job boards & aggregators** — ingest fresh, structured tech roles from hundreds of fast-growing companies.
- **Recruiting & sourcing tools** — track which companies are hiring for which roles, with compensation where disclosed.
- **Market & talent intelligence** — monitor hiring velocity, remote-vs-onsite mix, and salary bands across a basket of companies.
- **Lead generation** — companies actively hiring engineers/sales are buying signals for many B2B products.
- **Personal job search** — pull every role across your target companies into one searchable sheet.

***

### How it works

1. **Resolve** each input (board URL, job URL, or slug) to a company org slug.
2. **Fetch** `https://api.ashbyhq.com/posting-api/job-board/{org}?includeCompensation=true` — one HTTP call per company.
3. **Each job arrives fully detailed** in that response (description, compensation, locations, apply URL).
4. **Normalize** every job to a common ATS schema.
5. **Push** one row per job to the dataset.

Companies are fetched in parallel with a sliding-window concurrency cap. No proxy is needed, though you can supply one for IP rotation when scraping very large numbers of companies.

***

### Input configuration

| Field | Type | Default | Description |
|---|---|---|---|
| `startUrls` | array | – | Ashby board URLs, job URLs, or slugs (strings or `{url}` objects). |
| `organizations` | array | – | Bare Ashby org slugs, e.g. `["ramp","notion"]`. Merged with `startUrls`. |
| `maxItems` | integer | `5000` | Max job rows emitted across the whole run. |
| `maxConcurrency` | integer | `10` | How many company boards to fetch in parallel. |
| `titleKeyword` | string | – | Keep only jobs whose title contains this (case-insensitive). |
| `location` | string | – | Keep only jobs whose location contains this. |
| `department` | string | – | Keep only jobs whose department contains this. |
| `employmentType` | string | – | Keep only this type: FullTime / PartTime / Intern / Contract / Temporary. |
| `remoteOnly` | boolean | `false` | Keep only remote jobs. |
| `postedAfter` | string | – | Keep only jobs published on/after this date (YYYY-MM-DD). |
| `includeDescription` | boolean | `true` | Include `descriptionHtml` + `descriptionText`. Turn off for leaner/cheaper rows. |
| `includeRawJson` | boolean | `false` | Attach the original Ashby payload to each row under `raw`. |
| `enrichEmails` | boolean | `false` | Find a public contact email for each company (discovers its website, reads contact/about pages). Adds `contactEmail`, `contactWebsite` and an `emailEnrichment` object. Best-effort, billed per email found — never for a miss. |
| `qualifyByPayment` | boolean | `false` | Needs `enrichEmails`. Flags whether the company takes money online (Stripe, Shopify, PayPal, WooCommerce and more) via `takesPayments` + `paymentProcessors`. Reuses pages already fetched, so no extra cost. |
| `proxy` | object | – | Optional. Not required (no anti-bot); use only for IP rotation at scale. |

> **Filters run before a row is emitted**, so with pay-per-result pricing you only pay for jobs that match.

#### Example input

```json
{
  "startUrls": [
    "https://jobs.ashbyhq.com/ramp"
  ],
  "organizations": ["notion", "linear", "vanta"],
  "maxItems": 1000,
  "maxConcurrency": 10
}
```

***

### Output

One row per open job. Example (trimmed):

```json
{
  "ats": "ashby",
  "org": "ramp",
  "company": "Ramp",
  "jobId": "34413f8d-26bf-4bbc-8ade-eb309a0e2245",
  "globalId": "ashby:ramp:34413f8d-26bf-4bbc-8ade-eb309a0e2245",
  "title": "Security Engineer, Cloud",
  "department": "Engineering",
  "team": "Backend",
  "employmentType": "FullTime",
  "workplaceType": "Hybrid",
  "isRemote": true,
  "location": "New York, NY (HQ)",
  "locations": ["New York, NY (HQ)", "Miami, FL", "Remote (US)", "Remote (Canada)"],
  "address": { "postalAddress": { "addressRegion": "NY", "addressCountry": "USA", "addressLocality": "New York City" } },
  "compensation": { "compensationTierSummary": "$211.4K – $290.6K • Offers Equity" },
  "salaryText": "$211.4K – $290.6K • Offers Equity",
  "descriptionHtml": "<h1>About Ramp</h1><p>…</p>",
  "descriptionText": "About Ramp\nRamp is building the smart infrastructure for finance teams…",
  "publishedAt": "2026-04-07T17:12:35.753+00:00",
  "jobUrl": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245",
  "applyUrl": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245/application",
  "scrapedAt": "2026-06-12T15:53:01.683Z"
}
```

#### Key output fields

| Field | Description |
|---|---|
| `ats` | Always `"ashby"` — the source platform (useful when combining with other ATS scrapers). |
| `org` | Company board slug. |
| `company` | Company display name (resolved from the board). |
| `globalId` | Stable, unique key `ats:org:jobId` — use it to dedupe across runs. |
| `title` | Job title. |
| `department` / `team` | Org grouping as set by the company. |
| `employmentType` | `FullTime` / `PartTime` / `Intern` / `Contract` / `Temporary`. |
| `workplaceType` / `isRemote` | `Remote` / `Hybrid` / `OnSite`, plus a boolean remote flag. |
| `location` / `locations` | Primary location label + every listed location. |
| `compensation` / `salaryText` | Raw Ashby compensation object + a flattened human string (when the company discloses pay). |
| `descriptionHtml` / `descriptionText` | Full job description as HTML and as plain text. |
| `publishedAt` | When the role was published (ISO). |
| `jobUrl` / `applyUrl` | Public posting URL + application form URL. |

***

### FAQ

**Do I need a proxy?** No. Ashby's posting API is public and has no anti-bot. A proxy field is available only for optional IP rotation when scraping very large numbers of companies.

**Where does `company` come from?** Ashby's posting API doesn't return a display name, so we resolve it once per board from the public board page (e.g. "Ramp"), falling back to a title-cased slug if needed. It's never null.

**Can it discover all companies on Ashby?** No — Ashby has no public directory of all boards (the same is true for every Greenhouse/Lever/SmartRecruiters scraper). You supply the companies you care about by slug or board URL.

**How many jobs per company?** Whatever the company has open — from a handful to 700+. Use `maxItems` to cap total output and control cost.

**What if a slug isn't on Ashby?** That company is skipped with a warning (the API returns 404). The rest of the run continues normally.

**How fresh is the data?** Live — every run hits Ashby in real time.

***

### Support

Found a bug or need a field added? Open an issue on the actor's **Issues** tab in the Apify Console and we'll take a look.

***

### Additional services

Need a different ATS or job board? We also build scrapers for Greenhouse, Lever, SmartRecruiters, Workday, Indeed, LinkedIn, Glassdoor, and many more. Check our Apify Store profile.

***

### Explore more scrapers

- **Greenhouse Jobs Scraper** — open roles from any Greenhouse-hosted company.
- **Workday Jobs Scraper** — jobs from any Workday career site.
- **Indeed / LinkedIn / Glassdoor** — the major job boards, fast and structured.

***

### 🤖 For AI Agents & LLM Apps

Compact reference for AI agents calling this actor via the [Apify MCP server](https://mcp.apify.com) or the Apify API (actor: `memo23/ashby-jobs-scraper`).

**Purpose:** Scrape every open job from any company hosted on Ashby (`jobs.ashbyhq.com`) via Ashby's public posting API — one fully detailed row per job, with description, compensation, locations, and apply URL.

**Minimal input:**

```json
{ "organizations": ["ramp"], "maxItems": 25 }
```

Paste board URLs, job URLs, or slugs into `startUrls` instead (e.g. `https://jobs.ashbyhq.com/ramp`) — merged with `organizations`; a job URL scrapes that company's whole board.

**Output:** one row per open job — ats, org, company, jobId, globalId, title, department, team, employmentType, workplaceType, isRemote, location, locations\[], address {postalAddress}, compensation, salaryText, descriptionHtml, descriptionText, publishedAt, jobUrl, applyUrl, scrapedAt.

**Behaviors an agent should know:**

- `startUrls` and `organizations` are merged; one API call returns a company's entire board (can be 700+ jobs), so set `maxItems`.
- Filters (`titleKeyword`, `location`, `department`, `employmentType`, `remoteOnly`, `postedAfter`) run before a row is emitted.
- `includeDescription: false` drops `descriptionHtml`/`descriptionText` for leaner rows; `includeRawJson: true` attaches the original Ashby payload under `raw`.
- Use `globalId` (`ats:org:jobId`) to dedupe across runs. No public directory of all Ashby boards exists — you supply the companies.
- No proxy required (public API, no anti-bot); the `proxy` field is optional IP rotation for large runs.
- Pay-per-result billing — filters run before emit, so you only pay for matching jobs; see the Pricing tab on the actor page.

***

### ⚠️ Disclaimer

This actor collects only **publicly available** job-posting data exposed by Ashby's own public job-board API. It does not access any private, authenticated, or personal data, and it does not bypass any access control. You are responsible for using the scraped data in compliance with Ashby's terms, the source companies' terms, and all applicable laws (including data-protection regulations such as GDPR/CCPA). Use the data ethically and lawfully.

***

### SEO Keywords

Ashby scraper, AshbyHQ scraper, Ashby jobs scraper, jobs.ashbyhq.com scraper, Ashby job board API, Ashby ATS scraper, scrape Ashby jobs, Ashby careers scraper, ATS job scraper, applicant tracking system scraper, tech jobs scraper, startup jobs scraper, job postings API, company careers scraper, recruiting data, hiring data, compensation data scraper, remote jobs scraper.

# Actor input Schema

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

Ashby board URLs (e.g. https://jobs.ashbyhq.com/ramp) or individual job URLs (https://jobs.ashbyhq.com/ramp/{jobId}). Bare slugs also accepted.

## `organizations` (type: `array`):

Bare Ashby org slugs, e.g. \["ramp", "notion", "linear"]. The slug is the part after jobs.ashbyhq.com/. Merged with any Start URLs above.

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

Hard cap on job rows emitted across the whole run (across all companies). Use it to control billing — large boards like OpenAI have 700+ open roles.

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

How many company boards to fetch in parallel.

## `titleKeyword` (type: `string`):

Keep only jobs whose title contains this text (case-insensitive), e.g. "engineer".

## `location` (type: `string`):

Keep only jobs whose location (primary or secondary) contains this text, e.g. "remote", "London", "New York".

## `department` (type: `string`):

Keep only jobs whose department contains this text, e.g. "Engineering".

## `employmentType` (type: `string`):

Keep only jobs with this exact employment type.

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

Keep only jobs flagged remote.

## `postedAfter` (type: `string`):

Keep only jobs published on or after this date (YYYY-MM-DD). Ideal for scheduled monitoring runs that only want fresh roles.

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

Include `descriptionHtml` and `descriptionText` on each row. Turn off for leaner, cheaper rows when you only need title/location/compensation/links.

## `includeRawJson` (type: `boolean`):

Attach the original, unmodified Ashby job object to each row under a `raw` field. Useful for advanced fields not in the normalized schema. Off by default to keep rows lean.

## `enrichEmails` (type: `boolean`):

If enabled, tries to find a contact email for the company by discovering its website (Clearbit) and reading its contact/about pages. Adds contactEmail + contactWebsite columns plus a detailed emailEnrichment object. Best-effort, billed per contact email found; only charged when an email is returned, never for misses.

## `qualifyByPayment` (type: `boolean`):

Requires "Enrich with contact emails". Scans each business's website — reusing the pages already fetched for email discovery, so no extra cost or time — for payment processors and e-commerce platforms (Stripe, Shopify, PayPal, Paddle, Lemon Squeezy, WooCommerce, Square, Chargebee and more). Adds takesPayments (is this a real paying business?), paymentProcessors (which stack), stripeLiveKey (the public key if exposed) and paymentConfidence. Turn raw contacts into monetization-qualified leads. No extra charge — included with each enriched company.

## `proxy` (type: `object`):

Leave empty — the actor already routes all traffic through its own built-in residential proxy at no extra cost to you. Only set this if you want to use your own proxies.

## Actor input object example

```json
{
  "startUrls": [
    "https://jobs.ashbyhq.com/ramp"
  ],
  "organizations": [
    "notion",
    "linear"
  ],
  "maxItems": 5000,
  "maxConcurrency": 10,
  "remoteOnly": false,
  "includeDescription": true,
  "includeRawJson": false,
  "enrichEmails": false,
  "qualifyByPayment": false
}
```

# 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": [
        "https://jobs.ashbyhq.com/ramp"
    ],
    "organizations": [
        "notion",
        "linear"
    ]
};

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

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

```

## MCP server setup

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