Skip to content
Scraper Migration · Fix HTTP 429 Bans9 min read·Updated 2026-11-05

JobSpy Rate Limit (HTTP 429) Fix & Production Alternative: Unified ATS JSON API

Open-source python-jobspy works for small laptop scripts, but fails in production cron jobs and cloud workers with LinkedIn HTTP 429 Too Many Requests, Cloudflare 403 ASN bans on Indeed/Glassdoor, and $75–$300/month residential proxy bills. Migrate scrape_jobs() in 5 minutes to JobPostings API: 100% datacenter-IP-safe JSON across Greenhouse, Lever, Ashby, Workday, and 434 sources from $19/mo.

Instant 1,500 Free Credits ($1.50) + 2,000 Streak Bonus · No credit card required · Stripe (Card / Apple Pay / Google Pay) & 0%-fee Crypto (+5% bonus)

1 Credit = 1 Job Record ($0.199–$0.76 / 1K Jobs) · 0 Credits on Empty Searches · Remote OAuth 2.1 MCP: https://mcp.jobpostingsapi.com/v1/mcp

Instant Quickstart · Copy & Run in 30 Seconds

Drop-In Python Replacement for jobspy.scrape_jobs() + cURL & Node.js

Execute in Live Playground →
import pandas as pd
import requests

API_KEY = "jp_live_your_api_key"
SEARCH_URL = "https://api.jobpostingsapi.com/v1/jobs/search"

def fetch_jobs_dataframe(
    search_term: str = "backend engineer",
    country: str = "US",
    is_remote: bool = True,
    results_wanted: int = 100,
) -> pd.DataFrame:
    """
    Drop-in production replacement for jobspy.scrape_jobs().
    Works from AWS, GCP, Hetzner & GitHub Actions with zero 429 bans or proxies.
    """
    rows = []
    cursor = None

    while len(rows) < results_wanted:
        batch_limit = min(100, results_wanted - len(rows))
        params = {
            "q": search_term,
            "country": country,
            "limit": batch_limit,
        }
        if is_remote:
            params["work_arrangement"] = "remote"
        if cursor:
            params["cursor"] = cursor

        resp = requests.get(
            SEARCH_URL,
            headers={"x-api-key": API_KEY},
            params=params,
            timeout=20,
        )
        resp.raise_for_status()
        payload = resp.json()

        for job in payload.get("data", []):
            sal = job.get("salary") or {}
            comp = job.get("company") or {}
            loc = job.get("location") or {}
            src = job.get("source") or {}
            rows.append({
                "id": job.get("id"),
                "site": src.get("name"),
                "title": job.get("title"),
                "company": comp.get("name"),
                "company_domain": comp.get("domain"),
                "location": loc.get("raw"),
                "is_remote": job.get("work_arrangement") == "remote",
                "min_amount": sal.get("annual_usd_min"),
                "max_amount": sal.get("annual_usd_max"),
                "currency": sal.get("currency") or "USD",
                "job_url_direct": job.get("apply_url") or job.get("url"),
                "skills": ", ".join(job.get("skills") or []),
                "date_posted": job.get("posted_at"),
                "description": job.get("description"),
            })

        meta = payload.get("meta") or {}
        if not meta.get("has_more") or not meta.get("next_cursor"):
            break
        cursor = meta["next_cursor"]

    return pd.DataFrame(rows)

if __name__ == "__main__":
    df = fetch_jobs_dataframe("backend engineer", country="US", is_remote=True, results_wanted=50)
    print(df[["site", "company", "company_domain", "title", "min_amount", "job_url_direct"]].head())

