SimplyHired $1๐ฐ URL | Keyword Filters | Enriched
Pricing
from $1.00 / 1,000 results
SimplyHired $1๐ฐ URL | Keyword Filters | Enriched
From $1/1K. Pull active SimplyHired jobs across the US, UK, Canada, Australia, Ireland, and India. Search via builder or URL. Extract 40+ fields, including title, company, salary range, full HTML description, qualifications, geocoordinates, and apply URL.
Pricing
from $1.00 / 1,000 results
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
0
Bookmarked
5
Total users
0
Monthly active users
2 days ago
Last modified
Categories
Share
SimplyHired Jobs Scraper: Titles, Salaries, Full Descriptions & Apply Links
SimplyHired Jobs Scraper turns SimplyHired into a clean job-postings API. Get job title, company, employer rating, parsed salary range (min, max, currency, period), city, state, latitude/longitude, work setting, qualifications, benefits, the full HTML job description and the SimplyHired apply link for active listings across the US, UK, Canada, Australia, Ireland and India sites. Build a search from keywords, location, job type and country, or paste any simplyhired.com /search or /job URL, then export to JSON, CSV or Excel, or pull the results straight into your app through the API.
Why This Scraper?
- 40+ fields per job ad, including a parsed salary range (min, max, currency, period), city, state, latitude/longitude, work setting, qualifications, benefits and the full HTML description, not just the 10 to 15 fields typical scrapers return.
- Two ways to search: build with keywords, location, job type and country site, or paste any simplyhired.com /search URL and the scraper walks pagination forward from there, or a /job URL for that single listing.
- Six regional SimplyHired sites in one input field: United States, United Kingdom, Canada, Australia, Ireland and India.
- Concurrent detail-page enrichment with per-record delivery, so a mid-page failure still keeps the listings already fetched instead of losing the whole page.
- Client-side de-duplication across pages and searches by the canonical listing id, with the listing budget split evenly across multiple keywords in one run.
- Automatic retry across proxy connection tiers when one is refused, with a clear log warning (not a silently wrong result) when the actual cause is your own proxy setup.
- Built for schedules: Incremental mode returns only new and changed listings on recurring runs, and Resume continues one interrupted run without re-collecting what it already saved.
Use Cases
- Job boards and aggregators: pull fresh SimplyHired listings by keyword and location to mirror or enrich your own job feed.
- Recruiter and sourcing tools: track new postings for target companies or roles as soon as they appear, and pull only what changed on a schedule.
- Compensation research: build salary-range datasets by title, location and job type from the parsed
salaryMin/salaryMaxfields. - Labor market analytics: measure posting volume, remote-vs-onsite mix and qualifications trends across regions and countries.
- Application tooling: collect the SimplyHired apply link and full job description text to feed an autofill, alerting or matching tool.
Data You Get
Sample shape: values are illustrative placeholders, not from a live ad.
| Field | Example |
|---|---|
id | "abcd1234example" |
url | "https://www.simplyhired.com/job/abcd1234example" |
title / displayTitle | "Software Engineer" / "Software Engineer, Backend" |
company | "Sample Company Inc" |
companyRating | 4.2 |
companyPageUrl | "https://www.simplyhired.com/company/000-sample-company-inc" |
location / formattedLocation | "New York, NY" |
city / state | "New York" / "NY" |
latitude / longitude | 40.7128 / -74.006 |
country | "us" |
jobTypes / workSettings | ["Full-time"] / ["Hybrid"] |
salary | "$140,000 - $180,000 a year" |
salaryMin / salaryMax | 140000 / 180000 |
salaryCurrency / salaryPeriod | "USD" / "year" |
descriptionHtml / descriptionText | full HTML job description / the same description as plain text |
qualifications | ["Bachelor's degree", "5+ years experience"] |
benefits | ["Health insurance", "401(k)"] |
skillsAll | ["Python", "AWS", "API design"] |
datePosted | "2026-09-20T08:00:00.000Z" |
applyUrl | the SimplyHired apply link, a redirect that forwards to the employer's application page (the token rotates on every fetch) |
sponsored | false |
source | "SimplyHired" |
changeType (incremental mode only) | "NEW" (also "UPDATED", "UNCHANGED", "REAPPEARED", "EXPIRED") |
Each record also carries normalizedTitle (a lowercased title for matching), employerLogoUrl and employerHomepage, remoteAttributes (SimplyHired's own remote-work tags), the raw compensation object behind the parsed salary fields, a short snippet preview, a requirements list distinct from qualifications, datePostedEpochMs and dateOnIndeed (millisecond timestamps), mobileApplyUrl alongside applyUrl, indeedApply / auction / expired flags, jobCardTrackingKey (SimplyHired's own per-render analytics key), the jobTypeRequested / searchQuery / searchLocation / pageNumber that produced the row, and scrapedAt. In incremental mode, changedFields, firstSeenAt and lastSeenAt are added alongside changeType.
How to Use
- Pick a mode:
search(build with keywords, location, job type and country) orurl(paste one or more simplyhired.com links). - For search mode, fill in keywords, location, country site and job type. For URL mode, paste any
/searchor/jobURL; the search-builder fields above are ignored. - Set Max listings (and optionally Max pages) to control run size and cost, then click Start.
- Download the dataset as JSON, CSV or Excel, or read it through the API.
Search by keyword and location:
{"mode": "search","queries": ["software engineer"],"location": "Remote","country": "us","jobType": "fulltime","maxPages": 5,"maxListings": 100,"fetchDetails": true}
Multiple keywords, sponsored cards skipped, SERP-only fields for a fast and cheap feed:
{"mode": "search","queries": ["nurse", "physical therapist", "medical assistant"],"location": "Boston, MA","country": "us","jobType": "any","skipSponsored": true,"maxListings": 150,"fetchDetails": false}
URL mode on the UK site, mixing a search link and a single job link:
{"mode": "url","urls": ["https://www.simplyhired.co.uk/search?q=product+manager&l=London","https://www.simplyhired.com/job/abcd1234example"],"maxPages": 5,"maxListings": 200,"fetchDetails": true}
Recurring monitoring (scheduled daily run, only what changed):
{"mode": "search","queries": ["software engineer"],"location": "Remote","country": "us","maxListings": 0,"fetchDetails": true,"incrementalMode": true,"emitExpired": true}
Schedule this same input to run daily. The first run returns everything as NEW. Later runs return only NEW, UPDATED and EXPIRED listings (plus REAPPEARED once a listing that was previously marked EXPIRED shows up again), not the full result set every time.
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/simplyhired-com-scraper").call(run_input={"mode": "search","queries": ["software engineer"],"location": "Remote","country": "us",})for job in client.dataset(run["defaultDatasetId"]).iterate_items():print(job["title"], job["company"], job["salary"])
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/simplyhired-com-scraper').call({mode: 'search',queries: ['software engineer'],location: 'Remote',country: 'us',});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.
Max pages, Max listings and the per-keyword budget
Max pages caps how many SERP pages are walked per search entry (or per pasted URL); each page returns up to 20 listings. Leave it empty to walk every page until the site's own end-of-results signal. Max listings caps the total across every search in the run; set it to 0 for no cap. When a run has multiple keywords, the Max listings budget is split evenly across them so one keyword can't crowd out the others.
Resume and recurring updates
Two different things, both under one input section, so they don't get confused:
-
Resume from a previous run (
resumeFromRunId) continues one specific interrupted run. Paste the ID of a previous run (or its dataset), and this run skips every listingidalready saved there, appending only new ones. Good for an unbounded pull (maxPagesleft empty,maxListings: 0) that got cut off. -
Incremental mode (
incrementalMode) is for recurring monitoring of the SAME search (for example, scheduled daily). Turn it on and the actor remembers the previous run's results itself, no run or dataset id to paste. Each listing in the output then gets achangeType:NEW: never tracked before for this search.UPDATED: tracked before, but at least one non-volatile field changed since last time (seechangedFields). Per-request tracking tokens such asapplyUrlare ignored so they never trigger a falseUPDATED.UNCHANGED: identical to last time. Only emitted (and billed) whenemitUnchangedis on; off by default.EXPIRED: was tracked as present in a previous run, and was not found in this one. Only produced whenemitExpiredis on and this run reached the natural end of results for every tracked search, with nomaxListingscap hit and noresumeFromRunId. A capped, blocked or resumed run cannot tell "gone" apart from "not reached yet", so it leaves the previous state untouched instead of guessing.REAPPEARED: a listing markedEXPIREDin an earlier run that has now been found again. This can only happen for a listing that some earlier run actually marked absent, which itself only happens when that earlier run hademitExpiredon and completed a full, uncapped, non-resumed scan of the tracked search. IfemitExpiredhas never been on, or every run so far was capped, blocked, or usedresumeFromRunId, no listing is ever marked absent, soREAPPEAREDcannot occur, no matter how many times a listing actually disappears and comes back.
State is tracked separately per query/location/country/jobType/skipSponsored/URL-set/
fetchDetailscombination, or under one shared campaign if you setstateKey, so two differently-configured runs never mix baselines.
Independently of both, a checkpoint is saved automatically as the run progresses. If the run is interrupted by an Apify platform migration or you click Resurrect on a failed run, it picks back up in the same run without re-saving, or re-charging for, listings it already collected. No input is needed for this; it's automatic.
Send results into your apps (MCP connectors)
Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape; the Apify dataset is never changed.
What gets written to the connector: a condensed, human-readable summary of each record, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.
- Authorize a connector once under Apify โ Settings โ Integrations (Notion, Linear, Airtable, or Apify).
- Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
- For Notion, also set
notionParentPageUrlto the page where items should be created.
The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | search | search (use the builder fields below) or url (paste SimplyHired URLs). |
queries | array | no default (prefill: ["software engineer"]) | One scrape per keyword. Leave empty to browse without a keyword filter. |
location | string | no default (prefill: Remote) | City, state, ZIP, or "Remote". Leave empty to search nationwide. |
country | string | us | Which SimplyHired regional site to query: us, uk, ca, au, ie, in. |
jobType | string | any | any / fulltime / parttime / contract / temporary / internship / commission. |
skipSponsored | boolean | false | Drop sponsored / promoted job cards. Applied client-side, in both modes. |
urls | array | no default (prefill: a sample search URL) | URL mode only. A /search URL is paged forward independently; a /job URL returns that one listing. Search-builder fields above are ignored. |
maxPages | integer | no default (empty = unlimited) | Max SERP pages per search (or per pasted URL). Each page returns up to 20 listings. Leave empty to walk every result page until the site's own end-of-results signal. |
maxListings | integer | 20 | Stop after this many listings across all searches. 0 = no cap. |
fetchDetails | boolean | true | Also fetch each job's detail page for the full HTML description, qualifications list, employer logo, lat/lng and apply URL. |
resumeFromRunId | string | no default (empty) | A previous run ID or dataset ID to continue one specific interrupted run. Listings already collected there (matched by id) are skipped. |
incrementalMode | boolean | false | Turn on for daily or recurring monitoring of the same search. See "Resume and recurring updates" above. |
stateKey | string | no default (empty) | Incremental mode only. Names the monitoring campaign so its state stays stable, or lets you deliberately share state across differently-configured runs. Leave empty to derive a key automatically from the query/location/URL and detail settings. |
emitUnchanged | boolean | false | Incremental mode only. Also return (and bill) listings that haven't changed, marked UNCHANGED. |
emitExpired | boolean | false | Incremental mode only. Also return (and bill) listings from a previous run that are no longer found, marked EXPIRED. Only produced after a run that fully scanned the tracked search. |
proxy | object | no default (prefill: Apify Residential, country US) | SimplyHired requires residential routing pinned to the country site you query; datacenter exit IPs are rejected. For other regional sites, change the country to match (GB / CA / AU / IE / IN). |
mcpConnectors | array | no default (empty) | Optional: send a summary of each listing to apps you authorized under Integrations. |
notionParentPageUrl | string | no default (empty) | Notion connector only: page under which listing pages are created. |
maxNotifyListings | integer | 50 | Cap on items written to each connector per run. Does not affect the dataset. |
Output Example
Sample shape: values are illustrative placeholders, not from a live ad.
changeType,changedFields,firstSeenAtandlastSeenAtare only added whenincrementalModeis on; a normal run's output shape below is unchanged.
{"id": "abcd1234example","url": "https://www.simplyhired.com/job/abcd1234example","title": "Software Engineer","displayTitle": "Software Engineer, Backend","normalizedTitle": "software engineer","company": "Sample Company Inc","companyRating": 4.2,"companyPageUrl": "https://www.simplyhired.com/company/000-sample-company-inc","employerLogoUrl": "https://logos.example-cdn.com/sample-company-inc.png","employerHomepage": "https://www.samplecompany.example","location": "New York, NY","formattedLocation": "New York, NY","city": "New York","state": "NY","latitude": 40.7128,"longitude": -74.006,"country": "us","jobTypes": ["Full-time"],"workSettings": ["Hybrid"],"remoteAttributes": [],"salary": "$140,000 - $180,000 a year","salaryMin": 140000,"salaryMax": 180000,"salaryCurrency": "USD","salaryPeriod": "year","compensation": { "currency": "USD", "period": "year" },"snippet": "Short listing preview text appears here...","descriptionHtml": "<p>Full long-form HTML description appears here.</p>","descriptionText": "Full long-form description as plain text appears here.","requirements": ["Python", "AWS"],"qualifications": ["Bachelor's degree", "5+ years experience"],"benefits": ["Health insurance", "401(k)"],"skillsAll": ["Python", "AWS", "API design"],"datePosted": "2026-09-20T08:00:00.000Z","datePostedEpochMs": 1789891200000,"dateOnIndeed": 1789891200000,"applyUrl": "https://www.simplyhired.com/out?r=sampletoken000","mobileApplyUrl": "https://www.simplyhired.com/m/out?r=sampletoken000","indeedApply": false,"sponsored": false,"auction": false,"expired": false,"jobCardTrackingKey": "0-pdx0-0-0000000000000000-0000000000000000","jobTypeRequested": "fulltime","searchQuery": "software engineer","searchLocation": "New York, NY","pageNumber": 1,"source": "SimplyHired","scrapedAt": "2026-09-29T12:00:00.000Z"}
Plan Requirement
This scraper requires residential proxy routing pinned to the country site you query; SimplyHired rejects most datacenter exit IPs. The prefilled proxy setting in the Console uses the residential group, and the actor automatically retries with a different connection tier when one is refused. If your plan doesn't include residential proxy access, paste your own residential proxy URLs into the Proxy field under Proxy.
FAQ
How much does it cost?
You pay per listing returned, with an optional surcharge when detail pages are fetched (the default). The Pricing tab shows the current rates. Use Max listings to cap the cost of any run.
Is it legal to scrape SimplyHired?
This actor collects only publicly available job listing data. You are responsible for how you use it: follow SimplyHired's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution.
Can I get only new or changed listings on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new and updated listings, and unchanged ones are not billed unless you turn on Emit unchanged. Turn on Emit expired to also get EXPIRED listings after a run completes a full, uncapped scan; REAPPEARED appears only after such a run has marked a listing expired.
Why do my keyword and location filters have no effect?
Search-builder fields (queries, location, jobType) only apply when mode is search. In url mode, the scraper follows whatever filters are already baked into the pasted URL and ignores the builder fields entirely, since two different filter sources for the same run would conflict.
Why did my run return zero listings instead of failing?
If SimplyHired refuses every request on every proxy tier this actor tries, the run does not guess: it finishes with a warning in the log and an empty dataset, so you are not billed for a page that was never actually read. Check the log for the specific reason and try again in a few minutes, or supply your own residential proxy URLs. The run fails outright when it can detect a configuration problem immediately, such as an unreadable resumeFromRunId, turning on Incremental mode together with resumeFromRunId while a monitoring baseline already exists for that search, or the proxy configuration itself failing to set up.
Can I use it with AI agents or MCP?
Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.
๐ Want more jobs data?
Pair this actor with these related scrapers from the same team:
| ๐ผ ZipRecruiter Scraper From $1/1K. Scrape ZipRecruiter jobs with titles, companies, salaries, locations... | ๐ผ Jobs.cz Scrape Czech job listings from Jobs.cz. Search builder (keyword, location, field, salary... |
| ๐ผ Jora Jobs Scraper Scrape Jora.com job listings across supported countries by keyword, filters, or URL... | ๐ผ SEEK Jobs Scraper From $0.7/1K. Scrape SEEK.com.au and SEEK.co.nz jobs by keyword, location, or filters... |
| ๐ผ JobStreet Scraper From $1/1K. Scrape JobStreet listings across Malaysia, Singapore, Indonesia, and the... | ๐ผ NIJobs Scraper Scrape NIJobs.com listings across Northern Ireland by keyword, location, salary, posted... |
๐ Browse all abotapi scrapers
๐ฌ Support
- ๐ Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
- ๐ ๏ธ Need another site, extra fields or a private build? Email contact@abotapi.com.
- โญ Enjoying it? A quick review on the actor page helps other users find it.