# Upspy - Upwork Jobs Scraper (`ahsansubhani/upspy-apify-actor`) Actor

Upwork jobs scraper — export recent Upwork jobs as clean structured data: full job details, screening questions, budgets, skills, and complete client history (spend, hires, hire rate, rating, payment verification) on every posting. By Upspy.

- **URL**: https://apify.com/ahsansubhani/upspy-apify-actor.md
- **Developed by:** [Ahsan](https://apify.com/ahsansubhani) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Upspy - Upwork Jobs Scraper

**The Upwork jobs scraper that exports recent postings as clean, structured
data** — full job details, screening questions, and the client's complete
history on every job. Filter by keywords, budget, and client quality, and get
back a tidy dataset ready for spreadsheets, analysis, lead generation, or your
own pipeline.

No browser automation against Upwork, no login, no ToS roulette: this actor
reads from **[Upspy](https://upspy.ai)**'s continuously-updated feed of the
Upwork posting stream, so runs are fast and don't get blocked.

***

### What it scrapes, on every job

- **Job details** — title, full description, URL, posting time, job type
  (hourly/fixed), budget & rate range, contract type, duration, experience
  level, connects required
- **Classification** — skills/tags, category and sub-category
- **Screening questions** — the exact questions the client asks applicants
- **Client history** — country, payment-verified status, total spent, jobs
  posted, hires, hire rate, rating, review count, average hourly paid, and
  Upwork's client rank

### What you get per job

```json
{
  "title": "Automate invoice processing with Python",
  "url": "https://www.upwork.com/jobs/...",
  "job_type": "hourly",
  "budget": "$25–$45/hr",
  "budget_amounts": { "min": 25, "max": 45, "currency": "USD" },
  "skills": ["python", "automation"],
  "category": "Web, Mobile & Software Dev",
  "questions": ["Describe a similar project you've delivered."],
  "posted_at": "2026-08-30T14:02:11Z",
  "client_rank": { "score": 82, "label": "Excellent" },
  "client_country": "United States",
  "client_payment_verified": true,
  "client_spend": 42000,
  "client_jobs_posted": 20,
  "client_hires": 14,
  "client_hire_rate": 78,
  "client_rating": 4.9,
  "client_review_count": 23,
  "source": "upspy.ai"
}
```

**Full job + client record** — every fact we have, not a summary. **Honest
nulls**: every item has the same fields; anything the posting did not declare
is `null`, never guessed.

### Setup — none

Just run it. No account, no key, no card on our side — the actor is
pre-configured, and you pay Apify only for what you use.

*Advanced (optional):* paste your own Upspy API key
(**app.upspy.ai → Settings → Developer**) into the input to run against your
own Upspy account instead of the built-in one.

### Inputs

Every input is optional — an untouched control adds no constraint. These are
the same filters the Upspy app offers, run through the same matcher.

**Keywords** — three independent fields, ORed together (a job matches if *any*
field with terms in it matches). Within a field, pick Any (OR) or All (AND).

| Input | What it does |
|---|---|
| Title keywords | Words to find in the job title |
| Description keywords | Words to find in the description |
| Skill keywords | Words to find in the skills |
| Categories | Upwork categories/specialties, e.g. `Web Development` |

**Job terms**

| Input | What it does |
|---|---|
| How the job pays | Any · Hourly · Fixed-price · Budget not stated |
| Min / Max hourly rate | Bounds hourly jobs only |
| Min / Max fixed budget | Bounds fixed-price jobs only |
| Hide jobs with no budget | Drop postings that state no budget |
| Payment-verified clients only | Client has completed billing setup |

**Recency**

| Input | What it does |
|---|---|
| Posted within + Unit | 1–24, in **hours or minutes** — e.g. last 24 hours, last hour, last 5 minutes |

**Job qualifications**

| Input | What it does |
|---|---|
| Experience level | Entry level · Intermediate · Expert |
| Project length | e.g. `1 to 3 months` |
| Contract type | Ongoing project · One-time project |
| Max connects to apply | Drop jobs that cost more connects to bid |
| Max effort (hours) | Drop jobs Upspy estimates take longer |

**Client quality**

| Input | What it does |
|---|---|
| Min client rank (0–5) | Upwork's own client-quality score |
| Min client spend / hires / reviews | Client track-record floors |
| Min client rating (0–5) | Average star rating |
| Min client avg paid ($/hr) | What the client usually pays |
| Min client hire rate (%) | Share of postings that end in a hire |
| Include clients with no track record | Off drops brand-new clients |
| Client countries to keep / drop | Filter by client location |
| US-only / UK-only jobs | Include · Exclude · Only |

**Screening questions** — Any · Only jobs that ask · Only jobs that don't.

**Output** — Max jobs caps the run.

**Advanced** — Upspy API key (optional; blank uses the built-in key, no account
needed).

### What people use it for

- **Lead generation** — pull payment-verified clients hiring for your skill,
  with spend and hire-rate already attached, straight into a CRM or sheet.
- **Market research** — track rates, demand and skills over time by category
  or keyword.
- **Freelancer & agency prospecting** — a fresh, filtered list of live jobs
  worth bidding on, without refreshing Upwork all day.
- **Dashboards & data pipelines** — a stable JSON feed to wire into Zapier,
  Make, Google Sheets, or your own database via the Apify API.

### Pricing

**$2.50 per 1,000 results.** You pay per job returned — no monthly
subscription, no charge for runs that match nothing. Cap any run with **Max
jobs**.

### FAQ

**Does this log into Upwork or scrape their site directly?**
No. It reads Upspy's own feed of the Upwork posting stream, so there's no
login, no CAPTCHA, and no risk of your run being blocked.

**Do I need an Upwork or Upspy account?**
No. The actor is pre-configured and works out of the box. An Upspy key is an
optional advanced input only.

**How fresh are the jobs?**
Recent by design — choose how far back to look with **Posted within (hours)**,
up to 45 days.

**Why are some fields `null`?**
Because the client didn't state them on the posting. We never guess; a missing
value stays `null` so your data stays honest.

**Can I get jobs the moment they post instead of pulling them?**
Yes — that's the Upspy product itself (see below).

### Scraper vs. alerts

This actor **pulls** recent jobs — ideal for datasets, analysis, spreadsheets
and pipelines. If you want jobs **pushed to you the moment they post** —
WhatsApp, Slack, or your own webhook, while the proposal window is still
open — that is the Upspy product itself: **[start free](https://app.upspy.ai)**.

Reading on the strategy side: [why being first matters](https://upspy.ai/blog/why-being-first-on-upwork-matters) ·
[reading client history in 30 seconds](https://upspy.ai/blog/how-to-read-upwork-client-history) ·
[client red flags](https://upspy.ai/blog/upwork-client-red-flags)

***

Built by the team behind [Upspy](https://upspy.ai). Upspy is an independent
tool, not affiliated with or endorsed by Upwork.

# Actor input Schema

## `titleKeywords` (type: `array`):

Words to look for in the job title. Add one term per row (e.g. shopify, then dropshipping). The match setting below decides whether one term is enough or all are required.

## `titleMatch` (type: `string`):

How the title terms combine. Any of them (OR): keep the job if the title contains at least one term. All of them (AND): require every term to appear.

## `descriptionKeywords` (type: `array`):

Words to look for in the full job description. One term per row (e.g. automation, api integration). Useful for catching detail the title leaves out.

## `descriptionMatch` (type: `string`):

How the description terms combine. Any of them (OR): at least one term. All of them (AND): every term.

## `skillKeywords` (type: `array`):

Words to look for in the job's listed skills/tags. One term per row (e.g. python, postgresql). Often the cleanest way to match a technology.

## `skillMatch` (type: `string`):

How the skill terms combine. Any of them (OR): at least one skill. All of them (AND): every skill.

## `categories` (type: `array`):

Keep only jobs in these Upwork categories or specialties. Matched at either level, so a broad group (Design & Creative) or a single specialty (Web Development) both work. One per row.

## `budgetType` (type: `string`):

Keep only jobs of this pay type. "Budget not stated" keeps jobs that declare neither an hourly rate nor a fixed budget.

## `minHourly` (type: `integer`):

Keep hourly jobs advertising at least this rate. Fixed-price jobs are never affected by this. Example: 25 keeps $25/hr and up.

## `maxHourly` (type: `integer`):

Keep hourly jobs advertising no more than this rate. Leave empty for no ceiling.

## `minFixed` (type: `integer`):

Keep fixed-price jobs with a budget of at least this amount. Hourly jobs are never affected. Example: 500.

## `maxFixed` (type: `integer`):

Keep fixed-price jobs with a budget of no more than this amount. Leave empty for no ceiling.

## `hideNoBudget` (type: `boolean`):

Drop jobs that state no budget at all. Off (default) keeps them — many good jobs simply don't post a number.

## `paymentVerifiedOnly` (type: `boolean`):

Keep only jobs whose client has a verified billing method — a strong signal the client can actually pay. On by default.

## `postedWithinValue` (type: `integer`):

How far back to look, in the unit set by the toggle below. Range 1–24. Examples: 24 with the toggle off = the last 24 hours; 5 with the toggle on = the last 5 minutes.

## `postedWithinInMinutes` (type: `boolean`):

Off: the number above counts hours. On: it counts minutes — for catching jobs posted in the last few minutes.

## `experienceLevels` (type: `array`):

Keep only jobs at these experience levels. Pick one or more.

## `projectLengths` (type: `array`):

Keep only jobs of these expected durations. Pick one or more.

## `contractTypes` (type: `array`):

Keep only these engagement types. Pick one or both.

## `clientRankMin` (type: `integer`):

Upwork's own overall client-quality score, 0 to 5 (5 = Excellent). Example: 4 keeps well-rated clients.

## `clientSpendMin` (type: `integer`):

Minimum total the client has ever spent on Upwork, in USD — a proxy for how established they are. Example: 1000.

## `clientHiresMin` (type: `integer`):

Minimum number of freelancers the client has hired before. 0 means they may never have hired anyone.

## `clientRatingMin` (type: `integer`):

Minimum average star rating the client has received from freelancers. Whole numbers only (0–5).

## `clientReviewsMin` (type: `integer`):

Minimum number of reviews the client has received. More reviews means a longer, more reliable track record.

## `clientAvgRateMin` (type: `integer`):

Minimum average hourly rate the client has actually paid in the past, in USD — a signal of budget. Example: 20.

## `clientHireRateMin` (type: `integer`):

Minimum share of the client's postings that ended in a hire, as a percentage. A low hire rate can mean a client who posts but rarely hires. Example: 50.

## `includeNoTrackRecord` (type: `boolean`):

Whether to keep clients with no history at all — spent nothing, hired no one, and no reviews. On by default; turn off to focus only on proven clients.

## `clientLocations` (type: `array`):

Keep only clients located in these countries. Use full country names, one per row (e.g. United States, United Kingdom).

## `avoidClientLocations` (type: `array`):

Drop clients located in these countries. Full country names, one per row.

## `usJobs` (type: `string`):

Jobs Upwork restricts to US-based freelancers. Include (default) keeps them alongside everything else; Exclude drops them; Only returns just these.

## `ukJobs` (type: `string`):

Jobs Upwork restricts to UK-based freelancers. Same three options as US-only jobs.

## `screeningQuestions` (type: `string`):

Any: don't filter on this. "Only jobs that ask": keep postings that include screening questions. "Only jobs that don't": keep postings without any.

## `maxJobs` (type: `integer`):

Stop the run after this many jobs. Because you pay per result, this is also your cost ceiling for the run. Example: 500.

## `upspyApiKey` (type: `string`):

Optional and rarely needed. Blank uses the built-in key, so no account is required. Advanced users with an Upspy account can set their own key (app.upspy.ai → Settings → Developer) via the JSON input to run against their account.

## Actor input object example

```json
{
  "titleKeywords": [],
  "titleMatch": "OR",
  "descriptionKeywords": [],
  "descriptionMatch": "OR",
  "skillKeywords": [],
  "skillMatch": "OR",
  "categories": [],
  "budgetType": "any",
  "hideNoBudget": false,
  "paymentVerifiedOnly": true,
  "postedWithinValue": 24,
  "postedWithinInMinutes": false,
  "includeNoTrackRecord": true,
  "clientLocations": [],
  "avoidClientLocations": [],
  "usJobs": "include",
  "ukJobs": "include",
  "screeningQuestions": "any",
  "maxJobs": 500
}
```

# Actor output Schema

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

Every scraped job posting, as a row in the default dataset.

# 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 = {
    "titleKeywords": [],
    "descriptionKeywords": [],
    "skillKeywords": [],
    "categories": [],
    "clientLocations": [],
    "avoidClientLocations": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("ahsansubhani/upspy-apify-actor").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 = {
    "titleKeywords": [],
    "descriptionKeywords": [],
    "skillKeywords": [],
    "categories": [],
    "clientLocations": [],
    "avoidClientLocations": [],
}

# Run the Actor and wait for it to finish
run = client.actor("ahsansubhani/upspy-apify-actor").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 '{
  "titleKeywords": [],
  "descriptionKeywords": [],
  "skillKeywords": [],
  "categories": [],
  "clientLocations": [],
  "avoidClientLocations": []
}' |
apify call ahsansubhani/upspy-apify-actor --silent --output-dataset

```

## MCP server setup

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

```

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/la5kXgbHrYQM6aGVt/builds/nSbeO7CRgl7xG8Ewm/openapi.json
