
TikTok Shop Scraper
scrape.ly/store/shelfbright/tiktok-shop-scraperE-commerceSocial media
1 monthly user

Scrape public Upwork job search results: titles, descriptions, budgets, skills, and client stats. No account login.
Save public Upwork job posts into a clean dataset: title, description, budget or hourly range, skills, experience level, and the client stats shown on the job. Search by keyword or paste an Upwork search URL, filter by budget, experience, and client history, and export to JSON, CSV, or Excel. No Upwork login needed.
web scraping), or paste an Upwork search URL in rawUrl.| Field | Type | What it does |
|---|---|---|
query | string | Keywords, as you would type them into Upwork search. |
rawUrl | string | An upwork.com/nx/search/jobs URL. Replaces the keyword and filters. |
maxResults | integer | Jobs to save. Default 10. |
experienceLevel | array | entry, intermediate, expert. Empty means every level. |
jobType | array | hourly, fixed. Empty means both. |
paymentVerified | select | any, verified, or unverified. |
minHourlyRate, maxHourlyRate | number | Hourly range in USD. |
minFixedPrice, maxFixedPrice | number | Fixed-price range in USD. |
clientHistory | array | noHires, 1to9Hires, 10+Hires. |
location | array | Countries or regions as Upwork writes them, such as United States. |
sort | select | newest or relevance. |
page | integer | Start page. Default 1. |
maxJobAge | object | Drop older jobs, for example {"value": 24, "unit": "hours"}. |
customFilters | array | Rules on saved fields. Operators: includes, notIncludes, equals, notEquals. |
proxyConfiguration | object | Datacenter proxy by default. |
{
"query": "web scraping",
"maxResults": 10,
"sort": "newest",
"paymentVerified": "verified",
"maxJobAge": { "value": 24, "unit": "hours" }
}
includes matches a substring, or any value in a list. equals matches the whole value, including null.
One dataset row per job.
| Field | Description |
|---|---|
id, subId, url | Upwork job ids and the link to the job. |
title, description | Job title and description. |
budget | Fixed budget or hourly range text. |
jobType, experienceLevel | Fixed or Hourly, and the experience level. |
relativeDate, absoluteDate | When the job was posted. |
tags | Skills attached to the job. |
clientLocation, clientRating, clientTotalSpent | Client signals, when shown. |
paymentVerified | Payment verification, or unknown when not shown. |
proposals, clientName, questions | Present as keys but usually empty, see Limits. |
{
"id": "2110149616222361215",
"subId": "~022110149616222361215",
"title": "County Data Scraping to Excel",
"description": "Need a freelancer to scrape county-level data from public website and organize the info...",
"url": "https://www.upwork.com/jobs/County-Data-Scraping-to-Excel_~022110149616222361215/",
"budget": "$50.00",
"relativeDate": "Posted 29 minutes ago",
"absoluteDate": "2026-10-13T23:24:37.836000Z",
"jobType": "Fixed",
"experienceLevel": "Intermediate",
"clientLocation": "Worldwide",
"paymentVerified": "unknown",
"clientRating": 4.9,
"clientTotalSpent": 15000,
"tags": ["Data Scraping", "Web Crawling"]
}
The example is trimmed: the description and URL are shortened, and empty keys are left out.
$0.0001 per job saved, which is $0.10 per 1,000 jobs, plus platform usage. Upwork puts public search behind a challenge, so every run opens a short browser session, and that browser usage is the main cost of a run.
Worked example: a 10-job run measured about $0.07 in total (the job fee of $0.001 plus platform usage, mostly browser time). Larger runs spread the browser session over more jobs.
Is it legal to scrape Upwork? The actor reads public job search pages without logging in. You are responsible for how you use the data and for following local law and Upwork's terms.
Do I need an Upwork login or my own proxy? No. A proxy is configured by default.
How many jobs can I get?
As many as the search returns. The run pages through the results until it reaches maxResults or the last page.
Why are some fields empty? Client name, proposal counts, screening questions, and hire rate are not shown on the public job and stay empty. Client rating and spend appear only when they are on the page.
What happens with a bad URL? A URL that is not an Upwork job search fails the run with an explanation. A search that matches nothing finishes with an empty dataset.
Can I schedule it or use the API? Yes, through schedules in the console or the API.
Every field below can be set in the run form, passed through the API, or saved as a task. Unset fields fall back to the defaults shown.
querystringOptionalSearch query
Keywords, as you would type them into Upwork job search. Ignored when a search URL is set.
rawUrlstringOptionalSearch URL
An Upwork job search URL (upwork.com/nx/search/jobs). When set, it replaces the keyword and the filters below.
maxResultsintegerOptionaldefault 10Maximum jobs
How many jobs to save. The run stops at this number.
Narrow the search. A search URL replaces these fields.
experienceLevelarrayOptionalExperience level
Leave empty for every level.
jobTypearrayOptionalJob type
Leave empty for hourly and fixed-price jobs.
paymentVerifiedenumOptionaldefault "any"Payment verified
Keep every client, or only clients with verified or unverified payment.
minHourlyRatenumberOptionalMinimum hourly rate
USD per hour. Applied to hourly jobs.
maxHourlyRatenumberOptionalMaximum hourly rate
USD per hour. Applied to hourly jobs.
minFixedPricenumberOptionalMinimum fixed price
USD. Applied to fixed-price jobs.
maxFixedPricenumberOptionalMaximum fixed price
USD. Applied to fixed-price jobs.
clientHistoryarrayOptionalClient hires
How many people the client has hired before.
locationarrayOptionalClient location
Countries or regions, written the way Upwork shows them. Example: United States.
sortenumOptionaldefault "newest"Sort
Newest posts first, or Upwork's relevance order.
pageintegerOptionaldefault 1Start page
Page to start from. Page 1 is the first page.
maxJobAgeobjectOptionalMaximum job age
Drop jobs older than this. Example: {"value": 24, "unit": "hours"}. Units: minutes, hours, days, weeks.
customFiltersarrayOptionalCustom filters
Extra rules on the saved job. Operators: includes, notIncludes, equals, notEquals. includes and notIncludes accept a string or a list.
proxyConfigurationobjectOptionaldefault {"useScrapelyProxy":true,"scrapelyProxyGroups":["DATACENTER…Proxy configuration
Datacenter proxy is the default. Switch the group if Upwork blocks that pool.
Every run writes its results to a dataset. Preview it in the dashboard, then export it or read it through the API.
| Field | Type | Description |
|---|---|---|
| id | string | null | Upwork job id |
| subId | string | null | Job ciphertext from the URL |
| title | string | null | Job title |
| description | string | null | Job description |
| url | string | null | Job posting URL |
| budget | string | null | Fixed price, or the hourly range |
| relativeDate | string | null | How long ago the job was posted |
| absoluteDate | string | null | Posting time in UTC |
| jobType | string | null | Fixed or Hourly |
| experienceLevel | string | null | Entry, Intermediate, or Expert |
| clientLocation | string | null | Client country |
| paymentVerified | boolean | string | null | Whether the client payment method is verified |
| allowedApplicantCountries | array | null | Countries allowed to apply, when the job restricts them |
| clientName | string | null | Not available on the public search card |
| clientNameConfidence | number | null | Not available on the public search card |
| clientAvgHourlyRate | number | null | Client average hourly rate in USD, when hours and spend are both public |
| clientRating | number | null | Client feedback score from 0 to 5 |
| clientHireRatePercent | number | null | Hires divided by posted jobs, as a percent |
| clientTotalSpent | number | null | Total the client has spent, in USD |
| hasHired | boolean | null | Whether this job already shows a hire |
| proposals | number | null | Applicants, when the search result includes a count |
| questions | array | null | Screening questions, when the search result includes them |
| tags | array | null | Skills on the job |
You pay for the events the actor reports, such as each result or page it produces. Platform usage is included in the event prices.
| Event | Charged when | Price |
|---|---|---|
| Job | One public Upwork job saved to the dataset. | $0.0001 |
Run this actor from your own code. Swap in your API token and the examples work as-is.
import { ScrapelyClient } from 'scrapely-client'
const client = new ScrapelyClient({ token: process.env.SCRAPELY_TOKEN })
// Start the actor and wait for the run to finish.
const run = await client.actor('openrole/upwork-job-scraper').call({
"query": "web scraping",
"rawUrl": "https://www.upwork.com/nx/search/jobs/?q=react%20developer&sort=recency",
"maxResults": 10,
"minHourlyRate": 20,
"maxHourlyRate": 50,
"minFixedPrice": 100,
"maxFixedPrice": 1000,
"location": [
"United States"
],
"maxJobAge": {
"value": 24,
"unit": "hours"
},
"customFilters": [],
"proxyConfiguration": {
"useScrapelyProxy": true,
"scrapelyProxyGroups": [
"DATACENTER"
]
}
})
// Read the dataset the run produced.
const { items } = await client.dataset(run.defaultDatasetId).listItems()
console.log(items)Tokens live in your account settings. Keep them server-side: a token carries the full permissions of your account.
Connect the Scrape.ly MCP server once and your agent can run this actor as a tool. Pick your tool:
Fetch scrape.ly/agents.md and run openrole/upwork-job-scraperPaste into Claude Code, Codex, Cursor or any AI agent. It signs you in once in the browser.
{
"mcpServers": {
"scrapely": {
"url": "https://api.scrape.ly/mcp?tools=actors,runs,storage,docs&actors=openrole/upwork-job-scraper"
}
}
}No key in the file: your client opens the browser to sign you in the first time it connects.
Inputs the developer prepared for common jobs. Open one to see its input, then copy it to your account to run it as-is or adjust it.
Newest Upwork jobs for a search term.
Only jobs from clients with verified payment.
Jobs from a pasted Upwork search URL.
Scrape.ly gives you the infrastructure, the tooling, and the team to extract, process, and operationalize web data at any scale. Setup takes minutes. The advantage lasts forever.