Scrape the whole RemoteOK board into structured rows: job title, company, salary range, tech stack, location and a link to the original posting. Reads RemoteOK's public JSON feed - no browser, no proxy, no login - so a full run takes seconds. Filter by tech stack, category, region or minimum salary.
2026-09-08 — a short result set now says whose limit it was
Measured against the live Store listing: asking for the advertised maximum of 100 returned
100 (100%), and the count reproduced exactly across separate runs — so this is the board's real
inventory, not a flaky scrape. The status message said only Returned 100 RemoteOK postings., which a
buyer who asked for 100 cannot tell apart from a broken Actor.
finishRun() now receives requested: maxJobs and appends the reason:
Returned 100 RemoteOK postings. That is every posting on the board matching your
filters — asking for100 will not return more today.
RUN_STATS also carries requested and boardExhausted. Logic and tests live in
apify-actor-kit (inventory.ts); src/kit/ here is generated.
[2.1.0] - 2026-08-27
Added — a zero-row run now says why, and fails
Adopts the shared src/kit/, generated from apify-actor-kit — do not edit in place; check-sync.sh fails a build on any hand-edit.
This is the first consumer.
Until now a run that returned nothing printed ✓ Scraping complete! and exited
SUCCEEDED. A buyer paying per result could not tell a too-narrow filter from a
broken actor from a RemoteOK format change. Now:
outcome
run
Filters removed everything
FAILS — Read 99 postings but every one was removed by your filters (techStackFilter=99). Loosen the filters and re-run.
API returned records, none usable
FAILS — a RemoteOK format change, reported as one
Feed genuinely empty
FAILS — and says how to tell the two apart
failOnZeroResults (default true) lets a scheduled user opt back into
quiet green runs.
RUN_STATS now carries a per-filter breakdown (filteredOut), and is
written before the failure — a failed run is exactly when someone reads it.
Verified locally against the live feed, no platform spend:
99 fetched → 99 parsed → filteredOut {techStackFilter: 98} → 1 pushed, exit 0;
and with a filter matching nothing, exit 1 with
RUN_STATS.zeroRowReason = filtered_out
on disk.
Fixed — maxJobs advertised a ceiling it cannot reach
The input schema offered up to 1,000. RemoteOK's public feed is a single
un-paginated page of ~100 live postings, so anything above that was unreachable
by construction. Maximum corrected to 100 and the description now states the
real limit. Selling a cap that cannot be delivered is a refund request.
Changed
One batched Actor.pushData() per run instead of one call per row.
Unreleased — 2026-08-13
Documentation only. No behavior changes; build 0.0.5 is unmodified.
Added
Full documentation suite: docs/ARCHITECTURE.md, docs/DEVELOPMENT.md, docs/REMOTEOK-DOM.md,
docs/IMPROVEMENT-PLAN.md, and CLAUDE.md.
.actor/dataset_schema.json — the output surface was previously undeclared.
README rewritten as a buyer-facing listing, with an explicit known-limitations table.
Verified against live RemoteOK
Two platform runs on 2026-08-13:
Input
Rows
Cost
Duration
maxJobs: 10
10
$0.0042
34 s
maxJobs: 100
49
$0.0025
17 s
~$0.05 per 1,000 rows — the cheapest actor in the portfolio. 49 rows is source exhaustion: the
RemoteOK homepage is the only page read and it carries ~49 listings.
Findings recorded (not fixed)
A zero-row run exits SUCCEEDED — total scrape failure is indistinguishable from success.
maxJobs advertises a maximum of 1,000; ~49 is achievable.
description is not a description — it is the row's embedded JSON-LD blob captured via
textContent and truncated at 1,000 chars, mid-string.
verified (hard-coded false) and currency (hard-coded "USD") are fabricated.
postedAt, companyUrl, applyUrl are declared but never populated.
skills duplicates techStack.
The jobId fallback embeds Date.now(), so it differs every run.
Salary regex caps at three digits — $1500 would parse as $150,000.
The categories filter is bypassed for jobs with no detected category.
All are itemized and prioritized in docs/IMPROVEMENT-PLAN.md.
0.0.5 and earlier
No changelog was kept. Build 0.0.5 is the deployed build as of 2026-08-13; the last source commit
was 2025-11-16.