Remote Jobs API & Scraper – Jobicy, Remote OK, Only New avatar

Remote Jobs API & Scraper – Jobicy, Remote OK, Only New

Pricing

$1.00 / 1,000 new remote jobs

Go to Apify Store
Remote Jobs API & Scraper – Jobicy, Remote OK, Only New

Remote Jobs API & Scraper – Jobicy, Remote OK, Only New

Remote jobs from sources licensed for commercial republishing (Jobicy, Remote OK). Deduplicated, yearly salary, filters, only-new mode. Pay per new job.

Pricing

$1.00 / 1,000 new remote jobs

Rating

0.0

(0)

Developer

Francesco Antonio Russo

Francesco Antonio Russo

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Categories

Share

Remote job postings from sources that allow commercial republishing - Jobicy and Remote OK - in one clean feed. Unlike feeds built on boards whose terms bar passing jobs on (Himalayas, for example: "Do not pass them on to third parties ... including through feeds"), every source here is used within its published terms, with attribution built into each row. Same fields whatever the source, duplicates merged, salary normalized to a yearly figure, and an "only new" mode that makes a daily job feed a two-click job. You pay $0.001 per NEW job delivered - nothing for duplicates, jobs you already got, or jobs your filters drop.

Built for people who need remote jobs as data: job-board and newsletter owners, recruiters watching a niche, career coaches, salary researchers, and anyone feeding a Slack channel, a Google Sheet, an n8n / Make / Zapier flow or an AI agent with fresh remote openings.

What you get

  • Two public job boards, one schema. Jobicy (the last 7 days, ~1,100 postings at the time of writing) and Remote OK (~100 current postings). Both are read through their public APIs: no scraping, no login, no proxy.
  • Duplicates merged. The same posting on both boards (same company + title, or same link) is delivered once, with the other listing under alsoListedOn.
  • Only new postings. Switch on onlyNew and every run returns just what appeared since the last one. The memory is stored in your Apify account, saved after each delivered batch, and can be split per task with memoryKey.
  • Salary you can compare. Hourly, daily, weekly and monthly figures become a yearly figure, and the row says whether that figure was salaryYearlyEstimated. Currencies are kept as published (never converted).
  • Real filters. Keywords (any of, whole words), excluded keywords, category, contract type, experience level, allowed countries or regions, only with salary, minimum yearly salary, posted after.
  • Honest labels. Seniority that is only a guess from the title is flagged (seniorityInferred). A bare "Remote" is unspecified, never silently "worldwide".
  • No personal data. Company and posting data only. No recruiter field is extracted. The description is the employer's own text and may still mention a name; e-mail addresses in it, including disguised ones such as name(at)domain.com, are replaced by [email removed].
  • Attribution built in. Every row carries the posting url on its source board and an attribution text, as the sources' terms require.

Pricing - pay per new job

EventPriceWhen it is charged
job - Remote job posting$0.001Once for each posting delivered to your dataset (after it is stored).

Free: postings merged as duplicates, postings dropped by your filters, postings already delivered in an earlier run (onlyNew), postings a source could not give us, and a source that failed. If you set a maximum cost per run, the Actor stops delivering the moment the limit is reached and tells you in the SUMMARY how many postings it held back (with onlyNew they stay "new" for the next run). Example: 150 new postings = $0.15. A full unfiltered first run of ~1,200 postings = about $1.20.

Quick start

  1. Open the Actor and press Start: you get up to 25 current remote jobs (the prefilled maxItems).
  2. Add filters, for example keywords: ["python", "django"], countries: ["DE"], onlyWithSalary: true.
  3. For a daily feed: set onlyNew: true, remove maxItems, and Schedule the Actor once a day. Every run returns only the postings you have not seen.

Input

