About a quarter of the Fortune 500 runs hiring through iCIMS, which means a huge share of real, current job postings sit on employer career sites that no public API will hand you. I wanted those postings as JSON, from the source rather than from an aggregator's week-old copy. This post covers why iCIMS is awkward to read, what breaks when you script it yourself, and the shortcut: the iCIMS API on Apify, which turns a career-site address into one JSON row per open role.
Disclosure: the Apify links in this post are affiliate links. If you run the Actor, I may earn a referral commission at no extra cost to you.
Does iCIMS have a public jobs API?
Not one you can sign up for. iCIMS sells API access to its own customers so they can read their own data, which is the right tool if you own the account. There is no public endpoint for reading an employer's live postings from outside. So the workable path is a scraper you call like an API: give it a career site, get that employer's open roles back as structured JSON. It is an unofficial tool, it is not affiliated with iCIMS, and it reads only pages that are already public.
What the iCIMS API returns
The iCIMS API returns every live job on a career site as a JSON row with title, employer, locations, requisition ID, salary, dates, the full description, and the apply link.
| Field | Example | Notes |
|---|---|---|
url |
https://careers-rambus.icims.com/jobs/23006/job |
Canonical, stable across title edits, the key to dedupe on |
id |
2026-23006 |
The employer's own requisition ID, not a number from the URL |
title |
Design Verification Principal Engineer |
As published |
organization |
Rambus |
Hiring employer |
locations_derived |
["Hillsboro, OR, United States"] |
Readable City, Region, Country strings |
date_posted / date_updated
|
2026-08-03T04:00:00+00:00 |
ISO-8601; date_updated is the field to monitor |
salary_raw |
Pay range as published | Never inferred |
apply_url |
Direct application link |
Descriptions come back three ways: description_text, description_html, and description_markdown. The Markdown one is the friendliest if you are piping a job description into a model.
Who this is for
People tracking hiring at named accounts, who want a new requisition the day it appears rather than when a board syndicates it. Teams building or backfilling a job board, who need real posted dates and working apply links. And anyone doing recruitment market research across many employers on the same platform, where per-employer onboarding is the thing that kills the project.
The manual way, and where it breaks
Reading one career site by hand is fine; the trouble starts at scale. There are two kinds of iCIMS site, classic portals on icims.com and modern career sites on the employer's own domain, and they need different handling. iCIMS prints no posted date on the page, so a naive parser returns jobs with no usable date. Job URLs change when an employer edits a title, so dedupe quietly breaks and yesterday's role reappears as new. And some employers gate parts of the site to trusted networks, which looks like an empty result rather than an error. I lost an afternoon to that one before working out the site was fine and my code was being told to go away.
The faster way: run the iCIMS API
In the Apify Console, open the iCIMS API, click Try for free, paste a career-site root into startUrls or a bare company name into companies, then run it and export as JSON, CSV, or Excel. Every common address form works and the right approach is picked automatically: a site root, a sitemap.xml, a /jobs/search page, a single job URL, or a modern career site on the employer's domain.
From the command line it is one call:
curl -X POST "https://api.apify.com/v2/acts/johnvc~icims-careers-api/runs?token=YOUR_APIFY_TOKEN" -H "Content-Type: application/json" -d '{ "startUrls": [{"url": "https://careers-rambus.icims.com"}], "maxJobsPerSite": 50, "descriptionFormat": "both" }'
Run mechanics are in the Apify API docs.
Pull iCIMS jobs in Python
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("johnvc/icims-careers-api").call(run_input={"companies": ["rambus"], "maxJobsPerSite": 25})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
print(job["id"], job["title"], job.get("locations_derived"), job.get("date_posted"))
Swap companies for a list and you are reading several employers in the same run.
Track new postings without re-reading the whole site
Turn includeDetails off and you get list-only mode: job URL, requisition ID, and last-changed timestamp for every live job, in a single request per career site. Pair it with newerThan and you have a cheap daily change feed. The pattern that works is a list-only run every morning, a comparison of date_updated against what you stored yesterday, then a second run with details on only the jobs that moved.
Use it as an ATS API for your own tools
Most ATS API products are unification layers: you pay an integration vendor, connect an employer's account, and read their private data with permission. This is the other half of that problem. It reads what an employer has already published publicly, so there is no account to connect and no setup per employer, which is what makes "who is hiring in this market" a single run instead of a per-employer integration project. The companies field takes bare names, so ["rambus", "sas"] resolves without hunting for URLs, and duplicates across inputs are removed for you. For storage, url is a stable primary key and date_updated is the column to upsert on.
Read iCIMS jobs from Claude via MCP
Through the Model Context Protocol the Actor becomes a callable tool in Claude, Claude Code, and Cursor, so "what has Rambus posted in engineering this week" runs a live pull instead of guessing from training data. The input and output schema descriptions are written for a model to read, so an agent can work out which parameters it needs without much prompting. You can read more about Claude at claude.ai.
johnisanerd
/
Apify-iCIMS-Careers-API
iCIMS API example: pull live job postings from any iCIMS career site with Python or MCP. Covers both public iCIMS surfaces, with change detection so a daily poll only costs the jobs that moved.
iCIMS API: Pull Live Job Postings From Any iCIMS Career Site
iCIMS does not hand out a public read API for job postings, so most teams end up writing a one-off parser per employer. This repo shows you the shortcut: a working Python example plus MCP install steps for the iCIMS Careers API on Apify.
Point it at a career site, get back structured jobs: title, requisition ID, employer, locations, employment type, posted and updated dates, salary when the employer publishes it, and the apply link. It reads both public iCIMS surfaces, the classic careers-{tenant}.icims.com portals and the modern iCIMS career sites that live on the employer's own domain, so you do not have to know which one an employer runs.
Get a free Apify API key here: https://apify.com?fpr=9n7kx3
Text walkthrough
The icims api you are looking for is this Actor. You give it one thing, a career site, either…
FAQ about scraping iCIMS job postings
How much does the iCIMS scraper cost to run?
Billing is per job returned, with a small run-start charge and no subscription. There are three per-job rates: full postings at the standard rate, list-only jobs much cheaper because the whole site is read in one request, and proxied jobs higher because iCIMS serves job pages uncompressed. Error rows are not billed at any of the three, so a career site that cannot be reached does not charge you for jobs it never returned.
Can Claude or another agent drive this scraper over MCP?
Yes. The Actor is MCP-server-compatible, so Claude, Claude Code, Cursor, and other MCP clients call it as a tool and pull live postings inside an agent workflow.
Can I schedule the scraper to catch new jobs daily?
That is the intended use. Save an input as a Task, attach a Schedule, and pair a nightly list-only run with newerThan to get a change feed for a set of employers. Start from the iCIMS API and route the output through webhooks, n8n, Make, or Zapier.
Which career sites can this scraper not reach?
Ones restricted to trusted networks. You get a labelled error row with error_code set to ip_gated rather than a silent gap. Residential proxies clear many of them, but employers who allow only their own corporate network cannot be reached from outside by anything.
Is this scraper affiliated with iCIMS, and is the data really public?
No affiliation, and yes. It reads career-site pages that are already open to any browser, with no login and no API key. You are responsible for your own use, including local law and platform terms.
Can an AI agent pay for this scraper in USDC with x402?
Yes. The iCIMS API supports agentic payments via the x402 protocol, so AI agents and MCP clients can pay for runs in USDC on Base with no Apify account or API token. Point your agent at the Apify MCP server and it can discover, pay for, and run the scraper autonomously; the Apify x402 announcement has the details.
More from Truffle Pig Data
The same job for the other big enterprise ATS: Workday Careers API. From the destination side of the market rather than the employer side: LinkedIn Jobs API. And for scoring the companies you turn up: Glassdoor Reviews API.
Wrapping up
Employer career sites are the original source, ahead of every board that syndicates from them. Point the iCIMS API at one, or clone the example repo and start from working Python.

Top comments (0)