Handshake Jobs Scraper — Public Job Listings avatar

Handshake Jobs Scraper — Public Job Listings

Pricing

from $3.00 / 1,000 validated handshake job returneds

Go to Apify Store
Handshake Jobs Scraper — Public Job Listings

Handshake Jobs Scraper — Public Job Listings

Extract anonymous public Handshake job listings from public search or direct job URLs. Returns normalized titles, employers, locations, compensation, dates, descriptions, and canonical application URLs for early-career hiring research.

Pricing

from $3.00 / 1,000 validated handshake job returneds

Rating

0.0

(0)

Developer

Khadin Akbar

Khadin Akbar

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

15 days ago

Last modified

Share

What is Handshake Jobs Scraper — Public Job Listings?

Handshake Jobs Scraper extracts anonymous public Handshake job listings into a dataset, one normalized row per unique job, from public Handshake search pages or direct public job URLs. Each row returns the job ID, title, employer name, website and logo, location, remote flag, employment type, industry, published salary range, posting and expiry dates, the full description in HTML and plain text, and the canonical job and apply URLs. Early-career recruiters, university career teams, labor-market researchers and AI agents use it to track internships and graduate roles with no Handshake account.

Why recruiters use this Handshake scraper

  • Two ways in. Discover jobs from public joinhandshake.com/find-jobs/... pages, or enrich known app.joinhandshake.com/public/jobs/{id} URLs.
  • Full job detail. Every row follows the job page for descriptionHtml, descriptionText, industry, employmentType and dates.
  • Published pay, cleanly split. salaryMin, salaryMax, salaryCurrency and salaryUnit come straight from the listing.
  • Local filters. titleIncludes, companyIncludes, remoteOnly and minSalary narrow the jobs found on your URLs.
  • Expiry awareness. validThrough shows when each listing closes.
  • Provenance on every row. sourceSearchUrl and scrapedAt record where and when each job was collected.

Best fit for public early-career and graduate roles on Handshake: internship inventories by category, entry-level salary research, or monitoring a Handshake search page for new postings. It works with anonymous public pages, so it covers the jobs Handshake shows without login.

Example workflow: from a Handshake category to an internship tracker

A university career-services team starts with the public page https://joinhandshake.com/find-jobs/remote/software-engineering/, maxItems set to 50 and titleIncludes set to intern. The dataset returns each internship's title, companyName, salaryMin, salaryMax, postedAt, validThrough and applyUrl. They sort by validThrough to flag roles closing soon, export the table into the student newsletter, then schedule the same input weekly and compare jobId values to highlight only new postings.

How to scrape Handshake jobs

  1. Paste public Handshake search pages in Public search URLs, or known job pages in Direct public job URLs.
  2. Set Maximum jobs, and optionally Job title contains, Employer name contains, Remote jobs only and Minimum published salary.
  3. Click Start, then export the dataset as JSON, CSV or Excel, or read it through the API.

Input

Discover public remote engineering jobs:

{
"searchUrls": ["https://joinhandshake.com/find-jobs/remote/software-engineering/"],
"maxItems": 25,
"includeDescriptions": true,
"remoteOnly": true,
"titleIncludes": "engineer"
}

Look up known public jobs:

{
"jobUrls": [
"https://app.joinhandshake.com/public/jobs/11209339",
"https://app.joinhandshake.com/public/jobs/11209137"
],
"maxItems": 2,
"includeDescriptions": true
}
FieldTypeWhat it controls
searchUrlsarrayPublic joinhandshake.com/find-jobs/... pages to discover jobs from.
jobUrlsarrayDirect app.joinhandshake.com/public/jobs/{id} URLs.
maxItemsintegerUnique jobs saved across all URLs, up to 100. Default 10.
includeDescriptionsbooleanInclude the description in HTML and plain text. Default true.
titleIncludesstringKeep jobs whose title contains this phrase.
companyIncludesstringKeep jobs whose employer name contains this phrase.
remoteOnlybooleanKeep jobs explicitly marked remote. Default false.
minSalarynumberKeep jobs whose published maximum pay is at least this amount.

Output

One dataset row per unique public Handshake job.

