# Upwork Jobs Scraper – Clients, Budgets & Contacts (`trakk/upwork-jobs-scraper`) Actor

Find current Upwork jobs by keyword, URL or job ID. Extract descriptions, budgets, skills, client spend and hiring signals, activity, qualifications, questions and public contacts. Rank opportunities and export JSON, CSV or Excel.

- **URL**: https://apify.com/trakk/upwork-jobs-scraper.md
- **Developed by:** [Kelopr\_bk](https://apify.com/trakk) (community)
- **Categories:** Jobs, Lead generation, Developer tools
- **Stats:** 5 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.99 / 1,000 upwork jobs

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Upwork Jobs Scraper — Clients, Budgets & Contacts

Turn current Upwork job searches into structured opportunity data. Find jobs by keyword, enrich known listings, compare budgets, inspect public client hiring signals, extract contacts explicitly published in job text, and rank the best opportunities with explainable scores.

**Current jobs** · **Full descriptions** · **Budgets & skills** · **Client intelligence** · **Job activity** · **Qualifications** · **Screening questions** · **Public contacts** · **Application insights**

### What can this Actor do?

| Workflow | Best for | Output |
|---|---|---|
| `SEARCH` | Fast market and opportunity scans | Job identity, description, budget, skills, experience, duration, timestamps and search rank |
| `SEARCH_FULL` | Lead qualification and bid research | Search data plus available client, activity, qualification, attachment and screening-question fields |
| `DETAIL` | Enrich known jobs | Full public record for supplied Upwork job URLs or numeric job IDs |

Every workflow deduplicates by Upwork job ID, keeps matched search terms, applies filters, extracts public contacts and adds explainable opportunity intelligence.

### Quick start

#### Find recent Python jobs

```json
{
  "mode": "SEARCH",
  "queries": ["python developer"],
  "sourceSort": "recency",
  "maxResults": 25,
  "resultsPerQuery": 25
}
```

#### Search and add full job intelligence

```json
{
  "mode": "SEARCH_FULL",
  "queries": ["web scraping", "data extraction"],
  "maxResults": 20,
  "resultsPerQuery": 30,
  "includeContacts": true,
  "sortResultsBy": "OPPORTUNITY_SCORE"
}
```

#### Enrich known Upwork jobs

```json
{
  "mode": "DETAIL",
  "startUrls": [
    {"url": "https://www.upwork.com/jobs/~022094813107468472052"}
  ],
  "jobIds": ["2094725460191723809"],
  "maxResults": 10
}
```

### What data will you receive?

#### Job identity and timing

`jobId`, `ciphertext`, `url`, `title`, `description`, `status`, `closeReason`, `createdAt`, `publishedAt`, `scrapedAt`, `detailFetched`, `detailStatus`, `detailSource`, `warnings`.

#### Contract and budget

`jobType`, `experienceLevel`, `hourlyRateMin`, `hourlyRateMax`, `weeklyRetainerBudget`, `fixedBudget`, `fixedBudgetMax`, `budgetMin`, `budgetMax`, `budgetDisplay`, `currencyCode`, `engagementType`, `durationLabel`, `durationWeeks`, `workload`, `workArrangement`, `personsToHire`, `premium`, `enterpriseJob`, `contractStartDate`, `contractEndDate`, `onSiteType`.

#### Skills and classification

`skills`, `skillIds`, `highlightedSkills`, `technicalStack`, `inferredSkills`, `category`, `categorySlug`, `categoryGroup`, `categoryGroupSlug`, `subcategory`, `occupation`, `tags`.

#### Client intelligence

When Upwork publishes the values, full records can include:

`clientCountry`, `clientCity`, `clientState`, `clientTimezone`, `clientIndustry`, `clientCompanySize`, `clientPaymentVerified`, `clientRating`, `clientReviewCount`, `clientTotalSpent`, `clientJobsPosted`, `clientHireRate`, `clientOpenJobs`, `clientTotalHires`, `clientActiveHires`, `clientAverageHourlyRate`, `clientTotalHours`, `clientMemberSince`, `clientCanHire`.

#### Job activity

`totalApplicants`, `invitesSent`, `totalInvitedToInterview`, `totalHired`, `totalOffers`, `unansweredInvites`, `lastClientActivity`, `personsToHire`, `canReceiveProposals`.

#### Qualifications and application requirements

`preferredCountries`, `preferredStates`, `preferredRegions`, `preferredTimezones`, `localMarket`, `requiredEnglishProficiency`, `requiredJobSuccessScore`, `requiredHoursWorked`, `portfolioRequired`, `risingTalentPreferred`, `coverLetterRequired`, `screeningQuestions`, `screeningQuestionCount`, `attachmentNames`, `attachmentCount`.

#### Public contacts

The Actor finds only contacts explicitly published in the job text:

- email addresses;
- phone numbers;
- external websites;
- public messaging handles.

Contacts are saved to a separate dataset with the job ID, job title, source context and job URL. `contactCount` and `hasPublicContacts` stay on the job record.

### Application Intelligence

Every job receives transparent, locally calculated signals:

- `opportunityScore` and `opportunityBand`;
- `applyRecommendation`;
- `riskFlags` and `riskFlagCount`;
- `freshnessMinutes`;
- `competitionLevel`;
- `clientConfidenceScore`;
- `applicationEffort`;
- `technicalStack` and `inferredSkills`;
- `applicationRequirements`;
- `clientIntentSignals`;
- `proposalTips`;
- `agencyPreference`;
- `antiBotPhrase` when the client publishes a proposal instruction;
- `jobFingerprint` for stable downstream deduplication.

Scores never replace source data. The `jobScoreBreakdownJson` field explains the components used for ranking.

### Filters

| Input | Purpose |
|---|---|
| `jobType` | Any, hourly or fixed-price work |
| `experienceLevel` | Entry level, intermediate or expert |
| `minBudget`, `maxBudget` | Normalized budget bounds |
| `minHourlyRate`, `maxHourlyRate` | Hourly-rate range |
| `includeSkills`, `excludeSkills` | Required or blocked skills |
| `publishedAfter` | Keep newer jobs |
| `clientCountries` | Public client-location filter |
| `onlyPaymentVerified` | Keep jobs with verified client payment |
| `onlyWithContacts` | Keep jobs with public contact data |
| `sortResultsBy` | Source order, newest, opportunity score or budget |
| `maxResults` | Maximum unique jobs saved across the run |

Filtered and duplicate candidates do not count as saved results.

### Output views

| View | Designed for |
|---|---|
| **Best matches** | Scores, recommendations, freshness, competition and risk |
| **Jobs** | Full descriptions and core job records |
| **Client intelligence** | Spend, hire rate, reviews, payment and company signals |
| **Application intelligence** | Questions, qualifications, requirements and proposal tips |
| **Job activity** | Applicants, invites, interviews, hires and offers |
| **Budgets** | Hourly, fixed, retainer and normalized budget fields |
| **Skills** | Source skills, IDs, detected stack and query matches |
| **Public contacts** | Contacts explicitly published in job text |
| **Errors** | Skipped sources and actionable run issues |
| **Run summary** | Saved, filtered, duplicate and source-request counters |

### Source coverage

Public Upwork job surfaces do not expose the same fields for every posting. Search rows can be lighter than full records, and some job pages restrict client or activity information. Missing values remain `null`; the Actor does not invent budgets, client history, contacts or application statistics.

Use `detailStatus`, `detailSource`, `warnings` and the run summary to distinguish complete, search-only and unavailable fields.

### Export and integrations

Download results as JSON, JSONL, CSV, Excel, XML, RSS or an HTML table. Use the Apify API, webhooks, Make, Zapier, Google Sheets, Airbyte, your CRM, an AI agent or your own application.

Save a configured input as an Apify task when you want to reuse the same search and filters.

### Performance

The production `SEARCH_FULL` workflow was tested with **50 unique jobs on 512 MB**. It completed search, 50 public detail requests, scoring and dataset writes in **11.22 seconds** of total platform time, with 50/50 `public_complete` records and no source retries.

### Cost control

For a small first run:

1. Choose `SEARCH`.
2. Use one query.
3. Set `maxResults` and `resultsPerQuery` to 5.
4. Inspect the fields and filters you need.
5. Switch to `SEARCH_FULL` only when client and application details are useful.

Set **Maximum charge per run** in Apify Console for a hard budget ceiling.

### Frequently asked questions

#### Does the Actor require an Upwork account?

No. Provide keywords, public job URLs or numeric job IDs.

#### Why are some client fields empty?

Upwork publishes different detail levels across jobs. Empty fields mean the value was not available in the selected public source.

#### Can I combine several search phrases?

Yes. Add one phrase per row in `queries`. Duplicate jobs are merged and `matchedQueries` keeps every matching phrase.

#### Can I extract contact details?

Yes, when a client explicitly included them in the public job description. The Actor does not generate or guess contacts.

#### What makes the opportunity score explainable?

It uses published freshness, budget, skills, client signals, applicant competition and explicit risk phrases. The breakdown travels with each row.

#### Can I enrich jobs from another dataset?

Export or map the job URLs/IDs into `startUrls` or `jobIds`, then use `DETAIL`.

***

**Tags:** `upwork scraper` · `upwork jobs` · `freelance jobs` · `client intelligence` · `job leads` · `budget data` · `contact extraction` · `proposal research` · `opportunity scoring`

# Actor input Schema

## `mode` (type: `string`):

Search is fastest. Search + details verifies selected jobs and adds client/activity fields. Direct jobs accepts known URLs or IDs.

## `queries` (type: `array`):

One query per row. Results are merged and duplicates are removed while preserving every matched query.

## `sourceSort` (type: `string`):

Choose whether Upwork should return the newest or most relevant matches first.

## `startUrls` (type: `array`):

Direct jobs mode only. Add public Upwork job URLs. Numeric job IDs can be added below instead.

## `jobIds` (type: `array`):

Direct jobs mode only. Example: 2077479055407476346.

## `maxResults` (type: `integer`):

Global limit after duplicate removal, contact extraction, filters, scoring, and sorting.

## `resultsPerQuery` (type: `integer`):

Maximum source rows collected for each keyword before all queries are merged.

## `jobType` (type: `string`):

Keep all jobs, hourly contracts, or fixed-price projects.

## `experienceLevel` (type: `string`):

Filter by the experience level requested by the client.

## `maxAgeDays` (type: `integer`):

Keep only jobs published within this many days. Use 0 for any age.

## `minBudget` (type: `number`):

Minimum fixed budget or hourly range ceiling.

## `maxBudget` (type: `number`):

Maximum fixed budget or hourly range floor.

## `minHourlyRate` (type: `number`):

Keep hourly jobs whose range reaches at least this value.

## `maxHourlyRate` (type: `number`):

Keep hourly jobs whose range starts at or below this value.

## `includeSkills` (type: `array`):

Every entered value must appear in the job's skill list.

## `excludeKeywords` (type: `array`):

Jobs containing any entered phrase in the title or description are removed.

## `includeContacts` (type: `boolean`):

Save emails, phones, websites, and public messaging handles explicitly included in job text to the Contacts output.

## `onlyWithContacts` (type: `boolean`):

Discard jobs where no public email, phone, website, or messaging handle was found. This automatically enables contact extraction.

## `sortResultsBy` (type: `string`):

Applied after deduplication, enrichment, filters, and scoring.

## `maxConcurrency` (type: `integer`):

Number of independent queries or details processed at once. The default favors reliability.

## `maxRetries` (type: `integer`):

Fresh-session retries for temporary network or source interruptions.

## `requestTimeoutSeconds` (type: `integer`):

Maximum time for one source request.

## `proxyConfiguration` (type: `object`):

Connection settings are preconfigured for reliable Upwork results. The default is ready to run.

## Actor input object example

```json
{
  "mode": "SEARCH",
  "queries": [
    "python developer",
    "web scraping"
  ],
  "sourceSort": "recency",
  "startUrls": [],
  "jobIds": [],
  "maxResults": 20,
  "resultsPerQuery": 20,
  "jobType": "ANY",
  "experienceLevel": "ANY",
  "maxAgeDays": 0,
  "includeSkills": [],
  "excludeKeywords": [],
  "includeContacts": true,
  "onlyWithContacts": false,
  "sortResultsBy": "SOURCE",
  "maxConcurrency": 4,
  "maxRetries": 8,
  "requestTimeoutSeconds": 35,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "CA"
  }
}
```

# Actor output Schema

## `bestMatches` (type: `string`):

No description

## `jobs` (type: `string`):

No description

## `clients` (type: `string`):

No description

## `application` (type: `string`):

No description

## `activity` (type: `string`):

No description

## `budgets` (type: `string`):

No description

## `skills` (type: `string`):

No description

## `contacts` (type: `string`):

No description

## `errors` (type: `string`):

No description

## `runSummary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "queries": [
        "python developer",
        "web scraping"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "CA"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("trakk/upwork-jobs-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "queries": [
        "python developer",
        "web scraping",
    ],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "CA",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("trakk/upwork-jobs-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "queries": [
    "python developer",
    "web scraping"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "CA"
  }
}' |
apify call trakk/upwork-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,trakk/upwork-jobs-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/ZVtM9XLVwACj4eSOq/builds/Dx1bk0RggPSsI49MD/openapi.json
