Scrape Upwork jobs with full client intelligence — country, total spent, payment-verified, rating, reviews, and exact applicant count. 14 filters and incremental mode that reliably emits only new or changed listings across runs.
Incremental mode now keeps your existing history wherever it can. A run started with a
restricted API key previously moved to a fresh store unconditionally, which meant
re-collecting everything once. It now uses your existing store whenever it is allowed to,
and only starts a new one if access is genuinely refused.
Updated the underlying crawler library. A single failed storage access could previously
leave a run hanging until its time limit instead of failing or recovering.
0.6.6 — 2026-08-13
Fixed
Incremental mode no longer fails with an unexplained error when it cannot open its saved state. Runs started with a restricted API key could not open the stored state that incremental mode depends on, and the run ended with a generic "please try again later" that never cleared however often it was retried. Such a run now stops with a specific message naming what to change, and incremental runs started this way use stored state the run is allowed to create, so incremental mode works rather than failing. Runs with incrementalMode off were never affected. Affected accounts rebuild their baseline once, which means one run of already-seen jobs.
0.6.5 — 2026-08-03
Fixed
Runs no longer log Attempting to charge for an unknown event 'detail-enrichment'. Detail enrichment was listed as a separately billed $0.003 addon, but that event was never actually registered for this Actor, so the charge was rejected on every attempt and the warning was written into the run log instead. Nobody was ever billed for it. The addon has been withdrawn rather than activated: detail enrichment stays covered by the standard per-result fee, the pricing table no longer advertises a charge that does not exist, and no run's cost changes.
0.6.4 — 2026-08-02
Fixed
A rejected sessionToken is no longer a silent downgrade. Previously, when Upwork rejected the supplied token, detail enrichment was switched off for the rest of the run and the only trace was a single warning line in the log — the run finished as a success with items that were quietly missing every detail-only field (screening questions, attachments, client industry, company size, activity, allowed countries, work history). The run now reports the rejection as an error, sets a run status message explaining which fields are absent and why, and records the condition in the run summary.
Newest-first runs are now genuinely newest-first. Upwork's own recency ordering is only approximate — a job posted hours earlier can appear above a newer one — so results are re-sorted by publish time before they are written. The sort is applied before the maxResults cap, so a capped run keeps the newest jobs rather than the first ones Upwork happened to list. Runs that stream results in batches are ordered within each batch.
Corrected all current guidance for obtaining the token, including the example task and detail-client diagnostics. The previously documented oauth2_global_js_token cookie carries a token issued by a different client that has no access to the detail fields. The value that works is the authorization request header on a signed-in upwork.com request. Values pasted with a leading bearer or as a whole name=value pair are accepted and cleaned up automatically.
Fixed
When the Upwork job search backend stays unavailable through every retry, the run now reports it as a temporary upstream fetch error instead of a generic unexpected failure, so retrying later is clearly the right next step.
0.6.2 — 2026-05-26
Fixed
Brief network timeouts on the initial token request no longer fail the run outright. The retry layer now also recovers from transient thrown errors (timeouts, dropped connections), not just from non-success HTTP status codes.
0.6.1 — 2026-05-25
Fixed
Upstream-transient GraphQL errors from the Upwork job search backend (e.g. brief "search failed" responses from the upstream search index) are now retried with backoff before failing the run. These previously surfaced as immediate run failures even when a retry seconds later would have succeeded.
Standardized notification formatting and delivery across all supported channels.
Run metadata in notifications now includes the human-readable search label.
0.5 — 2026-04-24
Deploy-hardening release.
Changed
Renamed the enrichment billing event from apify-actor-detail-enrichment
to detail-enrichment (event names with apify- prefix are reserved by
Apify and cannot be registered on third-party actors).
Input form titles now consistently start with an emoji prefix across all
38 fields; schema auto-patches missing emojis on known field names on
each pre-push run via the shared tooling.
README regenerated from a fresh v0.5 sample so the live store page now
shows the rich field set including client intelligence and enrichment.
Added
Per-module test files: apiClient, categories, detailClient,
detailTransform, filters, notifications, regions, scoring —
brings total to 9 test files / 84 tests.
Country-code normalization (clientCountryCode — always ISO-3) and full
ISO-3 mapping for the countries Upwork emits.
Budget currency defaults to USD when a budget amount is present (the
source response never populates currency on search-surface results).
Fixed
clientCountry canonicalized to full country name across responses so
consumers can match consistently (Upwork mixes ISO-3 codes and names in
roughly an 18/82 split).
Country alias coverage for Upwork's non-standard spellings: Congo DRC,
Puerto Rico, Palestinian Territories, Ivory Coast, Sierra Leone, Antigua
and Barbuda, Gambia, Suriname, French Polynesia, Bermuda.
Fixed authenticated detail enrichment failing before any detail fields
could be returned.
0.4.0 — 2026-04-24
Added — notifications
Per-platform webhook/bot integrations, opt-in via separate input fields.
Fires in parallel after the dataset is pushed; failures on one platform
don't affect the others.
Telegram:telegramToken + telegramChatId. Markdown-formatted
messages with title, rate/budget, client country, applicant count, and
link per job.
Discord:discordWebhookUrl. Rich embeds color-coded by
customJobScore (green for ≥4, blue otherwise), with fields for
budget, experience level, client, proposals, and score.
Slack:slackWebhookUrl. Block Kit formatting with linked titles
and one-line metadata per job.
notificationLimit caps per-batch dispatch (default 5, max 20).
includeRunMetadata prepends a run summary line when true (default).
Pairs naturally with incrementalMode — only NEW/UPDATED jobs trigger
alerts, preventing duplicate notifications on recurring runs.
Added — README cookbook
Comprehensive user-facing README.md with minimal-start example, 7
use-case recipes (low-competition, geographic, URL-mode, real-time
alerts, LLM pipeline, custom DSL), full output sample with field
descriptions, session-token extraction guide, pricing table,
filter-reference tables, region groupings, and troubleshooting.
0.3.2 — 2026-04-24
Cookie-mode hardening after live empirical testing.
Fixed
Authenticated detail enrichment no longer fails before any detail fields
can be returned.
Added
sessionToken input description now explicitly warns that the
oauth2v2_int_XXXX format is rejected with permission errors — only JWT
Bearer tokens from the oauth2_global_js_token cookie have detail-page
scope. Live probes confirmed that OAuth2 clients issuing oauth2v2_int_*
tokens are accepted as authenticated (HTTP 200) but lack scope for every
field under jobAuthDetails.
0.3.1 — 2026-04-24
Data-quality patch, discovered during a 1000-item live audit.
Added
clientCountryCode output field — canonical ISO-3 alpha code (USA, GBR,
DEU, etc.) derived from Upwork's mixed country representation.
normalizeCountry() + deriveCountryCode() helpers in src/regions.ts.
Source data can contain either ISO-3 codes (~18% — ZAF, CHE, ARE, USA)
or full country names (~82%). We now canonicalize clientCountry
to the full name in all outputs, and always populate clientCountryCode
with ISO-3 when resolvable.
ISO-3 mapping table covering 100+ countries with alias support for
Upwork's non-standard name spellings (Congo DRC, Puerto Rico, Palestinian
Territories, Ivory Coast, etc.).
Fixed
budgetCurrency was null in 100% of fixed-price jobs — Upwork's search
source doesn't populate isoCurrencyCode on fixedPriceAmount. Now defaults
to "USD" when a budget amount is present (Upwork payment layer handles
FX, so search-surface budgets are always USD).
0.3.0 — 2026-04-24
Adds opt-in cookie-auth mode (sessionToken + enrichDetails). Users who
supply their own Upwork session token (oauth2_global_js_token cookie) unlock
a per-job detail fetch that enriches output with ~30 additional fields.
sessionToken (secret) — Bearer value from oauth2_global_js_token cookie.
enrichDetails — opt-in boolean.
Concurrency control for parallel detail fetches (default 5, max 30).
Added — pricing
New PPE event apify-actor-detail-enrichment ($0.003/enriched job).
Only charged when detail data is successfully returned. Paired with
incrementalMode, only NEW/UPDATED/REAPPEARED jobs trigger the charge —
UNCHANGED jobs serve their cached enrichment from state.
Added — state
JobStateEntry.enrichment + enrichedAt persist enriched payloads across
runs. UNCHANGED jobs automatically re-emit their cached enrichment.
Security
Auth errors (401/403) gracefully disable enrichment for the rest of the
run, emit a warning, and continue without charging.
Detail enrichment avoids returning account-owner profile data in scraped
output.
0.2.0 — 2026-04-24
Major release. Expands the search data surface with richer client intelligence.
Adds 14 filters, 5 post-fetch filter types, URL-mode input, and a composite
quality score.