Remote OK API: how to export remote jobs to CSV, with the link back it asks for
Last updated: 29 October 2026 · By Quicksloth
Remote OK is a job board for remote work, and it has a public API: one address, no key, JSON back. This guide shows what the API returns, what we got when we called it, and what its terms ask of anyone who reuses the jobs. It also has a short free script that saves the jobs of your tags as a CSV file, and explains when a scheduled cloud run is the better choice.
Short version: GET https://remoteok.com/api?tag=<tag> returns the latest jobs of one tag (up to about 100), and https://remoteok.com/api the latest jobs of all tags. The first item of the answer is a legal notice, not a job. If you show the jobs anywhere, link back to each job on Remote OK and name Remote OK as the source.
What the public API offers
Remote OK does not publish a documentation page for the API. What follows is what the API itself returns, as we read it on 29 October 2026, and what we have seen in our own use since 9 October 2026.
- Endpoint:
https://remoteok.com/apifor the latest jobs of all tags, andhttps://remoteok.com/api?tag=pythonfor one tag. Tags are the ones in the tag pages of remoteok.com (python,devops,customer-support). - No key, no paging: one request returns one window of recent jobs, up to about 100. There is no page parameter and no search by title or location.
- The first item is not a job: it holds
last_updated(a Unix time) andlegal, the API's terms of service. Skip it. - Tags match by substring:
?tag=uxreturns jobs whose tags merely contain "ux", such as "linux". Check the job's owntagslist if you need the exact tag. - Not live: the API is refreshed from time to time. On 29 October 2026 at about 15:00 UTC,
last_updatedsaid 28 October 2026, 21:53 UTC.
The main fields of each job, as the API returned them (some jobs also carry original and verified):
| Field | What it holds |
|---|---|
id, slug | the job ID (as text) and the last part of the job's address |
date, epoch | when the job was posted, as ISO 8601 and as Unix time |
company, position | the company and the job title |
location | free text written by the employer ("Worldwide", a city, a region), often empty |
tags | the job's Remote OK tags, often a long list |
salary_min, salary_max | the salary range in US dollars, usually per year; 0 when there is none |
description | the job description in HTML |
url, apply_url | the job page on Remote OK and where to apply (often the same page) |
company_logo, logo | image addresses, often empty |
What we got on 29 October 2026
We called the API with curl, one request at a time with a pause between them:
curl "https://remoteok.com/api?tag=python"
| Request | Jobs | Response size | With a salary | Location empty |
|---|---|---|---|---|
| all tags | 99 | 664 KB | 24 | 55 |
python | 100 | 534 KB | 6 | 14 |
devops | 72 | 343 KB | 2 | 4 |
Each request took about a second or less. The "all tags" window went back to jobs posted on 15 August 2026; the newest job was from 26 October 2026. ?tag=ux returned 55 jobs, every one tagged "linux" and none tagged "ux". A tag that does not exist (we tried zzzznotatag) returned HTTP 200 with the legal notice only.
What Remote OK asks in return
The legal item of every answer carries the API's terms. On 29 October 2026 it read:
"API Terms of Service: Please link back (with follow, and without nofollow!) to the URL on Remote OK and mention Remote OK as a source, so we get traffic back from your site. If you do not we'll have to suspend API access."
It also asks you not to use the Remote OK logo without written permission, and to use the name Remote OK. In practice: wherever you show the jobs, name Remote OK and link each job to its url with a normal link (no rel="nofollow"). Leave the company_logo and logo images out unless you have checked you may use them.
Remote OK's robots.txt allows /api to ordinary user agents (User-agent: *) and sets Crawl-delay: 1, one request per second; it blocks a list of named crawlers, such as SEO tools and AI-training bots, entirely. It also carries a content signal, ai-train=no: Remote OK does not allow its content to be collected for training AI models. A job alert, a sheet or a job board is not training, but if your use is, this is a "no".
A free Python script: your tags to CSV
The script reads one or more tags and writes remoteok_jobs.csv with one row per job: tag, ID, posted date, company, title, location, salary range, all tags, the source and the job link (the link back Remote OK asks for). It skips the legal item, keeps only jobs that really carry the tag, writes a job listed under two of your tags once, and waits one second between requests. It uses only Python's standard library (Python 3.8 or later).
"""Export the latest Remote OK jobs for one or more tags to a CSV file, with the link back Remote OK asks for."""
import csv
import json
import sys
import time
import urllib.parse
import urllib.request
TAGS = sys.argv[1:] or ["python"]
FIELDS = ["tag", "id", "posted", "company", "title", "location", "salaryMin", "salaryMax", "tags", "source", "url"]
def get_jobs(tag):
url = "https://remoteok.com/api?tag=" + urllib.parse.quote(tag)
request = urllib.request.Request(url, headers={"User-Agent": "remoteok-jobs-script"})
with urllib.request.urlopen(request, timeout=60) as response:
data = json.load(response)
return data[1:] # the first item is Remote OK's legal notice, not a job
def has_tag(job, tag): # ?tag= also matches tags that only contain the word ("ux" finds "linux")
wanted = tag.lower().replace(" ", "-")
return any(t.lower().replace(" ", "-") == wanted for t in job.get("tags") or [])
def salary(value): # Remote OK sends 0 when there is no salary
return value or None
seen = set()
with open("remoteok_jobs.csv", "w", newline="", encoding="utf-8") as file:
writer = csv.writer(file)
writer.writerow(FIELDS)
for tag in TAGS:
jobs = [j for j in get_jobs(tag) if has_tag(j, tag)]
new = [j for j in jobs if j["id"] not in seen] # a job can carry several of your tags
for j in new:
seen.add(j["id"])
writer.writerow([tag, j["id"], j.get("date"), j.get("company"), j.get("position"), j.get("location") or None,
salary(j.get("salary_min")), salary(j.get("salary_max")), "|".join(j.get("tags") or []),
"Remote OK", j.get("url")])
print(f"{tag}: {len(jobs)} jobs, {len(new)} new in this file")
time.sleep(1) # Remote OK's robots.txt asks for one second between requests
Run it with the tags after the file name:
$ python3 remoteok_jobs.py python devops ux
python: 100 jobs, 100 new in this file
devops: 72 jobs, 64 new in this file
ux: 0 jobs, 0 new in this file
What we got on 29 October 2026: a CSV with 164 jobs in about 6 seconds, 7 of them with a salary. Eight devops jobs were also python jobs and were written once. ux gave 0 because none of the 55 jobs it returned carried the tag. One row, as it appears in the file:
python,1136795,2026-08-16T00:00:03+00:00,Pivotal Health,Senior Software Engineer Case Execution,New York City,190000,220000,dev|front end|python|customer support|design|admin|exec|senior|ops|sys admin|medical|engineer|backend|digital nomad,Remote OK,https://remoteOK.com/remote-jobs/remote-senior-software-engineer-case-execution-pivotal-health-1136795
What the script does not do, to stay short: it leaves out descriptions; it does not filter by title, so a broad tag brings jobs from other fields (the row above, an engineering job, carries "customer support" and "design"); it does not fix the odd broken character in titles (for example "für" for "für"); and it exports the whole window each time. Because the API returns only the latest jobs, a busy tag needs regular runs to miss nothing, and then you want only the jobs you have not seen yet.
When the Apify Actor is worth it
The script is enough for a one-off export. Our Remote OK Jobs Scraper on the Apify Store reads the same API in the cloud. It is worth it when you need more than that:
- Only new or changed jobs: on a schedule, each run returns just the jobs that appeared or changed since the previous one, so the window of about 100 jobs per tag is not a problem if you run it often enough. The list of jobs already returned is kept for you.
- Filters: title and location keywords on top of the tags, up to 50 tags per run, and a job listed under several tags saved once.
- Clean text: broken characters and HTML codes fixed, a salary of 0 turned into an empty value, jobs that do not really carry your tag dropped.
- The link back built in: every result has
source("Remote OK") andurl. The output has no recruiter or contact fields, and descriptions are off unless you ask for them.
What we got on 29 October 2026, running the Actor's code (version 0.2, the one on the Apify Store) on our machine with this input:
{
"tags": ["python", "devops"],
"titleKeywords": ["engineer"],
"onlyNewJobs": true,
"stateKey": "remoteok-guide-test"
}
The first run saved 22 jobs with "engineer" in the title (12 python, 10 devops; one devops job was already saved as a python job) in 2 seconds; 6 had a salary. The second run, right after, saved 0. The first run of a new history returns every matching job in the window, up to Max jobs, which the Console form prefills at 100, and up to 100 jobs on Apify's free plan. With Only new or changed jobs on, the jobs left out by a limit come in the next runs, as long as they are still in the API's window.
The Actor charges per job a run saves, plus Apify's small start charge for each run. The current prices are in the Pricing tab of the Actor's page.
Questions and answers
- Do I need a Remote OK account or an API key?
- No. The API answers without a key. What it asks in return is the link back described in What Remote OK asks in return.
- Is it allowed to use the Remote OK API?
- Remote OK offers it publicly, with terms in every answer: link back to each job with a followed link, name Remote OK as the source, and leave the logo alone. Its robots.txt allows
/apiat one request per second and says no to collecting the content for AI training. If you publish the jobs and drop the link, the terms say Remote OK may suspend your access. Check also that your use of the job texts is allowed where you are. - How do I get more than 100 jobs?
- Not in one request: the API returns only its latest window for each tag. Ask for several tags, and run regularly, keeping only the jobs you have not seen before. That is what the Actor's only-new mode does on a schedule.
- Why are salary and location so often missing?
- Because employers leave them out. The API sends
0for a missing salary and an empty location. Salaries are in US dollars and usually per year, but a few employers enter small numbers that look hourly; the API has no field for the period. - Are there other free remote job APIs?
- Yes, each with its own terms. Read on 29 October 2026:
- Himalayas: "No API key is required; a free API key gives you higher rate limits", at most 20 jobs per request, and a visible link back. Its docs also say: "Do not pass them on to other job boards, aggregators, Google Jobs or LinkedIn Jobs".
- Jobicy: "No account or authentication header is required", up to 200 jobs per page, polling that "must not exceed once per hour", and "Clearly credit Jobicy as the original source when displaying listings". It allows you to "store, cache, process, and redistribute job data".
- Remotive: link back and mention Remotive as the source, "max. 4 times a day", and "Jobs displayed are delayed by 24 hours". It asks you not to submit its jobs to third-party sites such as Google Jobs or LinkedIn Jobs.
- What about jobs at specific companies?
- If the companies post on Greenhouse, Lever, Ashby or Workday, read them at the source: see how to monitor new jobs at a list of companies, and the guides for Greenhouse, Lever, Ashby and Workday.
API, script and Actor tested by Quicksloth on 29 October 2026 on the public Remote OK API; job counts change every day. Field descriptions come from the API's answers, terms from its legal item and robots.txt read on 29 October 2026. Written with AI tools and checked by Quicksloth. Quicksloth is an independent developer and is not affiliated with Remote OK, Himalayas, Jobicy, Remotive, Apify or the companies named. Remote OK, Himalayas, Jobicy, Remotive and Apify are trademarks of their respective owners.