---
title: "JobSpy review: python-jobspy tested, and where it breaks"
description: "JobSpy is a free, MIT-licensed Python scraper that pulls LinkedIn, Indeed, Glassdoor, ZipRecruiter, Google and three regional boards into one pandas DataFrame."
canonical: https://jobspipe.dev/blog/jobspy-review
date_published: 2026-07-13
date_modified: 2026-09-30
author: Dvir Atias
---

> **Facts:** Free: 1,000 free credits, one time. Paid: from $49/month for 25,000 jobs. 12 months of history on every plan. Jobs from 30+ sources. Try it without a key: `curl -d '{"limit":3}' https://api.jobspipe.dev/v1/sandbox/jobs/search`

# JobSpy GitHub review: the Python job scraper tested, and where it breaks

JobSpy is a free, MIT-licensed Python scraper that pulls LinkedIn, Indeed, Glassdoor, ZipRecruiter, Google and three regional boards into one pandas DataFrame. It works well for prototypes, but LinkedIn usually rate limits around the 10th page, each board search is capped at around 1,000 jobs, and PyPI still ships 1.1.82 from July 2025. Past toy volumes you are buying proxies and maintaining the pipeline yourself.

JobSpy on GitHub scrapes LinkedIn, Indeed, Glassdoor, ZipRecruiter, Google and three regional boards with one Python call - until it gets blocked. What the repo ships today (PyPI has not had a release since July 2025), where it breaks, and the no-scraper path: JobsPipe's free tier for normalized postings.

