iCIMS Careers Portal Scraper for icims.com avatar

iCIMS Careers Portal Scraper for icims.com

Pricing

from $0.75 / 1,000 results

Go to Apify Store
iCIMS Careers Portal Scraper for icims.com

iCIMS Careers Portal Scraper for icims.com

Collects job postings from any iCIMS careers portal on icims.com: title, company or brand, department, employmentType, postedAt, apply URL, and the location split out of the portal's country-state-city code. Follows the portal's own paginator, so a 1,000-posting site comes back in full.

Pricing

from $0.75 / 1,000 results

Rating

0.0

(0)

Developer

String

String

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

15 days ago

Last modified

Share

What does iCIMS Job Board Scraper do?

It walks a company's iCIMS careers portal and writes one row per posting on the job search, following the portal's own paginator until the postings run out. Each row carries the posting id, title, the company or brand the role sits under, the category, the position type, the posted date, the apply URL, and the location split out of the code iCIMS writes it in.

An iCIMS portal is addressed by subdomain, not by a path. Every tenant gets its own host, so https://careers-emcorgroup.icims.com and https://careers-eastwestbank.icims.com are two different portals. Pass the URL or just the subdomain.

Two things about iCIMS shape how this works:

  • Every tenant renders job cards from the same platform build, so the card markup is a stable contract across all of them. What differs is which fields a tenant switches on and what it calls them.
  • iCIMS serves the branded wrapper with zero cards unless the request presents iframe fetch metadata. That is not a URL parameter. Without those headers a portal listing 1,450 postings answers with a 98 KB shell and nothing in it.

No iCIMS account, cookie or API key is used. This is the job search a logged-out visitor sees.

What data does it extract?

FieldTypeDescription
jobIdstringiCIMS's posting id, taken from the job URL. Stable, so use it to de-duplicate
titlestringThe posting title. Falls back to the anchor's title attribute when a tenant drops the heading
companystringFrom whichever company field the tenant publishes: Company, Subsidiary, Brand, Business Unit, Facility and similar. null when the portal publishes none
tenantstringThe portal subdomain, for example careers-emcorgroup
locationstringVerbatim, in the iCIMS code country-state-city. A posting open in several places lists them all, pipe-separated
citystringFrom that code, describing the first location listed
statestringFrom that code
countrystringFrom that code
isRemotebooleanFrom the tenant's workplace field where it has one, otherwise from the location text. null when neither is present
departmentstringFrom the tenant's category field: Category, Function, Department, Job Family, Area of Interest and similar
employmentTypestringFrom the tenant's type field: Position Type, Employment Type, Full/Part Time and similar
postedAtstringYYYY-MM-DD, or YYYY-MM-DDTHH:MM:SS when the portal publishes a time. Local wall clock, see the FAQ
jobUrlstringDirect link to the posting
boardUrlstringhttps://<tenant>.icims.com
sourceUrlstringThe search page the row was read from
collectedAtstringISO 8601 timestamp of the run

How the fields are matched

Every value on an iCIMS card is labelled in the markup, either by a field-label span in the card header or by a term in the header tag list. This Actor reads those labels and maps them onto contract fields, rather than trusting positions. Tenants also prefix labels with the form section they came from (Requisition Post Information* : Posted Date), so the label is reduced to its last colon segment before matching.

The practical result: a portal that calls its category column Function and another that calls it Area of Interest both land in department, and a field a tenant does not publish comes back null instead of holding some other column's value.

Why scrape iCIMS careers portals?

iCIMS is where high-volume employers run their hiring: construction and trades, healthcare systems, retail chains, regional banks, manufacturers. These are not the companies you find well covered on technology-focused boards, and the postings are frequently hourly or site-based roles that aggregators index unevenly.

  • Track requisition volume at a facility or region level using location, which iCIMS codes precisely.
  • Watch a competitor's plant, store or clinic openings by the postings that appear before them.
  • Feed a staffing agency's pipeline with fresh requisitions from a defined employer list.
  • Segment by employmentType to separate full-time headcount from seasonal or per-diem demand.
  • Supply labour-market research that needs employers outside the technology sector.
  • Build local candidate-facing job boards for a metro area from the employers who actually hire there.

How to use it

  1. Open the company's "careers" or "search jobs" link. If the address bar shows something like careers-<company>.icims.com, that host is the portal.
  2. Put the URL, or just the subdomain, into Job boards. Up to 100 portals per run.
  3. Set Maximum results. This matters more here than on a single-request board, because a large portal can hold thousands of postings and pagination is where the requests go.
  4. Leave Concurrency at 3 unless you are collecting many portals and want to finish sooner.
  5. Start the run, then export as JSON, CSV, Excel or XML, or pull the dataset over the API.

maxItems is a budget shared across every portal in the input, and each portal stops paginating as soon as the run can no longer keep the rows. A hundred portals under a thousand-row cap fetch a thousand rows, not a hundred portals in full.

Input

