Free Remote Job Board APIs
JSON & RSS endpoints you can hit without registration or API keys. Tested September 2026.
๐ญ Want a ready-made tool?
GigWatch watches all these sources automatically, dedupes results, and AI-ranks them against your skill profile. Self-hosted, free, no account.
GitHub โ ยท Live Demo โ
JSON APIs (no auth)
| Board | Endpoint | Notes |
| Remotive | remotive.com/api/remote-jobs?limit=50 | Title, company, tags, salary, location, contract type |
| RemoteOK | remoteok.com/api | Company, category, tags, salary range |
| Jobicy | jobicy.com/api/v2/remote-jobs?count=50 | Aggregates 50+ boards; industry, level, geo |
| Hacker News | hn.algolia.com/api/v1/search?query=hiring&tags=story | Algolia-backed; filter by date, points |
RSS / Atom Feeds
| Board | Feed URL | Notes |
| We Work Remotely | weworkremotely.com/remote-jobs.rss | Largest remote-only board; dev, design, marketing, sales |
| Working Nomads | workingnomads.com/feed | Curated across categories |
| Jobspresso | jobspresso.co/rss.xml | Startup-focused |
Niche / Key-Required (free tier)
| Source | Endpoint | Notes |
| Adzuna | api.adzuna.com/v1/api/jobs/search/ee?app_id=KEY | 250 req/day free; register at adzuna.com |
| Jooble | jooble.org/api/search?keyword=remote&api_key=*** | Aggregates many boards; free key |
SPA / No Clean API
| Board | Why it's hard |
| JustRemote | Next.js SPA; /api/jobs returns HTML shell |
| Arc.dev | Cloudflare-protected; blocks non-browser UAs |
| Toptal / Turing | Auth-walled; enterprise-focused |
Python Quick Start
import requests, time
from dataclasses import dataclass, field
@dataclass
class Job:
title: str
company: str | None
url: str
tags: list[str] = field(default_factory=list)
salary: str | None = None
source: str = ""
def fetch_all(limit=50):
jobs = []
r = requests.get("https://remotive.com/api/remote-jobs",
params={"limit": limit}, timeout=15)
for j in r.json().get("jobs", []):
jobs.append(Job(j["title"], j.get("company_name"),
j.get("url",""), j.get("tags",[]),
j.get("salary"), "remotive"))
r = requests.get("https://jobicy.com/api/v2/remote-jobs",
params={"count": limit}, timeout=15)
for j in r.json():
jobs.append(Job(j.get("title",""), j.get("company"),
j.get("link",""),
[j["industry"]] if j.get("industry") else [],
j.get("salary"), "jobicy"))
r = requests.get("https://hn.algolia.com/api/v1/search",
params={"query":"hiring","tags":"story",
"numericFilters":f"created_at_i>{int(time.time())-7*86400}",
"hitsPerPage":limit}, timeout=15)
for h in r.json().get("hits",[]):
jobs.append(Job(h.get("title",""), None,
h.get("url") or f"https://news.ycombinator.com/item?id={h['objectID']}",
["hn"], None, "hn"))
return jobs
for job in fetch_all(10):
print(f"[{job.source:10}] {job.title} @ {job.company}")
Tips
๐ก Cache aggressively. These are public marketing endpoints, not SLA-backed APIs. Cache 15-60 min minimum.
๐ก Set a User-Agent. Some boards block the default python-requests UA.
๐ก Dedupe. Same job appears on multiple aggregators. Match on normalized title + company.
๐ก Salary is sparse. Most boards don't publish it. Don't build features that depend on it.