Key Engineering Takeaways (TL;DR)

  • ✓python-jobspy hits HTTP 429/999 on LinkedIn guest endpoints within ~10–25 pages, and enabling linkedin_fetch_description=True triggers N+1 HTML requests (100 jobs = 100+ extra GETs) that burn IPs in under a minute.
  • ✓Running JobSpy from AWS, GCP, Hetzner, Railway, Render, or GitHub Actions triggers Cloudflare JA3/TLS blocks on Indeed & Glassdoor unless backed by rotating residential proxies ($75–$300+/mo).
  • ✓JobPostings API serves clean, deduplicated JSON from 434 direct ATS & corporate career portals (Greenhouse, Lever, Ashby, Workday, Rippling, SmartRecruiters, iCIMS) over standard HTTPS — zero proxies, 60–600 RPM concurrency, and 0 Credits charged on 0-result queries.
  • ✓Start free in 15 seconds with 1,500 Free Credits ($1.50, no credit card), scale from $19/mo ($0.76/1K jobs) or $25 PAYG via Stripe (Card / Apple Pay / Google Pay) & 0%-fee Crypto, or attach https://mcp.jobpostingsapi.com/v1/mcp directly to Claude & ChatGPT.

1. Why python-jobspy Hits HTTP 429 Too Many Requests & Cloud IP Bans

Developers deploying jobspy.scrape_jobs() into scheduled Airflow/GitHub Actions pipelines, FastAPI backends, or AI recruiting agents consistently run into three infrastructure walls:

  • LinkedIn Guest Endpoint Throttling & N+1 Description Amplification: JobSpy scrapes LinkedIn's unauthenticated /jobs-guest/jobs/api/seeMoreJobPostings/search HTML endpoint, which enforces aggressive per-IP sliding-window rate limits (HTTP 429 / status 999). Setting linkedin_fetch_description=True fires an extra HTTP GET per job posting to extract full text and compensation — turning a 100-job batch into 104 rapid requests.
  • Datacenter ASN & TLS Fingerprint Blocks on Indeed / Glassdoor: Cloudflare Bot Management and TLS/JA3 fingerprinting block standard Python requests/tls-client traffic originating from AWS, GCP, Azure, DigitalOcean, Hetzner, and GitHub Actions runners — forcing teams to buy rotating residential proxy bandwidth ($5–$12/GB).
  • Missing Canonical Company Domains & Redirect-Wrapped Apply Links: Job board HTML cards frequently strip employer domains, mask original ATS URLs behind tracking redirects, and silently return empty DataFrames whenever upstream CSS classes or GraphQL query hashes rotate.
Total Cost of Ownership: DIY python-jobspy + Residential Proxies vs. JobPostings API
Production MetricJobPostings API (jobpostingsapi.com)DIY python-jobspy + Proxy PoolHosted Scraper Actors (Apify / Bright Data)
AWS / GCP / Hetzner / GitHub Actions Safe100% Native HTTPS API (0 proxies needed)Blocked (429 / 403) without residential proxiesRuns in vendor cloud (compute + proxy markup)
Monthly Proxy & Maintenance Overhead$0.00 infrastructure maintenance$75 – $300+/mo residential GBs + retry queues$49 – $500+/mo actor compute + proxy residential units
Entry Price & Free Sandbox$0 Free (1,500 Credits) · $19/mo Starter · $25 PAYGOpen-source library, paid proxy bandwidth required$30 – $49+/mo platform plans
Effective Cost per 1,000 Full Jobs$0.199 – $0.76 / 1,000 jobs (0 Credits on empty queries)$1.50 – $4.50+ / 1,000 jobs in proxy GBs & retries$1.50 – $5.00+ / 1,000 scraped records
Full HTML/Text JD in Single RequestYes — up to 100 full jobs per GET call (<300ms p50)Requires N+1 per-job detail fetches on LinkedInSlow async actor run (30s – 10m wait)
Employer ATS Source Coverage434 direct ATS & career portals (Greenhouse, Lever, Ashby, Workday)4–6 consumer job boards (heavy anti-bot walls)Single-board actors per site
Normalized USD Salary & Tech SkillsBuilt-in salary.annual_usd_min/max + skills[] arrayRaw inconsistent strings or missing on guest HTMLVaries by actor schema
Remote MCP for Claude & ChatGPT1-Click OAuth 2.1: https://mcp.jobpostingsapi.com/v1/mcpNone (fails inside cloud agent sandboxes)Requires custom MCP token setup

