# Career Site Jobs Feed (`jobo.world/career-site-jobs-feed`) Actor

Bulk fetch jobs from 100+ ATS platforms with cursor-based pagination. Up to 1000 jobs per batch. Perfect for data pipelines, job boards & incremental syncs.

- **URL**: https://apify.com/jobo.world/career-site-jobs-feed.md
- **Developed by:** [Jobo](https://apify.com/jobo.world) (community)
- **Categories:** Jobs, Automation, Developer tools
- **Stats:** 48 total users, 6 monthly users, 98.0% runs succeeded, 3 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $1.00 / 1,000 jobs

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/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

**Career Site Jobs Feed** — the bulk firehose for **data pipelines**: stream Jobo's entire index of **3.9 million+ live jobs** across **100+ ATS platforms** with cursor pagination, at up to **1,000 jobs per batch** and **100,000 jobs per run**. This is not a keyword-search tool (that's [ATS Jobs API](https://apify.com/jobo.world/ats-jobs-api)) — it's the fastest way to get the whole normalized, daily-verified inventory into your warehouse. Open the actor, hit **Try for free**, and run the default input (one 500-job batch) — no code or API key required.

[![Service Status](https://img.shields.io/badge/Service%20Status-jobo.world%2Fstatus-brightgreen)](https://jobo.world/status)

### What does Career Site Jobs Feed do?

- Streams **up to 1,000 jobs per batch** with cursor pagination — versus 100 per page on the search actors
- Pulls **up to 100,000 jobs in a single run** (`batch_size` × `max_batches`), looping batches automatically and stopping early when the feed is exhausted
- Covers **all 100+ ATS platforms** in one feed — or scope with `sources`, structured `locations`, and `work_models`
- **Resumable**: every completed run writes its final cursor to the `FEED_METADATA` key-value record, so the next run picks up exactly where this one stopped
- Built for **incremental syncs** — schedule it daily with `posted_after: "1 day ago"` for cheap deltas instead of full re-exports
- Returns the same **normalized, AI-enriched job records** as every Jobo actor: de-duplicated, geocoded locations, USD-normalized salaries, typed skills, work-authorization signals
- Optionally attaches the **full company profile** with `include_company_details` — a cross-batch cache fetches each unique company once per run
- Exports to **JSON, CSV, or Excel**, and plugs into **schedules, webhooks, Zapier, Make, and the Apify API**

### Which ATS platforms are covered?

The provider catalog is maintained by Jobo's scraper registry, so newly supported
platforms appear without an actor schema update. Leave `sources` empty to stream
all indexed jobs, or pass canonical provider IDs such as
`["greenhouse", "lever", "ashby"]` to scope a run.

### Authentication and source visibility

You never need to provide a Jobo API key. When you run the actor in the Apify
Console, Apify handles authentication for you. When you call it through the
Apify API or an Apify client, supply only your own Apify token in the normal
`token` parameter or client configuration.

The actor's source files are not published. Its publisher-managed Jobo
credential is stored as an encrypted Apify Secret and injected only while the
actor runs. The credential value is absent from actor inputs, dataset output,
`FEED_METADATA`, source definitions, public build metadata, and logs. It is not
a customer credential and there is no Jobo key to copy, configure, or rotate.

### How does cursor pagination work?

The feed uses opaque cursors. The first call omits `cursor`; each response returns `next_cursor` and `has_more` — pass `next_cursor` back to fetch the next batch:

```
Request  → {batch_size: 1000}
Response → {jobs: [...1000 rows], next_cursor: "abc123...", has_more: true}

Request  → {batch_size: 1000, cursor: "abc123..."}
Response → {jobs: [...300 rows], next_cursor: null, has_more: false}
```

The actor runs this loop for you — up to `max_batches` times per run, stopping early when `has_more` comes back `false` — and writes the final cursor to the `FEED_METADATA` key in the run's key-value store so a follow-up run can resume.

After a run completes in the Apify Console, open the run and select **Output →
Feed Metadata**. Copy `last_cursor` into the next run's **Pagination Cursor**
input. Also check `has_more`: when it is `false`, the feed is exhausted and
`last_cursor` is `null`.

For API-driven runs, fetch the same run-specific record directly (replace
`<RUN_ID>` with the `id` returned when you started the run):

```http
GET https://api.apify.com/v2/actor-runs/<RUN_ID>/key-value-store/records/FEED_METADATA?token=<YOUR_APIFY_TOKEN>
```

The synchronous `run-sync-get-dataset-items` endpoint returns dataset items —
the jobs — only. It does not include `FEED_METADATA` or the next cursor in its
JSON response. Use a normal actor run plus the endpoint above when you need to
continue into another run.

### How much does it cost?

This actor uses **pay-per-event pricing**: you pay a fixed rate per job record returned — the current rate is in the pricing box on this page. There are no separate compute, proxy, or storage charges, and a run never returns more than `batch_size` × `max_batches` rows, so spend is fully predictable. Apify's **free plan** includes enough credit to pull thousands of jobs, so you can evaluate the full dataset before paying anything.

### How do I run a full export?

1. **Open the actor** and click **Try for free** — you'll need a free [Apify account](https://console.apify.com/).
2. **Smoke-test with the defaults** — one batch of 500 jobs (`batch_size: 500`, `max_batches: 1`) lets you inspect the record shape cheaply.
3. **Scope the feed** (optional): pick `sources`, structured `locations`, `work_models`, or a `posted_after` window. Remember `batch_size` × `max_batches` is your spend ceiling.
4. **Scale up and Start** — `batch_size: 1000`, `max_batches: 100` pulls up to 100,000 jobs in one run; the actor loops batches automatically and stops when the feed reports no more pages.
5. **Export or resume** — download JSON, CSV, or Excel from the Output tab, then open **Output → Feed Metadata** and copy `last_cursor` into the next run's **Pagination Cursor** field.

### ⬇️ Input

| Parameter | Type | Description |
|-----------|------|-------------|
| `batch_size` | integer | Jobs per batch, 1–1,000 (default `500`). |
| `max_batches` | integer | Batches to pull this run, 1–100 (default `1`). |
| `cursor` | string | Opaque cursor from a previous run's `FEED_METADATA`. Omit to start from the beginning. |
| `locations` | array | **Structured** location filters — `{country, region?, city?}` objects; jobs match ANY entry. A bare string is treated as a country. |
| `sources` | array | ATS slugs to include (e.g. `["greenhouse", "lever"]`). Empty = all 100+. |
| `work_models` | array | `remote`, `hybrid`, `onsite`. |
| `posted_after` | string | ISO 8601 (`2026-01-01`) or relative (`1 day ago`) — the key to incremental syncs. |
| `include_company_details` | boolean | Attach the full enriched company profile; a cross-batch cache fetches each unique company once per run (default `false`). |

Note the `locations` format: unlike the search actors, which take free-text location strings and geocode them server-side, the feed takes **structured objects** so filtering stays exact at bulk scale:

```json
"locations": [
  { "country": "United States" },
  { "country": "Germany", "region": "Bavaria" },
  { "country": "United Kingdom", "city": "London" }
]
```

The full input schema with defaults is on this page's **Input schema** tab.

### ⬆️ Output example

Results land in the dataset under two views: *Job Feed (all sources)* (one row per job) and *Company details* (populated when `include_company_details` is on). Every row is the same normalized record shape as [ATS Jobs API](https://apify.com/jobo.world/ats-jobs-api) and the single-ATS actors — the `source` field carries the slug of the ATS each job came from (here `"greenhouse"`; a feed batch mixes all the platforms you include). A typical record:

```json
{
  "id": "f0f6a7d0-c667-48f7-95bc-a91f172e2d6d",
  "title": "Software Engineer",
  "normalized_title": "Software Engineer",
  "summary": "Design and develop software for capital equipment and medical devices used by cardiac surgeons and electrophysiologists…",
  "company": {
    "id": "6647fb14-d420-434a-a332-9c972016b9b0",
    "name": "AtriCure",
    "website": "https://atricure.com",
    "logo_url": "https://images.jobo.world/logos/atricure.jpg",
    "industries": ["Medical Devices & Equipment"],
    "details_url": "https://connect.jobo.world/api/companies/6647fb14-d420-434a-a332-9c972016b9b0"
  },
  "locations": [
    {
      "location": "Minneapolis, MN",
      "city": "Minneapolis",
      "region": "Minnesota",
      "country": "United States",
      "latitude": 44.9772995,
      "longitude": -93.2654692
    }
  ],
  "compensation": { "min": 71036, "max": 104186, "currency": "USD", "period": "yearly" },
  "employment_type": "Full-time",
  "workplace_type": "On-site",
  "experience_level": "Mid Level",
  "qualifications": {
    "must_have": {
      "education": ["Bachelor's degree in Systems Engineering, Electrical Engineering, or Computer Engineering"],
      "skills": [
        { "name": "C", "type": "hard" },
        { "name": "C++", "type": "hard" },
        { "name": "Software Development Methodologies", "type": "hard" }
      ]
    },
    "preferred": {
      "skills": [
        { "name": "Rust", "type": "hard" },
        { "name": "Python", "type": "hard" }
      ]
    }
  },
  "is_work_auth_required": true,
  "listing_url": "https://job-boards.greenhouse.io/atricure/jobs/4309998009",
  "apply_url": "https://job-boards.greenhouse.io/atricure/jobs/4309998009#app",
  "source": "greenhouse",
  "date_posted": "2026-07-09T13:47:14Z",
  "description": "…full job description, HTML stripped…"
}
```

### How do I resume and sync incrementally?

Every successful run writes a `FEED_METADATA` record to its key-value store.
In the Console, open the completed run and choose **Output → Feed Metadata**:

```json
{
  "total_jobs": 100000,
  "batches_processed": 100,
  "last_cursor": "eyJsYXN0X2lkIjoi…",
  "has_more": true
}
```

`last_cursor` is only set while `has_more` is `true`; once the feed is exhausted it's `null` and you're done.

From the Apify API, read the same record without first resolving a key-value
store ID:

```http
GET https://api.apify.com/v2/actor-runs/<RUN_ID>/key-value-store/records/FEED_METADATA?token=<YOUR_APIFY_TOKEN>
```

**Worked example — a multi-run full export.** Run 1 starts from the top:

```json
{ "batch_size": 1000, "max_batches": 100 }
```

Run 1 finishes with `has_more: true` and a `last_cursor` in `FEED_METADATA`. Run 2 carries that cursor over:

```json
{
  "batch_size": 1000,
  "max_batches": 100,
  "cursor": "eyJsYXN0X2lkIjoi…"
}
```

Repeat until `has_more` comes back `false`.

**Daily incremental sync.** Create an Apify **Schedule** that runs this actor every 24 hours with:

```json
{
  "batch_size": 1000,
  "max_batches": 100,
  "posted_after": "1 day ago"
}
```

Each scheduled run then pulls only jobs posted since the previous one — far cheaper than re-paginating the full feed.

### What can you expect from a run?

- **Hard ceiling: 100,000 jobs per run** — 100 `max_batches` × 1,000 `batch_size`. For more, chain runs by passing `last_cursor` as the next run's `cursor`.
- **Pacing**: the actor waits 0.5 seconds between batches to keep the feed healthy.
- **On a 503**, the actor honors the API's `Retry-After` header and retries automatically; if it persists, check [jobo.world/status](https://jobo.world/status).
- **Cursors are opaque** — pass them back exactly as returned; don't construct or edit them. A stale cursor from an old run may be rejected — omit it to restart from the beginning.
- **No keyword, salary, or skills filters** — the feed is a firehose by design. For search and faceted filtering, use [ATS Jobs API](https://apify.com/jobo.world/ats-jobs-api).
- **Freshness**: every listing is re-verified daily; expired jobs are removed within 24 hours of disappearing from the source board.

### Integrations, API & MCP

Everything on the Apify platform works out of the box: **schedules** (hourly/daily/weekly runs), **webhooks** on run completion, and one-click integrations with **Zapier, Make, n8n, Slack, Google Sheets, and Google Drive**.

Prefer code? Call this actor as a **bulk jobs feed API** from Python or JavaScript with the [Apify API clients](https://docs.apify.com/api) — start a run, wait for it, and page through the dataset in a few lines (ready-made snippets are in the **API** section of this page). AI agents can run it through the **[Apify MCP server](https://mcp.apify.com)**, which exposes this actor as a tool.

### Use cases

| Who | What for |
|-----|----------|
| **Data platforms** | Sync millions of normalized jobs into a warehouse or lakehouse for analytics |
| **Job boards** | Backfill and refresh a full job index with cross-ATS coverage |
| **Search infrastructure** | Build a custom job search engine on top of the raw feed |
| **HR tech** | Market-intel pipelines fed by bulk daily syncs |
| **AI training** | Job-data corpora for embeddings, fine-tunes, and classifiers |
| **Competitive intel** | Track hiring velocity across companies and sectors at full-market scale |

### ❓ FAQ

#### Should I use this actor or ATS Jobs API?

Use **[ATS Jobs API](https://apify.com/jobo.world/ats-jobs-api)** for filtered, paginated queries — keyword search, salary and skills filters, up to 100 pages × 100 results. Use **this actor** for bulk download and sync: cursor pagination, 1,000 jobs per batch, built for ETL pipelines and warehouses.

#### How fast is it? What's the maximum throughput?

One run pulls up to **100,000 jobs** (`batch_size: 1000` × `max_batches: 100`), with a 0.5-second pause between batches. For the full index, chain runs — each run's `FEED_METADATA` hands the next one its starting `cursor`.

#### How do I resume a long export?

Open the previous run's **Output → Feed Metadata**, copy `last_cursor`, and pass it as `cursor` in the next run. API callers can GET `/v2/actor-runs/<RUN_ID>/key-value-store/records/FEED_METADATA`. When `has_more` is `false`, you've reached the end. The synchronous dataset-items response contains jobs only, not the cursor.

#### Can batches overlap or skip jobs?

Within a run, consecutive batches never overlap — the cursor encodes the exact feed position. Across resumed runs the cursor picks up where you left off, but the index is live: jobs added or expired in between follow the daily refresh.

#### Are duplicate listings removed?

Yes. Jobo de-duplicates by company + canonical title + listing URL before results are returned, so cross-posted duplicates of the same role are merged.

#### How fresh is the data?

New jobs are indexed within 24 hours of appearing on any of the 100+ platforms; every listing is re-verified daily and removed within 24 hours of expiring.

#### Where can I check if the API behind this actor is up?

At [jobo.world/status](https://jobo.world/status) — the live status page for the Jobo Connect API that powers every Jobo actor.

### ⚖️ Is it legal to scrape ATS job listings?

Yes — this actor only extracts publicly posted job listings, the content employers publish specifically to be found and shared. It does not collect private user data. Note that scraped results can incidentally contain personal data (e.g., a recruiter's name in a job description); personal data is protected by the GDPR and similar regulations, so only process it with a legitimate reason and consult a lawyer if unsure. Read more in Apify's guide to [the legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

All ATS names are trademarks of their respective owners. This actor is an independent product and is not affiliated with, endorsed by, or sponsored by any of them.

### 🔗 Related actors

| Actor | Best for |
|-------|----------|
| [ATS Jobs API](https://apify.com/jobo.world/ats-jobs-api) | Search 100+ ATS platforms in one call |
| [AI Deep Job Search](https://apify.com/jobo.world/ai-deep-job-search) | Describe your ideal job in plain English, get AI-scored matches |
| [Greenhouse Jobs Scraper](https://apify.com/jobo.world/greenhouse-jobs-scraper-api) | 175,000+ jobs from tech companies on Greenhouse |
| [Workday Jobs Scraper](https://apify.com/jobo.world/workday-jobs-scraper-api) | 850,000+ jobs from Fortune 500 employers on Workday |
| [Lever Jobs Scraper](https://apify.com/jobo.world/lever-jobs-scraper-api) | 75,000+ jobs from VC-backed startups on Lever |
| [Crunchbase Company Lookup](https://apify.com/jobo.world/crunchbase-company-lookup) | Funding, leadership, and tech-stack data for any company |

### About Jobo & support

Jobo builds job-data infrastructure: a normalized, daily-verified index of jobs scraped directly from company ATS boards, powering job boards, AI agents, and HR-tech products.

- **Questions or bugs?** Open a ticket on this actor's **Issues** tab — issues are answered within hours.
- **Website**: [jobo.world](https://jobo.world) · **Enterprise API**: [jobo.world/enterprise](https://jobo.world/enterprise) · **API status**: [jobo.world/status](https://jobo.world/status)
- **Email**: enrico@jobo.world

# Actor input Schema

## `batch_size` (type: `integer`):

Number of jobs to fetch per batch (1-1000). Recommended: 500-1000 for optimal performance.

## `max_batches` (type: `integer`):

Maximum number of batches to fetch. Set higher for bulk downloads.

## `cursor` (type: `string`):

The last\_cursor value from the previous run's Output → Feed Metadata record. Omit for the first request.

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

Filter by country, region, and/or city. Each location is an object with optional 'country', 'region', and 'city' fields. Jobs match ANY provided location.

## `sources` (type: `array`):

Filter by canonical ATS provider IDs. Leave empty for all indexed sources; use the Jobo provider catalog for the current production-ready IDs.

## `work_models` (type: `array`):

Filter by work model. Leave empty for all jobs.

## `posted_after` (type: `string`):

Only return jobs posted after this timestamp (ISO 8601 or relative, e.g. '7 days ago'). Use for incremental syncs.

## `include_company_details` (type: `boolean`):

When enabled, replaces the lightweight company preview on each job with the fully enriched company profile (funding, leadership, ratings, tech stack, H1B stats, etc.) fetched from GET /api/companies/{id}. Companies are deduplicated across the whole feed run, so each unique company is fetched only once. Slower and uses more API calls — leave off for bulk syncs that don't need enriched company data.

## Actor input object example

```json
{
  "batch_size": 500,
  "max_batches": 1,
  "locations": [
    {
      "country": "United States"
    }
  ],
  "include_company_details": false
}
```

# Actor output Schema

## `jobs` (type: `string`):

All jobs fetched in this run

## `feed_metadata` (type: `string`):

Open Output → Feed Metadata to get last\_cursor and has\_more for the next run

## `json_export` (type: `string`):

Complete dataset in JSON format

## `csv_export` (type: `string`):

Job results in CSV format for spreadsheet analysis

# 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 = {
    "locations": [
        {
            "country": "United States"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("jobo.world/career-site-jobs-feed").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 = { "locations": [{ "country": "United States" }] }

# Run the Actor and wait for it to finish
run = client.actor("jobo.world/career-site-jobs-feed").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "locations": [
    {
      "country": "United States"
    }
  ]
}' |
apify call jobo.world/career-site-jobs-feed --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=jobo.world/career-site-jobs-feed",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/PQZzPOkjgUACvxqEM/builds/SO7fLl3hVaz5VGtr5/openapi.json
