All integrations

CleanJobData + Python

Access CleanJobData from Python for data science, analytics, and AI training.

Get Free API Key

Benefits

Setup Guide

1Install requests

Install the requests library.

pip install requests

2Fetch job listings

Fetch job listings with a GET request.

import requests
res = requests.get('https://api.cleanjobdata.com/jobs',
  headers={'X-API-Key': 'your-key'},
  params={'query': 'software engineer', 'limit': 50})
jobs = res.json()['data']

3Analyze with pandas

Load job data into pandas for analysis.

import pandas as pd
df = pd.DataFrame(jobs)
print(df['salary'].describe())

Advanced Recipes

Real-world patterns beyond the basic setup.

A complete pagination + pandas script

Walks every page with the cursor the API returns, loads the full result set into a DataFrame, and does basic salary analysis — copy-pasteable end to end.

import requests
import pandas as pd

API_KEY = "your-key"
BASE_URL = "https://api.cleanjobdata.com/jobs"

def fetch_all_jobs(title: str, limit: int = 100) -> list[dict]:
    jobs = []
    params = {"title": title, "limit": limit}
    cursor = None

    while True:
        if cursor:
            params["cursor"] = cursor
        res = requests.get(BASE_URL, headers={"X-API-Key": API_KEY}, params=params)
        res.raise_for_status()
        payload = res.json()
        jobs.extend(payload["data"])

        cursor = payload.get("pagination", {}).get("next_page")
        if not cursor:
            break

    return jobs

jobs = fetch_all_jobs("software engineer")
df = pd.DataFrame(jobs)

# Basic salary analysis on postings that disclose pay
priced = df.dropna(subset=["salary_min", "salary_max"])
print(priced[["salary_min", "salary_max"]].describe())
print(f"{len(priced)}/{len(df)} postings disclosed a salary range")

Environment variables

Keep the key out of source control.

# .env
CLEANJOBDATA_API_KEY=cjd_live_your_api_key_here

Frequently Asked Questions

Can I use CleanJobData with async Python?

Yes — it's plain REST/JSON, so httpx.AsyncClient or aiohttp work exactly like requests: `async with httpx.AsyncClient() as client: res = await client.get('https://api.cleanjobdata.com/jobs', headers={'X-API-Key': API_KEY}, params={'title': 'engineer', 'remote': 'true'})`. This matters most if you're fanning out requests across several filters or cursors concurrently — watch `X-RateLimit-Remaining`, since concurrent calls burn the per-second bucket faster than sequential ones.

Do you offer a Python SDK?

Not a dedicated package — the API is a handful of plain JSON endpoints, so a `requests.Session` with your key set as a default header covers it: `session = requests.Session(); session.headers.update({'X-API-Key': API_KEY})`, then `session.get('https://api.cleanjobdata.com/jobs', params={'limit': 50}).json()['data']`. That's usually all the abstraction a Python project needs on top of the REST API.

How do I paginate through the full result set?

The API returns a `next_page` cursor token inside a `pagination` object, not page numbers. Loop: send the request, read `payload['pagination']['next_page']`, and if it's not `None`, pass it back as the `cursor` param on the next request. Stop when it comes back `None` — that's the last page. Don't try to construct or decode the cursor yourself, and don't reuse one across a different filter set.

What happens if I hit the rate limit mid-script?

A 429 response includes `X-RateLimit-Remaining` and `Retry-After` headers. A simple pattern for a long-running pagination loop is to check the response status, and on 429, sleep for `Retry-After` seconds before retrying the same request — don't advance the cursor until the retry succeeds, or you'll silently skip a page.