FieldTitleDefaultWhat it does
sourcesSources["jobicy", "remoteok"]Which boards to read. Both are public APIs that need no key. Leave both selected for the widest feed; duplicates between them are merged.
keywordsKeywords (any of)emptyKeep a posting if ANY of these words or phrases appears as a whole word in its title, company, tags or description ("java" does not match "javascript"). Leave empty for no keyword filter.
excludeKeywordsExclude keywordsemptyDrop a posting if any of these appears. Same whole-word rule as above.
keywordsInTitleOnlyMatch keywords in the title onlyfalseLook for the keywords in the job title only, not in the description. Fewer, more precise results.
categoriesCategoriesemptyKeep only these categories. Every posting gets one shared category whatever its source calls it. Leave empty for all.
employmentTypesContract typesemptyKeep only these. Postings whose source does not state a type (most of Remote OK) are left out when you pick one.
senioritiesExperience levelsemptyKeep only these. Jobicy publishes a level; for Remote OK it is guessed from the title (see seniorityInferred). Postings with no level are left out when you pick one.
countriesAllowed countriesemptyKeep postings someone living in one of these countries can take. Use ISO codes (US, DE), names (Germany) or regions (Europe, EU, EMEA, APAC, LATAM, North America). Worldwide postings are kept too (see below). The sources do not publish time zones, so there is no time-zone filter.
includeWorldwideInclude worldwide postingstrueWith "Allowed countries" set, also keep postings that say "Anywhere" or "Worldwide".
includeUnspecifiedLocationInclude postings with no usable locationfalseWith "Allowed countries" set, also keep postings whose location is empty, a bare "Remote" or a city we cannot place. Off by default: we do not guess.
onlyWithSalaryOnly postings with a salaryfalseDrop postings that publish no salary.
minSalaryYearlyMinimum yearly salaryemptyKeep postings whose top yearly salary reaches this amount, in the currency below (hourly, weekly and monthly figures are converted to a year first). Postings with no salary or in another currency are dropped. Leave empty for no minimum.
salaryCurrencyCurrency for the minimumUSDThree-letter code of the currency the minimum is in. Currencies are never converted.
postedAfterPosted afteremptyOnly postings published on or after this date, such as 2026-10-15, or a relative time such as "3 days" or "2 weeks".
descriptionFormatDescription formattextPlain text (easy to read and search), the original HTML (safe to sanitize before showing it), or no description (smaller output). E-mail addresses are removed either way.
maxItemsMaximum new postingsemptyStop after this many postings are delivered (and charged). Postings held back stay "new" for the next run when "Only new postings" is on. Leave empty for no limit. The spending limit you set on the run is respected too.
onlyNewOnly new postingsfalseDeliver only postings this feed has not delivered before. Run it on a schedule and every run returns just what appeared since. The memory is saved after each delivered batch. First run: everything currently listed counts as new.
memoryKeyMemory keydefaultName of the memory used by "Only new postings". Use a different key for each scheduled task (for example one per filter set) so they do not share what was delivered. Letters, digits, - and _.

Postings that do not pass the filters are dropped for free. All filters apply together. A posting whose source does not state the thing you filter on (for example a contract type) is left out when you filter on it.

Output

One row per posting, always the same fields in the same order:

{
"id": "jobicy:153777",
"source": "jobicy",
"sourceName": "Jobicy",
"url": "https://jobicy.com/jobs/153777-sales-manager-net-new-sales",
"title": "Sales Manager - Net New Sales",
"company": "CoderPad",
"postedAt": "2026-10-22T04:45:25.000Z",
"employmentTypes": ["full_time"],
"seniority": "lead_director",
"seniorityInferred": false,
"category": "sales",
"locationText": "USA",
"locationRestriction": "restricted",
"countries": ["US"],
"salaryMin": 200000,
"salaryMax": 220000,
"salaryCurrency": "USD",
"salaryPeriod": "year",
"salaryMinYearly": 200000,
"salaryMaxYearly": 220000,
"salaryYearlyEstimated": false,
"alsoListedOn": [],
"attribution": "Jobicy (https://jobicy.com) - listing and apply link are on Jobicy; used under the Jobicy API terms.",
"fetchedAt": "2026-10-22T10:08:37.000Z"
}

(shortened: the real row also has description, companyLogoUrl, categories, tags and regions.)

