# Upwork Job Monitor (`deepmine/upwork-job-monitor`) Actor

Upwork Job Monitor tracks freelance job listings over time with new-job alerts, closed-job detection, budget trend shifts, and hiring-intent signals by keyword. Export clean Upwork jobs data for lead generation, market research, and automation.

- **URL**: https://apify.com/deepmine/upwork-job-monitor.md
- **Developed by:** [DeepMine](https://apify.com/deepmine) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 4 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$25.00/month + usage

To use this Actor, you pay a monthly rental fee to the developer. The rent is subtracted from your prepaid usage every month after the free trial period. You also pay for the Apify platform usage, which gets cheaper the higher Apify subscription plan you have.

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

## 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 Job Monitor

Upwork Job Monitor is a high-value **Upwork jobs scraper and monitoring actor** built for teams that need more than one-time exports. Instead of only pulling current listings, this actor tracks **what changed between runs** so you can see new freelance jobs, dropped jobs, budget movement, and hiring momentum by keyword.

If you are looking for an **Upwork job monitor**, **Upwork jobs API alternative**, **Upwork lead generation tool**, or **freelance market intelligence workflow**, this actor is designed for exactly that.

### Upwork Job Monitoring, Not Just One-Time Scraping

Most Upwork scraping workflows stop at static data collection. This actor is designed for repeated runs so you can monitor the market over time and answer practical questions like:

- Which Upwork jobs are truly new since my last run?
- Which opportunities disappeared and were likely filled or closed?
- Is budget pressure going up or down in my niche?
- Are new client accounts entering this category?
- Is this niche getting more competitive or cooling off?

That makes this actor useful for **freelancers, agencies, lead gen teams, recruiters, and B2B growth operators** who care about trend direction, not just snapshots.

### Core SEO Use Cases

This actor supports common search intents such as:

- Upwork job monitor
- Upwork jobs scraper
- scrape Upwork jobs by keyword
- Upwork freelance jobs data export
- Upwork lead generation automation
- Upwork job alerts and tracking
- Upwork market research and trend tracking
- Upwork fixed price and hourly job analysis
- Upwork hiring activity monitoring
- Upwork competitive niche analysis

### What This Upwork Actor Tracks

For each query, the actor stores current listings and compares them against prior runs using a persistent monitor state.

#### Run Summary Metrics

Each query includes a summary row with monitoring metrics like:

- `currentActiveJobs`
- `previousActiveJobs`
- `newJobs`
- `closedJobs`
- `unchangedJobs`
- `newClientEntrants`
- `avgBudgetCurrent`
- `avgBudgetPrevious`
- `budgetDelta`
- `budgetDeltaPercent`
- `avgOpenDaysCurrent`

#### Active Job Rows

Current opportunities include fields such as:

- `title`, `url`, `jobId`
- `postedAge`, `jobType`, `experienceLevel`
- `budget`, `hourlyRate`, `budgetSignal`
- `skills`, `description`
- `isNew`, `newClientEntrant`, `ageOpenDays`
- `firstSeenAt`, `lastSeenAt`

#### Closed Job Rows

When enabled, jobs that disappeared since the previous run are emitted as `closed_job` rows with:

- `isClosed`
- `closedAt`
- `ageOpenDays`
- `firstSeenAt`, `lastSeenAt`
- preserved identifiers (`jobId`, `url`, `title`)

This gives you a practical **Upwork lifecycle dataset** rather than a flat export.

### Why Teams Use Upwork Job Monitor

#### 1. Upwork Lead Generation That Improves Over Time

Instead of contacting every listing every run, you can prioritize **new jobs only** and avoid repetitive outreach.

#### 2. Better Upwork Opportunity Prioritization

Use budget deltas, freshness, and client signals to focus on higher-value opportunities first.

#### 3. Faster Niche Validation

Track multiple service categories and compare active volume, entrant activity, and pricing movement.

#### 4. Reliable Weekly or Daily Monitoring

Run on a schedule and build historical visibility into Upwork demand trends.

#### 5. Clean Data for Automation Stacks

Dataset output is structured for Make, n8n, Zapier, Airtable, Google Sheets, CRMs, and internal scoring pipelines.

### Typical Users

- Freelancers building consistent proposal pipelines
- Upwork agencies managing outbound and inbound lead qualification
- Sales development teams targeting service demand signals
- Recruiters and staffing teams tracking contract hiring demand
- Market research operators monitoring niche volatility and pricing

### Input Configuration

#### Required

- `searchQueries` (array)
  - Example:
    - `"javascript developer"`
    - `"python scraping"`
    - `"shopify CRO"`

#### Main Control Inputs

- `maxJobsPerQuery`
- `maxPagesPerQuery`
- `sort` (`recency` or `relevance`)
- `jobType` (`all`, `fixed`, `hourly`)
- `experienceLevel` (`any`, `entry-level`, `intermediate`, `expert`)

#### Monitoring Inputs

- `monitorStateKey` (persistent snapshot key)
- `includeClosedJobs` (emit `closed_job` rows)
- `persistSessionState` (improves consistency over repeated runs)

#### Optional Enrichment

- `scrapeJobDetails` (collect deeper detail-page fields)

### Output Views

The actor includes prebuilt output views so you can inspect monitoring data immediately:

- **Summary** (`view=summary`)
- **Active Jobs** (`view=activeJobs`)
- **Closed Jobs** (`view=closedJobs`)
- Full raw dataset (`results`)

### Example Summary Row

```json
{
  "recordType": "summary",
  "query": "python scraping",
  "runAt": "2026-03-08T18:10:45.000Z",
  "currentActiveJobs": 74,
  "previousActiveJobs": 69,
  "newJobs": 11,
  "closedJobs": 6,
  "unchangedJobs": 63,
  "newClientEntrants": 4,
  "avgBudgetCurrent": 312.5,
  "avgBudgetPrevious": 287.2,
  "budgetDelta": 25.3,
  "budgetDeltaPercent": 8.81,
  "avgOpenDaysCurrent": 9.4
}
```

### Example Active Job Row

```json
{
  "recordType": "active_job",
  "query": "python scraping",
  "isNew": true,
  "newClientEntrant": false,
  "title": "Python scraping expert for ecommerce catalog",
  "url": "https://www.upwork.com/jobs/~2030313017716519876",
  "jobType": "Hourly",
  "hourlyRate": "$35.00 - $55.00",
  "budgetSignal": 45,
  "skills": ["Python", "Web Scraping", "Data Extraction"],
  "firstSeenAt": "2026-03-08T18:10:45.000Z",
  "lastSeenAt": "2026-03-08T18:10:45.000Z",
  "ageOpenDays": 0
}
```

### Example Closed Job Row

```json
{
  "recordType": "closed_job",
  "query": "python scraping",
  "isClosed": true,
  "title": "Scrape product pages and output JSON",
  "url": "https://www.upwork.com/jobs/~2030111111111111111",
  "firstSeenAt": "2026-03-01T12:00:00.000Z",
  "lastSeenAt": "2026-03-07T12:00:00.000Z",
  "closedAt": "2026-03-08T18:10:45.000Z",
  "ageOpenDays": 6
}
```

### How To Run (Apify Console)

1. Open actor input.
2. Add one or more `searchQueries`.
3. Choose `maxJobsPerQuery` and optional filters.
4. Keep `monitorStateKey` stable to track deltas over time.
5. Run actor and review Summary, Active Jobs, and Closed Jobs views.

### How To Run (API)

```bash
curl -X POST "https://api.apify.com/v2/acts/<ACTOR_ID>/runs?token=<APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "searchQueries": ["python scraping", "javascript developer"],
    "maxJobsPerQuery": 100,
    "sort": "recency",
    "jobType": "all",
    "experienceLevel": "any",
    "monitorStateKey": "UPWORK_JOB_MONITOR_STATE",
    "includeClosedJobs": true,
    "scrapeJobDetails": false
  }'
```

### Best Practices For Cleaner Upwork Monitoring Data

- Use focused service-intent queries, not broad single words.
- Keep the same query set across runs for comparable deltas.
- Run on a consistent schedule (for example every 6, 12, or 24 hours).
- Keep one stable `monitorStateKey` per monitoring strategy.
- Enable detail scraping only when deeper enrichment is required.

### FAQ

#### Is this only an Upwork scraper, or a real monitor?

This is a monitoring actor. It compares each run with prior snapshots and outputs change metrics.

#### Can I monitor multiple niches in one run?

Yes. Add multiple `searchQueries` and get separate summary and job rows per query.

#### Can I use this for Upwork lead generation?

Yes. Many users use `isNew`, `ageOpenDays`, budget fields, and skills to prioritize outreach.

#### Can I build dashboards from this output?

Yes. The dataset structure is designed for BI, Sheets, Airtable, and automation pipelines.

### Positioning

Upwork Job Monitor is built for users who need **repeatable Upwork market tracking**, **clean delta signals**, and **automation-ready freelance jobs data** instead of fragile manual exports.

If your goal is reliable Upwork job alerts, hiring trend visibility, and better lead prioritization, this actor is purpose-built for that workflow.

# Actor input Schema

## `searchQueries` (type: `array`):

Keywords or niches to monitor on Upwork. Each run compares with the previous snapshot for each query.

## `maxJobsPerQuery` (type: `integer`):

Maximum active jobs to track per query on each run.

## `maxPagesPerQuery` (type: `integer`):

Optional hard limit for pagination depth per query. Leave empty for no page cap.

## `sort` (type: `string`):

Sort search results by recency or relevance.

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

Filter by fixed-price or hourly jobs, or return all.

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

Filter by required experience level.

## `enforceQueryRelevance` (type: `boolean`):

Apply stricter token-level filtering so each returned job matches all query keywords (recommended for stable, precise results).

## `scrapeJobDetails` (type: `boolean`):

Visit each job's individual page to collect full description, proposal activity, client history, and location restrictions. Slower but more complete — roughly doubles run time.

## `stealthMode` (type: `boolean`):

Enable anti-detection browser hardening and challenge-resilient navigation behavior.

## `enableHumanCursor` (type: `boolean`):

Enable human-like cursor movement for checkbox-based verification challenges.

## `humanizeMaxTimeSec` (type: `number`):

Maximum cursor movement duration in seconds for humanized pointer movement.

## `disableCoop` (type: `boolean`):

Disables Cross-Origin-Opener-Policy handling to allow cross-origin iframe interaction. Keep OFF unless needed for specific challenge pages.

## `stopAfterFirstBlockedQuery` (type: `boolean`):

If the first query is fully challenge-blocked and returns zero jobs, stop the run early to reduce usage. Turn off to continue remaining queries.

## `navigationRetries` (type: `integer`):

How many times to rotate session and retry when challenge or navigation failures happen.

## `navigationTimeoutSeconds` (type: `integer`):

Timeout for a single page navigation attempt.

## `challengeWaitSeconds` (type: `integer`):

How long to keep waiting on anti-bot challenge pages before rotating session.

## `queryTimeCapSeconds` (type: `integer`):

Maximum total time spent per query before returning partial results.

## `persistSessionState` (type: `boolean`):

Reuse cookies/storage across runs for a sticky Upwork session cohort and better result consistency.

## `monitorStateKey` (type: `string`):

Key-value store key used to persist previous run snapshots for delta tracking.

## `includeClosedJobs` (type: `boolean`):

Include jobs that disappeared since the previous run as `closed_job` rows.

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

Residential proxies are recommended — Upwork blocks datacenter IPs.

## `proxySessionId` (type: `string`):

Set a fixed proxy session ID to improve run-to-run consistency by reusing the same proxy cohort.

## Actor input object example

```json
{
  "searchQueries": [
    "javascript developer",
    "python scraping"
  ],
  "maxJobsPerQuery": 50,
  "sort": "recency",
  "jobType": "all",
  "experienceLevel": "any",
  "enforceQueryRelevance": true,
  "scrapeJobDetails": false,
  "stealthMode": true,
  "enableHumanCursor": true,
  "humanizeMaxTimeSec": 1.5,
  "disableCoop": false,
  "stopAfterFirstBlockedQuery": false,
  "navigationRetries": 3,
  "navigationTimeoutSeconds": 35,
  "challengeWaitSeconds": 25,
  "queryTimeCapSeconds": 180,
  "persistSessionState": true,
  "monitorStateKey": "UPWORK_JOB_MONITOR_STATE",
  "includeClosedJobs": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "proxySessionId": "upwork-stable"
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `summary` (type: `string`):

No description

## `activeJobs` (type: `string`):

No description

## `closedJobs` (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 = {
    "searchQueries": [
        "javascript developer",
        "python scraping"
    ],
    "proxySessionId": "upwork-stable"
};

// Run the Actor and wait for it to finish
const run = await client.actor("deepmine/upwork-job-monitor").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 = {
    "searchQueries": [
        "javascript developer",
        "python scraping",
    ],
    "proxySessionId": "upwork-stable",
}

# Run the Actor and wait for it to finish
run = client.actor("deepmine/upwork-job-monitor").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 '{
  "searchQueries": [
    "javascript developer",
    "python scraping"
  ],
  "proxySessionId": "upwork-stable"
}' |
apify call deepmine/upwork-job-monitor --silent --output-dataset

```

## MCP server setup

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

```

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/0N6Ao9PCmbzeYCqBp/builds/bkRYMGy1FFJWtZtW6/openapi.json