**JobSpy** is an open-source Python job scraper that lives on GitHub at `speedyapply/JobSpy`: one `pip install python-jobspy`, one function call, and you get postings from LinkedIn, Indeed, Glassdoor, ZipRecruiter, Google and three regional boards back as a pandas DataFrame. We build a commercial jobs API, so we are exactly the vendor you’d expect to trash it. We’re not going to - JobSpy is genuinely good at what it is for, and it takes first place among the libraries in our [ranking of job scraping tools](https://jobspipe.dev/blog/best-job-scrapers). This review starts with what the GitHub repo actually ships today, then covers what it does well, where it breaks, and how to make the scraper-vs-API call honestly.

## The JobSpy GitHub repo, as of September 2026

Everything in this section was read from the repository, its issue tracker and PyPI on September 15, 2026.

-   **Where it lives.** The canonical repo is `github.com/speedyapply/JobSpy`. The older `cullenwatson/JobSpy` URL now redirects to the same repository. It is MIT-licensed, dates from July 2023, and has roughly 4,300 stars and 850 forks.
-   **Eight boards.** The `Site` enum in `jobspy/model.py` lists `linkedin`, `indeed`, `zip_recruiter`, `glassdoor`, `google`, `bayt`, `naukri` and `bdjobs`.
-   **PyPI is behind GitHub.** The newest release on PyPI, `python-jobspy` 1.1.82, was uploaded on July 28, 2025 and needs Python 3.10 or newer. Fixes merged since then - Naukri parsing in August 2025, a relaxed numpy pin and a BDJobs user-agent fix in January 2026, a LinkedIn date-parsing fallback in February 2026 - exist only on `main`, whose `pyproject.toml` still says 1.1.82. The GitHub Releases page lags further still: its newest tag is v1.1.79, from March 2025.
-   **A busy issue tracker.** 47 open issues and 17 open pull requests, and 18 of those open issues mention LinkedIn. Recent reports include an Indeed scrape that hangs on page 2 despite `timeout=10` (#385, September 2026), empty LinkedIn descriptions (#374) and a missing `job_url_direct` on LinkedIn results (#370).

The practical upshot: `pip install python-jobspy` gives you the July 2025 build. To run what is on GitHub today, install straight from the repo, and once it works, pin the commit you tested by adding `@<commit-sha>` to the URL:

```
pip install "git+https://github.com/speedyapply/JobSpy.git"
```

## What JobSpy does well

The core loop is hard to beat for exploratory work:

```
from jobspy import scrape_jobs

jobs = scrape_jobs(
    site_name=["indeed", "linkedin", "zip_recruiter", "glassdoor"],
    search_term="data engineer",
    location="Austin, TX",
    results_wanted=100,
)
print(jobs.head())
```

-   **One interface over many boards.** The same call shape works across every supported site, and results land in a DataFrame ready for analysis.
-   **Free and open source.** For a student project, a one-off market analysis, or a weekend prototype, the cost argument ends here.
-   **Proxies built in.** The `proxies` parameter takes a list and each board scraper round-robins through it, so the first fix for blocking is a parameter, not a rewrite.

## Where it breaks

-   **Blocking, early.** The README calls Indeed its best scraper, with no rate limiting, and is candid about the other end: LinkedIn “usually rate limits around the 10th page with one ip. Proxies are a must basically.” The LinkedIn scraper already sleeps a random 3 to 7 seconds between pages of 25, and the FAQ’s answer to a 429 is to wait between scrapes or rotate proxies. Past toy volumes you are buying rotating residential proxies and babysitting 429s - the costs the “free” framing hides.
-   **Query-shaped, capped, and picky about filters.** Per the README, every board endpoint is capped at around 1,000 jobs per search. Filters also exclude each other: on Indeed a search can use only one of `hours_old`, `job_type` with `is_remote`, or `easy_apply`; on LinkedIn only one of `hours_old` or `easy_apply`. Comprehensive or continuous coverage means enumerating a large query matrix on a schedule you maintain.
-   **No dedup, no change tracking.** The same role appears on three boards as three rows, and nothing tells you when a posting closed. Both become your code.
-   **Maintenance transfers to you.** When a board re-skins, your pipeline is down until a fix lands on GitHub - and, as the repo section shows, fixes can sit on `main` for months before they reach PyPI. Fine for research; a pager problem in production.

## Same boards, different job: where postings come from

LinkedIn and Indeed are JobSpy’s workhorse boards, and they carry most of our collection too. In JobsPipe’s own index, the three job boards hold 95.7% of active postings and ATS-hosted boards 4.3%:

-   LinkedIn48.0%
-   Indeed47.6%
-   Workday1.5%
-   Greenhouse0.9%
-   Workable0.9%
-   Ashby<0.5%
-   Lever<0.5%
-   SmartRecruiters<0.5%
-   Y Combinator<0.5%
-   Paylocity<0.5%

Share of active postings by board of origin, ten collected boards.

How this was measured

Measured from active postings on the ten collected boards (deduplicated by posting id); the mix reflects what JobsPipe collects, not the market. Generated 2026-09-09. Shares only: JobsPipe publishes percentages, not counts.

LinkedIn and Indeed are crawled broadly, while ATS boards are crawled per known company, so the ATS share is a lower bound. Postings on LinkedIn and Indeed are often syndicated from an ATS.

```
curl -X POST https://api.jobspipe.dev/v1/jobs/search \
  -H "Authorization: Bearer $JOBSPIPE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"source_or":["linkedin","indeed"],"job_title_or":["data engineer"],"limit":25}'
```

So the gap between JobSpy and an API is mostly not about where the data comes from. It is about everything that happens after the fetch, which is the part JobSpy leaves to you.

## Scraper or API: the actual decision

The decision is not about tool quality - it is about whether the collection layer is your product. If you are running a one-off analysis, learning scraping, or prototyping, JobSpy is the right tool and you should use it. If jobs data feeds something with users, revenue, or an SLA, the DIY pipeline math turns against you fast - see the build-or-buy notes for [Indeed](https://jobspipe.dev/blog/indeed-api-guide#should-you-scrape-indeed-yourself-or-use-an-api) and [Glassdoor](https://jobspipe.dev/blog/glassdoor-scraper-vs-api), and proxies plus maintenance plus on-call time reliably clears $3,000 a month before opportunity cost.

That after-the-fetch work is the structural difference. JobsPipe crawls continuously instead of per query, dedups by posting id, marks postings closed when they come down, classifies each one by occupation (ISCO-08) and industry (ISIC), converts salary to annual USD, and adds ATS boards - Workday, Greenhouse, Lever, Ashby and more - crawled per known company. One call replaces the query matrix:

```
curl https://api.jobspipe.dev/v1/jobs/search \
  -H "Authorization: Bearer jp_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "job_title_or": ["data engineer"], "job_country_code_or": ["US"], "posted_at_max_age_days": 7 }'
```

A reasonable path many teams take: prototype the idea on JobSpy, and switch the collection layer to an API when the prototype earns production status.

## Sources

-   [JobSpy repository on GitHub](https://github.com/speedyapply/JobSpy)
-   [python-jobspy on PyPI](https://pypi.org/project/python-jobspy/)
-   [JobSpy Site enum (jobspy/model.py)](https://github.com/speedyapply/JobSpy/blob/main/jobspy/model.py)

## Frequently Asked Questions

### Is JobSpy free?

Yes, JobSpy is free and open source - you install it with pip install python-jobspy. What the free framing hides is infrastructure cost: past toy volumes you are buying rotating residential proxies and babysitting 429s, because LinkedIn rate-limits unauthenticated scraping within a few hundred results and Indeed and Glassdoor run serious bot management. For a student project, a one-off analysis, or a weekend prototype, free really is free.

### Does JobSpy still work?

Yes. JobSpy is actively maintained and keeps pace with board layout changes better than most scraping libraries, with proxy support built in rather than bolted on. One scrape\_jobs call pulls from Indeed, LinkedIn, Glassdoor, ZipRecruiter, and Google into a pandas DataFrame. Its limits are operational rather than functional: blocking at scale, query-shaped results capped per run, no dedup, and no change tracking when a posting closes.

### When should I use a jobs API instead of JobSpy?

Use an API when jobs data feeds something with users, revenue, or an SLA. JobSpy is the right tool for one-off analyses, learning scraping, and prototypes, and you should use it there. Past that you own the proxies, the query matrix, the dedup, and the downtime when a board re-skins, which reliably clears $3,000 a month before opportunity cost. Many teams prototype on JobSpy and swap the collection layer later.

Related

## Keep reading

-   [Guide · Oct 6, 2026Indeed scraper in Python: how Indeed scraping works, where it breaks, and what hosted scrapers cost](https://jobspipe.dev/blog/indeed-scraper)
-   [Comparison · Jan 4, 2026Glassdoor scraper: what it costs, what breaks, and the API alternative](https://jobspipe.dev/blog/glassdoor-scraper-vs-api)
-   [Guide · Jun 26, 2026Job scraper: the build-vs-buy guide for 2026](https://jobspipe.dev/blog/job-scraper-build-vs-buy)
-   [Comparison · Sep 30, 2026Coresignal vs TheirStack (and JobsPipe): job data compared](https://jobspipe.dev/blog/coresignal-vs-theirstack)
-   [Comparison · Jul 25, 2026AI sourcing tools for recruiting: what they do, where the candidate data comes from, and what breaks](https://jobspipe.dev/blog/ai-sourcing-tools-recruiting)


## Further reading

- [How to scrape LinkedIn jobs in Python (and the API that replaces it)](https://jobspipe.dev/blog/linkedin-job-scraper-python)
- [Glassdoor API](https://jobspipe.dev/sources/glassdoor)
- [How to Scrape LinkedIn Jobs: 5 Methods Compared (2026)](https://jobspipe.dev/how-to-scrape-linkedin-jobs)
- [JSearch API: how it works, the key, limits and pricing](https://jobspipe.dev/blog/jsearch-api-direct)
- [How to use JobSpy?](https://jobspipe.dev/answers/how-to-use-jobspy)

---
Comparing free job APIs? JobsPipe's free tier is 1,000 jobs to start across 30+ sources in one normalized schema, and every /v1/sandbox route works with no key at all:

```bash
curl -d '{"limit":3}' https://api.jobspipe.dev/v1/sandbox/jobs/search
```

Free key: https://jobspipe.dev/signup. Full agent index: https://jobspipe.dev/llms.txt?src=md-twin