FieldTypeMeaning
idstringStable ID of the posting: ":
sourcestringBoard the record comes from: "jobicy" or "remoteok". When the same posting is on both, the first one in the list above supplies the record.
sourceNamestringHuman name of the source board.
urlstringCanonical URL of the posting ON THE SOURCE board. Use it for the "Apply" button: the sources require that apply links and credit stay on their own pages.
titlestringTitle as published.
companystringHiring company name. Company only: no recruiter names or e-mails are ever delivered.
companyLogoUrlstring/nullCompany logo URL when the source gives one (the Remote OK logo itself is never used).
postedAtstring/nullPublication date, ISO 8601 UTC.
descriptionstring/nullJob description as plain text (default), HTML or null, see "descriptionFormat". E-mail addresses inside the text are replaced by "[email removed]".
employmentTypesarrayAny of full_time, part_time, contract, freelance, internship, temporary, other. Empty when the source does not say.
senioritystring/nullentry, mid, senior or lead_director. Null when the source says "any" or nothing and the title gives no hint.
seniorityInferredbooleanTrue when seniority was guessed from the title because the source gives no level (always the case for Remote OK).
categorystringOne shared category: engineering, devops, data, security, design, product, marketing, sales, support, finance, hr, legal, operations, healthcare, education or other.
categoriesarrayCategory names exactly as the source gives them (Jobicy industries). Empty for Remote OK.
tagsarraySkill and topic tags as the source gives them (Remote OK). Empty for Jobicy.
locationTextstring/nullThe location text of the source, untouched.
locationRestrictionstring"worldwide" (the text says anywhere/worldwide), "restricted" (named countries or regions) or "unspecified" (nothing usable; a bare "Remote" is unspecified, not worldwide).
countriesarrayISO 3166-1 alpha-2 codes of the countries named in the location text.
regionsarrayRegions named in the location text: europe, eu, emea, apac, latam, north america, americas.
salaryMinnumber/nullLower end of the published range, in the published period. Null when no salary is published.
salaryMaxnumber/nullUpper end of the published range.
salaryCurrencystring/nullISO 4217 code. Never converted: no exchange rates are applied.
salaryPeriodstring/nullyear, month, week, day or hour.
salaryMinYearlynumber/nullLower end per year: x12 for months, x52 weeks, x260 days, x2080 hours. Same currency as salaryCurrency.
salaryMaxYearlynumber/nullUpper end per year.
salaryYearlyEstimatedboolean/nullFalse when the source published a yearly figure; true when the yearly figure was computed from another period (or a guessed one). Null without salary.
alsoListedOnarraySame posting found on the other source: [{ source, sourceName, id, url }]. Empty when only one source has it.
attributionstringCredit text for the source(s). Show it, with the posting URL, wherever you display the posting.
fetchedAtstringWhen the source was read, ISO 8601 UTC (up to one hour old: sources are read at most once per hour).

Salary: how the yearly figure is made

Published periodYearly figuresalaryYearlyEstimated
yearas publishedfalse
monthx 12true
weekx 52true
dayx 260true
hourx 2,080true

Remote OK publishes yearly USD amounts; the few figures under 1,000 there are clearly hourly rates, so they are read as hourly and flagged as estimated. Some sources publish odd numbers (for example a range of 10,000-10,000): they are passed on as published. Currencies are never converted - there is no exchange-rate source, so minSalaryYearly compares in one currency (salaryCurrency, default USD) and leaves out the others.

Location: what it means

locationRestriction is worldwide when the posting says Anywhere / Worldwide, restricted when it names countries or regions (countries are ISO codes, regions are europe, eu, emea, apac, latam, north america, americas), and unspecified when there is nothing usable: an empty location, a bare "Remote", or a city we do not place. We do not guess. Time zones are not published by these sources, so there is no time-zone field or filter.

The run summary

Every run writes a SUMMARY record to the key-value store: status, what each source returned (fetched, usable, discarded, whether it came from the one-hour cache), how many postings were merged as duplicates, dropped by each filter, already delivered, delivered and held back, the stop reason, billing, and warnings.

Sources and their terms (read on 22 October 2026)

SourceWhat the terms sayWhat this Actor does
Jobicy - API & RSS terms, site termsListings may be used in your own products, commercially, and stored, cached, processed and redistributed. "Use of content requires a clickable source link"; keep the canonical Jobicy URL and keep apply links pointing at Jobicy; credit Jobicy. "Start a new automated pass no more than once per hour"; handle HTTP 429 with a deferred retry. The API serves the last 7 days.Uses the public API only. Keeps the Jobicy URL and an attribution on every row. Reads Jobicy at most once per hour (the last answer is cached for 60 minutes), waits at least 1 second between requests and obeys Retry-After.
Remote OK - API notice, site termsThe API answer says: link back to the URL on Remote OK and mention Remote OK as a source; do not use the Remote OK logo; otherwise API access can be suspended. The site terms say nothing against API reuse.Keeps the Remote OK URL and an attribution on every row, never ships the Remote OK logo, same one-hour cache and 1-request-per-second pacing.