FieldWhat it contains
jobId, titleHandshake job ID and title
companyName, companyUrl, companyLogoUrlEmployer name, website and logo
location, isRemotePublished location and remote flag
employmentType, industryFor example FULL_TIME and Internet & Software
salaryMin, salaryMax, salaryCurrency, salaryUnitPublished pay range, currency and unit such as YEAR
postedAt, validThroughPosting date and listing expiry
descriptionHtml, descriptionTextFull description, when includeDescriptions is on
jobUrl, applyUrlCanonical public job page and application link
sourceSearchUrl, scrapedAtOriginating search page and collection time
{
"jobId": "11517349",
"title": "Software Engineering Intern",
"companyName": "Clerkie",
"companyUrl": "https://www.clerkie.io/",
"companyLogoUrl": "https://joinhandshake-production.imgix.net/app/public/assets/institutions/326956/original/hs-emp-logo-data.",
"location": "Remote",
"isRemote": true,
"employmentType": "FULL_TIME",
"industry": "Internet & Software",
"descriptionHtml": "<p>We’re hiring<strong> Software Engineering Interns!</strong> ...</p>",
"descriptionText": "We’re hiring Software Engineering Interns! This is a full-time (40+ hours a week) salaried 12 month internship...",
"salaryMin": 80000,
"salaryMax": 100000,
"salaryCurrency": "USD",
"salaryUnit": "YEAR",
"postedAt": "2026-09-28T19:01:39.000Z",
"validThrough": "2026-10-28T06:00:00.000Z",
"jobUrl": "https://app.joinhandshake.com/public/jobs/11517349",
"applyUrl": "https://app.joinhandshake.com/public/jobs/11517349",
"sourceSearchUrl": "https://joinhandshake.com/find-jobs/remote/software-engineering/",
"scrapedAt": "2026-10-01T01:44:24.966Z"
}

Each run also writes an OUTPUT record with the outcome (COMPLETE, PARTIAL, VALID_EMPTY, INVALID_INPUT, UPSTREAM_FAILED or CONFIG_ERROR) and a RUN_SUMMARY with page-level counts.

Pricing

This Actor uses Pay per event plus Apify platform usage. You pay one Validated Handshake job returned event for each unique, validated job written to the dataset and one Actor Start event per run. Duplicates and filtered-out jobs are never charged, and maxItems caps the job events. Platform usage is billed separately by Apify.

Worked example in words: a run with maxItems set to ten that saves ten jobs costs ten Validated Handshake job returned events plus one Actor Start event, plus a small amount of platform usage. Check the live Pricing tab on this page for current event prices.

API example

curl -X POST "https://api.apify.com/v2/acts/khadinakbar~handshake-jobs-scraper/run-sync-get-dataset-items?token=YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"searchUrls": ["https://joinhandshake.com/find-jobs/remote/software-engineering/"], "maxItems": 10, "includeDescriptions": false}'
from apify_client import ApifyClient
client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("khadinakbar/handshake-jobs-scraper").call(run_input={
"searchUrls": ["https://joinhandshake.com/find-jobs/remote/software-engineering/"],
"maxItems": 25,
"titleIncludes": "intern",
})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
print(job["title"], job["companyName"], job["salaryMin"], job["validThrough"])

Use with AI agents (MCP)

Connect the Actor to Claude, ChatGPT, Cursor or any MCP client through Apify MCP and ask:

From the public Handshake remote software engineering page, list 10 internships with employer, pay range, posting date and apply link.

The agent passes the page in searchUrls with titleIncludes set to intern, reads rows from the dataset, and checks OUTPUT.outcome. Every row keeps jobUrl, sourceSearchUrl and scrapedAt for citation, and maxItems sets the cost scope before the run starts.

Best results

Starting situationHelpful actionExpected outcome
A broad category pageAdd titleIncludes, for example intern or analystOnly matching roles
Known job linksUse jobUrls instead of a search pageDirect enrichment of exactly those jobs
Lean exportsSet includeDescriptions to falseFaster, compact rows
Paid roles onlySet minSalary in the listing's pay unitJobs with published pay at or above it
Ongoing monitoringSchedule weekly and compare jobId valuesNew postings each week
Closing-soon alertsSort on validThroughRoles nearing their deadline

Builder's note

I built this Actor on Handshake's anonymous public pages, which already carry structured job data, so it reads them with plain HTTP and needs no account. I designed it around URLs because Handshake's public category pages are the cleanest way to define a search, and I kept title, company, remote and salary filters local so they refine exactly what those pages show. I found that the expiry date matters as much as the posting date for student audiences, so validThrough sits on every row.

FAQ

Do I need a Handshake account?

No. The Actor reads anonymous public Handshake job pages.

Can it search all of Handshake by keyword?

It works from the public pages you provide. Use a category page as the starting point and narrow with titleIncludes and companyIncludes.

Why is salary empty on some jobs?

Pay fields are filled when the employer publishes compensation on the listing.

Does it return student or applicant data?

It returns public job postings only.

Responsible use

This Actor collects public job-posting data from Handshake. Use it in line with Handshake's terms and applicable laws, and keep its output to job-market research and recruiting; it is designed for job postings and market analysis. Handshake is a trademark of its owner; this independent Actor is not affiliated with or endorsed by Handshake.