Scrape Upwork jobs with full client intelligence — country, total spent, payment-verified, rating, reviews, and exact applicant count. 14 filters and incremental mode that emits only new or changed listings across runs.
Replaced actor-specific notification formatters with canonical workspace lib (native fetch, no extra deps)
sendAllNotifications now takes NotificationItem[] + RunMetadata with searchLabel field
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.
Removed an unused GraphQL variable from the detail-fetch query that
caused every authenticated request to be rejected with a validation
error.
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
JobAuthDetailsQuery previously declared an unused $isFreelancerOrAgency
variable left over from trimming the frontend query. Upwork's GraphQL
validator rejected the query with Validation error (UnusedVariable)
before any field could be fetched. Removed the unused variable from both
the query signature and the variables payload.
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.
Upwork's userJobSearchV1 returns a mix of ISO-3 codes (~18% — ZAF, CHE,
ARE, USA) and 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.
currentUserInfo fragment deliberately dropped from the detail query to
prevent cookie-owner's own freelancer profile from leaking into scraped
output.
0.2.0 — 2026-04-24
Major release. Switches from the visitorJobSearchV1 GraphQL operation to
userJobSearchV1, which accepts the same anonymous visitor token but
returns a much richer field surface. Adds 14 filters, 5
client-side filter types, URL-mode input, and a composite quality score.