2. 5-Minute Python Migration: Replace scrape_jobs() with pandas-Ready ATS JSON

Drop out rotating proxy URLs, sleep jitter, and 429 retry loops. The function below returns a clean pandas DataFrame matching JobSpy's familiar columns while adding canonical employer domains, normalized USD compensation, and extracted technical skills:

JobPostings API Transparent Rate Card vs. Residential Proxy Bills
Tier / PackPriceMonthly / Pack CreditsEffective Rate / 1K JobsRate Limit & Key Capabilities
Free Trial$0 (Instant, no card)1,500 instant + 2,000 streak$0.0060 RPM · Full descriptions & cursor pagination
Starter$19/mo25,000 Credits / mo$0.76 / 1K jobs60 RPM · Cheaper than 3 GB of residential proxies
Growth$49/mo100,000 Credits / mo$0.49 / 1K jobs180 RPM · Unlocks /v1/feeds/* & live ?refresh=true
Pro$99/mo300,000 Credits / mo$0.33 / 1K jobs300 RPM · 10 Webhooks + high-concurrency ETL
Scale$199/mo1,000,000 Credits / mo$0.199 / 1K jobs600 RPM · 1,000,000 full jobs/mo + priority routing
Never-Expiring PAYG$25 / $50 / $100 / $30030,000 – 800,000 Credits (+5% Crypto bonus)$0.375 – $0.83 / 1K jobsStripe (Card / Apple Pay / Google Pay) & 0%-fee Crypto

Drop-In Python Replacement for jobspy.scrape_jobs() + cURL & Node.js

Query remote US backend engineering roles across Greenhouse, Lever, Ashby, Workday, and 430+ sources with zero proxies and deterministic pagination:

curl -sG "https://api.jobpostingsapi.com/v1/jobs/search" \
  -H "x-api-key: jp_live_your_api_key" \
  --data-urlencode "q=backend engineer" \
  --data-urlencode "country=US" \
  --data-urlencode "work_arrangement=remote" \
  --data-urlencode "limit=50"
Verified Production 200 OK JSON Response (First Record from Live Gateway Capture)
{
  "code": 0,
  "status": "ok",
  "meta": {
    "request_id": "d1c0b11c-f35c-40cb-87f3-361e394a0dc3",
    "count": 1,
    "total": 507,
    "total_relation": "eq",
    "has_more": true,
    "next_cursor": "eyJrIjoibG9jYWwiLCJvIjoyfQ",
    "took_ms": 123,
    "redistribution_filter": "redistributable_only"
  },
  "data": [
    {
      "id": "j_n4p2mfqrxjlhyw7w",
      "data_tier": "premium",
      "status": "active",
      "title": "Senior Backend Engineer - Backend",
      "company": {
        "id": "c_x5lqv2wtrcdok",
        "name": "Dragos",
        "slug": "dragos",
        "domain": "dragos.com",
        "is_staffing_agency": false,
        "industry": "software_it"
      },
      "department": "Backend Development",
      "location": {
        "raw": "United States",
        "country": "US"
      },
      "work_arrangement": "remote",
      "employment_type": "full_time",
      "seniority": "senior",
      "experience_years_min": 5,
      "job_function": "engineering",
      "skills": [
        "cybersecurity",
        "rust",
        "docker",
        "kotlin",
        "postgresql",
        "terraform",
        "microservices",
        "python",
        "kubernetes",
        "distributed systems"
      ],
      "salary": {
        "min": 165000,
        "max": 165000,
        "currency": "USD",
        "period": "year",
        "annual_usd_min": 165000,
        "annual_usd_max": 165000
      },
      "url": "https://job-boards.greenhouse.io/dragos/jobs/5364834008",
      "apply_url": "https://job-boards.greenhouse.io/dragos/jobs/5364834008",
      "source": {
        "name": "greenhouse",
        "display_name": "Greenhouse",
        "type": "ats",
        "board": "dragos",
        "job_id": "5364834008"
      },
      "redistribution_allowed": true,
      "posted_at": "2026-07-21T01:17:03.000Z"
    }
  ]
}

3. Give Claude, ChatGPT & Coding Agents Live Job Search via Remote MCP (https://mcp.jobpostingsapi.com/v1/mcp)

Wrapping python-jobspy inside an MCP tool or cloud AI agent fails immediately because Anthropic, OpenAI, Modal, and cloud container egress IPs are blocked by LinkedIn and Cloudflare. Use our hosted MCP endpoints instead:

  • 1-Click OAuth 2.1 Remote MCP (Claude Web & ChatGPT Connectors): Point Claude.ai or ChatGPT Connectors to https://mcp.jobpostingsapi.com/v1/mcp. Browser-based OAuth 2.1 PKCE authenticates in one click, mints 1,500 Free Credits automatically, and exposes search_jobs, get_company_jobs, get_job_detail, and detect_company_ats with zero 429 errors.
  • API-Key HTTP MCP & Local Stdio Package: For Cursor, Windsurf, Claude Code, or automated agent frameworks, connect directly to https://api.jobpostingsapi.com/mcp with Authorization: Bearer jp_live_... or run npx -y @jobpostingsapi/mcp-server.
  • Free Browser Utilities Before Writing Code: Inspect live Greenhouse/Lever/Ashby JSON payloads at /tools/greenhouse-lever-job-json-viewer or detect any company's underlying ATS slug for free at /tools/ats-detector.

Interactive Engineering Workbench · GET /v1/jobs/search

Verify real-time latency, pagination math & JSON schema

5,000 jobs/day
2,000 records/day
500 checks/day
HTTP Calls / Day
570
100 jobs/page batching
ATS Sources Covered
434 Sources
1 JSON schema
Empty Search Fee
0 Credits
$0.00 for 0 results
Estimated Monthly Pipeline Cost (30 Days)
$44.78/ mo at Scale rate ($74.25 at Pro rate)
Monthly consumption: 225,000 Credits (7,500 Credits/day)
JobPostings API (Scale $0.199/1K):$44.78 / mo
Legacy Enterprise Job Feeds:$1012.50 / mo
Empty search / 4xx error fee:$0.00 (0 Credits)

Frequently Asked Questions

Why does python-jobspy throw 429 Too Many Requests after a few pages?
LinkedIn's unauthenticated guest job search endpoint rate-limits IPs after roughly 10–25 paginated requests, and setting linkedin_fetch_description=True triggers a separate HTTP GET for every single job card. JobPostings API returns up to 100 complete job descriptions per single HTTPS request from our pre-indexed 434-source ATS database with zero 429 blocks.
Why does JobSpy work on my home Wi-Fi but fail on AWS, GitHub Actions, or Hetzner?
Home Wi-Fi uses a residential ISP ASN, whereas AWS, GCP, Azure, Hetzner, Railway, and GitHub Actions use datacenter ASNs that Cloudflare and LinkedIn block at the TLS/edge layer. JobPostings API is an authenticated REST & MCP gateway designed specifically for cloud servers, serverless functions, and CI cron jobs.
Is JobPostings API cheaper than buying rotating residential proxies for JobSpy?
Yes. Reliable residential proxy pools typically cost $75–$300+/month once HTML page weight and failed retries are counted. JobPostings API includes 1,500 Free Credits ($1.50) on sign-up, starts at $19/month for 25,000 full job records ($0.76/1K jobs) or $25 non-expiring PAYG, and charges 0 Credits when a search returns 0 results.
Does JobPostings API include direct employer apply URLs instead of job board redirects?
Yes. Every verified ATS record links directly to the employer's canonical Greenhouse, Lever, Ashby, Workday, Rippling, SmartRecruiters, or corporate career-site requisition URL, alongside company.domain and normalized USD salary bounds.
How can I connect this API to Claude, ChatGPT, or Cursor without scraping?
Add https://mcp.jobpostingsapi.com/v1/mcp as a Remote OAuth 2.1 MCP connector in Claude.ai or ChatGPT, or run npx -y @jobpostingsapi/mcp-server in Cursor, Windsurf, or Claude Desktop.