Your side of the deal: if you publish these postings, show the attribution and link to the posting url (for Remote OK a normal followed link), and send applicants to that URL. Jobicy also asks you to remove postings that have expired (a posting that drops out of its 7-day feed is not necessarily closed: confirm before you mark it closed), and to keep your own data in step with the source. The terms of each board apply to you as the user of the data.

The attribution texts delivered in the rows are exactly:

  • Jobicy: Jobicy (https://jobicy.com) - listing and apply link are on Jobicy; used under the Jobicy API terms.
  • Remote OK: Remote OK (https://remoteok.com) - source of this listing; link back to the Remote OK URL.

Sources deliberately NOT used (and why)

  • Himalayas - its API terms (section 113, read 22 Oct 2026) allow showing jobs "only on sites and apps you operate" and say "Do not pass them on to third parties ... including through feeds". A data feed sold to other people is exactly that, so it is not included.
  • Arbeitnow - its API asks for a link back, but its terms of use (section 2) grant a licence for "personal, non-commercial transitory viewing only" of the site materials, and it is unclear whether that covers a paid feed. Left out until Arbeitnow confirms in writing that commercial reuse is fine.
  • Remotive - API terms ask you not to submit its jobs to third-party sites, require a 24-hour delay and a link back, and offer a paid API for other uses; not used.
  • Working Nomads - its API is open but no reuse terms are published for it; no terms, no use.
  • LinkedIn, Indeed and any site that blocks bots - never scraped.

Limits (honest)

  • Two boards, not twenty. Together about 1,200 postings are listed at any time; most are tech, sales and operations roles. Jobicy only serves the last 7 days.
  • Sources are read at most once per hour; a run started twice in an hour sees the same data (fetchedAt tells you when it was read).
  • Category and seniority are mapped by rules: Jobicy states a level, but it is dropped when the title contradicts it (many Jobicy postings are tagged "Director" whatever the title says), and for Remote OK the level is always a guess from the title. Check seniorityInferred.
  • The description is the employer's text. We remove e-mail addresses but do not rewrite it.
  • No contact details, no application tracking, no salary currency conversion, no time zones.
  • A posting that disappears from a board is not announced; use postedAt and onlyNew.

FAQ

How is "only new" decided? A posting is "delivered" once it is in your dataset. Its id (and the id of the same posting on the other board) is then saved to a memory in your account. The next run skips any posting whose id is in the memory. Postings are forgotten after 60 days.

Can I run several scheduled tasks with different filters? Yes - give each task its own memoryKey, so they do not share the memory.

What if a run is interrupted? The Apify platform may restart a run on another server. The Actor reads what is already in the dataset and does not deliver or charge those postings twice.

Why did my second run return nothing? With onlyNew that is the point: nothing new appeared. Without it, check the filters and the SUMMARY.

Can I use my own keys or another job board? Not in this version. Open an issue in the Actor page with the board and we will check its terms.

Use it from code

curl -X POST "https://api.apify.com/v2/acts/far003~remote-jobs-feed/run-sync-get-dataset-items?token=<YOUR_API_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"keywords": ["python"], "countries": ["DE"], "onlyNew": true, "memoryKey": "python-de"}'
from apify_client import ApifyClient
client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("far003/remote-jobs-feed").call(run_input={"onlyNew": True, "memoryKey": "daily", "categories": ["engineering"]})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
print(job["title"], job["company"], job["url"], job["attribution"])
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('far003/remote-jobs-feed').call({ onlyNew: true, memoryKey: 'daily' });
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Works with Apify Schedules (run it every morning), webhooks (call your endpoint when a run finishes), the Make, Zapier and n8n integrations, Google Sheets, Slack and the Apify MCP server for AI agents. Export the dataset as JSON, CSV, Excel, XML or RSS.

Support

Something wrong, or a field you need? Use the Issues tab of this Actor. Include the run ID; the SUMMARY record tells us what each source returned.