# BuiltIn Jobs Scraper API (`dami_studio/builtin-jobs-scraper`) Actor

Lowest price on the market for Built In jobs: $0.81 per 1,000, under every established Built In scraper (the rest start at $0.95). Search any board or a whole company for title, company, all locations, workplace type, salary, seniority, skills and the exact posted date. No login.

- **URL**: https://apify.com/dami\_studio/builtin-jobs-scraper.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** Jobs, Lead generation, Integrations
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.81 / 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/platform/actors/running/actors-in-store#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

## Built In Jobs Scraper API

Pulls tech job listings out of [Built In](https://builtin.com) — the US/Canada startup and tech job board behind builtin.com, builtinnyc.com, builtinchicago.org, builtinaustin.com and the rest of the city sites.

Give it a search term, a location, or just a URL. You get one row per job: title, company, every location the role is open in, remote/hybrid/on-site, the posted salary range, seniority, the exact publish timestamp, industries, the tech stack listed on the card, and a one-paragraph summary.

**$0.81 per 1,000 jobs** ($0.00081 each), plus $0.001 each time a run starts — the lowest per-job price of any Built In jobs scraper on the Apify Store with an active user base. The next cheapest, `solidcode/builtin-scraper` (46 monthly users), is $0.95 per 1,000 even on its cheapest volume tier; the others charge $0.99, $1.00, $1.50, $2.99 and $3.50 per 1,000. (One brand-new listing with 5 users is priced lower; it has no track record yet.)

### What a row looks like

```json
{
  "jobId": "9546563",
  "title": "Principal Data Engineer, LLM/AI Platforms (Remote)",
  "companyName": "CrowdStrike",
  "companySlug": "crowdstrike",
  "companyUrl": "https://builtin.com/company/crowdstrike",
  "companyLogo": "https://static.builtin.com/cdn-cgi/image/.../Red%20Feather%20Icon%20White%20Background.png",
  "jobUrl": "https://builtin.com/job/principal-data-engineer-llm-ai-platforms-remote/9546563",
  "location": "USA",
  "locations": ["USA", "ON, CAN", "NS, CAN", "AB, CAN", "MB, CAN", "NB, CAN", "BC, CAN"],
  "locationCount": 7,
  "workplaceType": "Remote or Hybrid",
  "isRemote": true,
  "isHybrid": true,
  "isOnsite": false,
  "salaryText": "195K-320K Annually",
  "salaryMin": 195000,
  "salaryMax": 320000,
  "salaryPeriod": "year",
  "experienceLevel": "Expert/Leader",
  "postedAt": "2026-08-04T00:12:50.000Z",
  "postedLabel": "Reposted 3 Days Ago",
  "isFeatured": false,
  "industries": ["Cloud", "Computer Vision", "Information Technology", "Sales", "Security", "Cybersecurity"],
  "skills": ["Airflow", "AWS", "BigQuery", "Docker", "Kafka", "Kubernetes", "Python", "Snowflake", "Spark"],
  "summary": "As a Principal Data Engineer, you will design and implement LLM, AI-powered security data platforms, mentor engineers, and drive the adoption of data solutions across teams.",
  "employmentType": null,
  "validThrough": null,
  "benefits": [],
  "descriptionHtml": null,
  "descriptionText": null,
  "searchQuery": "data engineer",
  "searchUrl": "https://builtin.com/jobs?search=data+engineer",
  "page": 1,
  "position": 1,
  "scrapedAt": "2026-08-07T22:10:00.000Z"
}
```

`postedAt` is the real publish timestamp Built In records for the listing, not a guess parsed from "3 Days Ago". `postedLabel` keeps the human string in case you want it. On the rare page template that omits the exact timestamp, `postedAt` falls back to the relative label.

The last five fields — `employmentType`, `validThrough`, `benefits`, `descriptionHtml`, `descriptionText` — stay `null` unless you turn on **Include the full job description** or paste a job URL directly. See below.

### Input

```json
{
  "searchQueries": ["data engineer", "product manager"],
  "location": "Austin, TX",
  "remotePreference": "remote",
  "maxItems": 200
}
```

| Field | What it does |
|---|---|
| `searchQueries` | One search term per line. |
| `location` | Plain text — `Austin, TX`, `New York`, `Chicago`. Resolved through Built In's own location lookup. Empty means every location. |
| `searchRadius` | `5mi` to `100mi` around that location. |
| `remotePreference` | `remote`, `hybrid`, `office`, or blank for all. |
| `category` | Built In's own categories: `engineering`, `data-analytics`, `product`, `designer`, `sales`, and so on. |
| `experienceLevel` | `internship`, `entry-level`, `junior`, `mid-level`, `senior`, `expert-leader`. |
| `postedWithinDays` | `1`, `3`, `7` or `30`. |
| `startUrls` | Paste Built In pages directly. See the next section. |
| `includeJobDescription` | Off by default. Adds the full posting text at no extra charge per job. |
| `maxItems` | Hard cap on rows, 1–10000. You are charged per row returned. |

Run it with no input at all and it returns a single labelled sample row so you can see the shape. That row carries no per-job charge — the run costs only the $0.001 start fee.

#### URLs you can paste

| URL | What you get |
|---|---|
| `https://builtin.com/job/lead-data-engineer/10586279` | That one job, with the full description. `summary` and `skills` are card-only fields and stay empty on this route |
| `https://builtin.com/jobs?search=product+manager` | Everything that search returns |
| `https://builtin.com/jobs/remote/engineering` | Every remote engineering role |
| `https://builtin.com/company/crowdstrike/jobs` | One company's whole board |
| `https://builtinnyc.com/jobs` | A city site's board |

Filters that Built In puts in the path — `/remote`, `/hybrid`, `/office`, `/senior`, `/entry-level`, category names — are all understood, so if you can build the view in your browser you can paste it here.

### Full descriptions

`includeJobDescription: true` opens each job's own page and adds `descriptionText` (plain text, typically 6,000–10,000 characters), `descriptionHtml`, `employmentType` (`FULL_TIME`, `PART_TIME`, `INTERN`, `CONTRACTOR`), `validThrough` (the date Built In will close the listing), and `benefits` — Built In publishes a long, unusually specific benefits list, 60+ entries for a large employer.

It is one extra HTTP request per job, eight at a time. A 100-job run went from about 11 seconds to 26. Descriptions came back on 100/100 jobs in that run, 4,248 to 13,409 characters each, median 6,427. **The price per job does not change.**

### How much you get back

Built In serves 25 job cards per request when you give it a search term, and 45–65 when you only use filters. Real runs on Apify, 1 GB:

| Run | Rows | Wall clock |
|---|---|---|
| `data engineer`, Austin TX | 5 | 4.3 s |
| `software engineer`, nationwide | 300 | 32 s |
| `engineer`, nationwide | 1000 | 103 s |
| `product manager`, New York, **with full descriptions** | 100 | 26 s |
| Mixed URLs: one job page, CrowdStrike's board, builtinnyc.com remote | 80 | 12 s |

Deep paging works to page 1000, so one broad board is good for roughly 25,000 rows before it runs out. A narrow search stops when the search does.

#### Field coverage

Measured on **1,455 unique jobs** from the runs above:

| Field | Present |
|---|---|
| `jobId`, `title`, `companyName`, `companyUrl`, `companyLogo`, `jobUrl`, `location`, `postedAt`, `industries` | 1455 / 1455 |
| `workplaceType`, `experienceLevel`, `summary` | 1454 / 1455 |
| `skills` | 1387 / 1455 (95%) |
| `salaryText` | **723 / 1455 (50%)** |

**Read that salary number before you buy.** Built In shows a pay range only when the employer published one, and across a broad sample that is about half of all listings. Coverage swings hard by search: 97% on Chicago data-scientist roles, 81% on New York product managers, 46% on a nationwide `engineer` sweep, 23% on one large company's global board. No scraper can produce the missing ones — the number is not on the page. Rows without a range carry `salaryText: null` rather than a guess.

### What this does not do

- **It does not invent salaries.** See above. There is also no currency on the card — Built In prints `118K-152K Annually` for a Toronto job the same way it does for a Boston one — so this actor does not emit a currency field rather than assume USD. `salaryPeriod` is `year` or `hour`; hourly is rare (8 of 659 in the sample).
- **It does not scrape applicant or recruiter contact details.** Built In does not publish them.
- **It is mostly US and Canada.** That is Built In's own coverage. Company boards do carry the occasional Dublin or Singapore role, but if Europe or Asia is your main target this is the wrong source.
- **It does not log in.** Saved jobs, job alerts and anything behind a Built In account are out of reach.
- **It does not follow the "Apply" link out to the employer's ATS.** `jobUrl` is the Built In page.

### Technique

builtin.com is a server-rendered ASP.NET app. Its job board calls itself back with `?handler=SearchResults`, which returns just the results fragment — every card fully rendered, with a machine-readable analytics payload at the bottom listing each job id and its exact publish timestamp. This actor reads that fragment directly. No headless browser, no per-job request on the default path, and nothing that needs an API key.

Requests carry a real Chrome TLS fingerprint (via `impit`) over a static-ISP address pool. Plain Node `fetch` is a different thing entirely to a CDN and gets treated as such.

### Reliability

Every failure produces a labelled, **uncharged** diagnostic row instead of a silent empty dataset: `BAD_URL`, `LOCATION_NOT_FOUND`, `NO_RESULTS`, `JOB_NOT_FOUND`, `HTTP_ERROR`. You are charged once per real job row and never for a failed or empty one; a run that returns nothing costs only the $0.001 start fee.

### FAQ

**Is there an official Built In API?**
No. Built In publishes no public jobs API. This actor reads the same results fragment the site's own front end reads.

**Does it return the salary?**
Yes, when Built In shows one — as `salaryText` ("195K-320K Annually") plus parsed `salaryMin`, `salaryMax` and `salaryPeriod` (`year` or `hour`). That was 723 of 1,455 jobs (50%) in our measured sample. The rest are `null`, because the employer did not publish a range.

**Can I get the full job description?**
Yes. Set `includeJobDescription: true`, or paste the job's URL into `startUrls`. Both give you `descriptionText` and `descriptionHtml`, and neither costs extra.

**Can I filter to remote jobs only?**
Yes — set `remotePreference` to `remote`. Every row also carries `workplaceType`, `isRemote`, `isHybrid` and `isOnsite`, so you can filter afterwards too. Built In's own values are `Remote`, `Hybrid`, `In-Office`, `Remote or Hybrid` and `In-Office or Remote`.

**Can I scrape one company's jobs?**
Yes. Paste `https://builtin.com/company/<slug>/jobs` into `startUrls`. Built In's own company page stops at 20 jobs and does not paginate; this actor resolves the company id behind it and reads the main board filtered to that employer instead, which pages properly. CrowdStrike returned 200+ that way against the company page's 20.

**Do the city sites work?**
Yes. builtinnyc.com, builtinchicago.org, builtinaustin.com, builtinla.com, builtinboston.com, builtinsf.com, builtincolorado.com, builtinseattle.com — paste any of their `/jobs` URLs. Or just set `location` on builtin.com, which covers the same ground.

**How many jobs can I get in one run?**
`maxItems` goes to 10,000. Built In stops paginating at page 1000, so a single broad board tops out somewhere around 25,000 rows. Split by category, city or keyword to go wider.

**How do I run it daily?**
Schedule it in Apify and set `postedWithinDays` to `1`. You then only pay for jobs posted since yesterday.

**How much does it cost?**
$0.81 per 1,000 jobs, plus a $0.001 start fee per run. A 500-job run costs about $0.41.

# Actor input Schema

## `searchQueries` (type: `array`):

Job titles or keywords to search on Built In, one per line. Example: "data engineer", "product manager". Leave empty if you only want the filters below, or only the URLs.

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

City or region, in plain text: "Austin, TX", "New York", "Chicago". Resolved through Built In's own location lookup. Leave empty to search every Built In location.

## `searchRadius` (type: `string`):

How far around the location to look. Ignored when no location is set.

## `remotePreference` (type: `string`):

Restrict to one working style. "Any" returns all of them and still tells you which each job is.

## `category` (type: `string`):

Built In's own job category.

## `experienceLevel` (type: `string`):

Seniority band as Built In labels it.

## `postedWithinDays` (type: `string`):

Only jobs published in the last N days.

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

Hard cap on rows returned across every search and URL (1-10000). You are charged per job returned.

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

Optional. Paste single job pages (https://builtin.com/job/lead-data-engineer/10586279), board pages (https://builtin.com/jobs/remote/engineering), a company's board (https://builtin.com/company/crowdstrike/jobs) or a city site (https://builtinnyc.com/jobs). Works alongside the fields above.

## `includeJobDescription` (type: `boolean`):

Off by default. When on, the actor opens each job's own page to add the full description text and HTML, employment type, benefits and the closing date. This makes the run slower because it is one extra request per job. The price per job does not change.

## `proxyConfiguration` (type: `object`):

Optional. The actor already uses its own egress; leave this alone unless you need to exit from a specific network.

## Actor input object example

```json
{
  "searchQueries": [
    "data engineer"
  ],
  "searchRadius": "",
  "remotePreference": "",
  "category": "",
  "experienceLevel": "",
  "postedWithinDays": "",
  "maxItems": 50,
  "startUrls": [],
  "includeJobDescription": false,
  "proxyConfiguration": {
    "useApifyProxy": 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 = {
    "searchQueries": [
        "data engineer"
    ],
    "location": "",
    "maxItems": 50,
    "startUrls": [],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/builtin-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 = {
    "searchQueries": ["data engineer"],
    "location": "",
    "maxItems": 50,
    "startUrls": [],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/builtin-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 '{
  "searchQueries": [
    "data engineer"
  ],
  "location": "",
  "maxItems": 50,
  "startUrls": [],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call dami_studio/builtin-jobs-scraper --silent --output-dataset

```

## MCP server setup

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