FieldTypeDefaultDescription
boardsarray of stringsrequirediCIMS portal URLs or tenant subdomains. Between 1 and 100 entries
maxItemsinteger1000Cap on dataset rows, up to 50,000. Shared across all portals
concurrencyinteger3Portals fetched in parallel, up to 5
{
"boards": [
"https://careers-emcorgroup.icims.com",
"careers-eastwestbank"
],
"maxItems": 2000,
"concurrency": 3
}

A host outside icims.com is rejected and reported as you wrote it, rather than fetched.

Output

One row per job card. Illustrative shape:

{
"jobId": "28417",
"title": "Journeyman Electrician",
"company": "EMCOR Group",
"tenant": "careers-emcorgroup",
"location": "US-PA-Wilkes-Barre",
"city": "Wilkes-Barre",
"state": "PA",
"country": "US",
"isRemote": false,
"department": "Skilled Trades",
"employmentType": "Regular Full-Time",
"postedAt": "2026-07-14T09:32:00",
"jobUrl": "https://careers-emcorgroup.icims.com/jobs/28417/journeyman-electrician/job",
"boardUrl": "https://careers-emcorgroup.icims.com",
"sourceUrl": "https://careers-emcorgroup.icims.com/jobs/search?ss=1&searchRelation=keyword_all&in_iframe=1&pr=0",
"collectedAt": "2026-08-20T09:14:02.118Z"
}

A posting open in several places keeps all of them in location, pipe-separated, and the three geo fields describe the first one. A tenant that writes locations outside the coded form leaves those three null with the raw string still in location.

Each run also writes a SUMMARY record with the item count, the failure count, and every page that failed with its error.

How much does it cost?

Pay per event, charged once per result row written to the dataset. The current rate is on this Actor's pricing tab, and a portal that cannot be read writes no rows and costs nothing.

Unlike a single-request board feed, an iCIMS portal is paginated, so requests scale with rows. That is what maxItems is really controlling: set it to what you intend to use.

Runs started from an Apify free plan stop at 250 requests and 250 results and say so in the run status. Any paid plan runs the full input and your maxItems. The limit binds on requests as well as rows because these fetches run on our own infrastructure, which Apify does not reimburse for free-plan runs.

Using it with the Apify API

import { ApifyClient } from "apify-client";
const client = new ApifyClient({ token: "<YOUR_APIFY_TOKEN>" });
const run = await client.actor("usestring/icims-jobs").call({
boards: ["https://careers-emcorgroup.icims.com"],
maxItems: 2000,
concurrency: 3
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const byState = items.reduce((counts, job) => {
const key = job.state ?? "unknown";
counts[key] = (counts[key] ?? 0) + 1;
return counts;
}, {});
console.log(byState);

The run's SUMMARY record, in the same run's key-value store, lists anything that failed.

A careers portal exists to be found. Employers publish these pages for candidates and search engines, and this Actor reads what an anonymous visitor's browser is served. No login, no session cookie, no API key, nothing gated.

The rows describe requisitions rather than people. There are no applicant records, no application counts and no recruiter contact details in the output.

What you are permitted to do with the collected data still depends on your jurisdiction and on any terms you have accepted. Treat this section as context, not legal advice.

FAQ

How do I find a company's iCIMS portal? Click "careers" or "search jobs" on the company's site and look at the host in the address bar. iCIMS portals are always <tenant>.icims.com, where the tenant is a name the company chose, often prefixed with careers-. Both the full URL and the bare subdomain work as input.

How many postings does one request return? It varies. iCIMS lets each tenant set its own page size, so this Actor follows the portal's rel="next" link until the rows run out or the budget does, to a ceiling of 200 pages per portal. That ceiling exists so a paginator that never terminates cannot consume a whole run.

Why are company, department and employmentType sometimes empty? Because the tenant did not put them on the job card. iCIMS lets each employer choose which fields appear and what to call them, so those three are filled only when a matching labelled field is present.

Is postedAt in UTC? No, and it is deliberately not stamped as though it were. iCIMS renders the posting time in the portal's own timezone and never states which one, so the value is kept as a local wall-clock stamp rather than given an invented offset. Dates in M/D/YYYY form are read as en-US, which is what these portals write.

Does it open each posting's detail page? No. The full JobPosting structured data lives on the detail page, one fetch per posting, and this Actor stays on the search results. Follow jobUrl for the description, requirements and any structured data the tenant publishes there.

What if a portal's paginator points somewhere else? A rel="next" link that leaves the portal's own host is not followed. The paginator is markup the tenant controls, and following it off-host would mean proxying a stranger's site under this Actor's pricing.

Can I search or filter within a portal? Not from the input. The run collects the portal's unfiltered job search and you filter the dataset afterwards, which is usually cheaper than one run per filter.

Feedback

If a portal comes back empty, or a field lands in the wrong column, open an issue from this Actor's Store page and include the portal host. Label mapping is the part most likely to need a new alias, and a named portal is all it takes to add one.