Freelance-market and rate research
Use Upwork endpoints to turn freelance-market and rate research into repeatable API requests with documented inputs and JSON responses.
Turn public Upwork pages into structured freelance-market data — keyword job search, one posting's full detail (budget, client info, proposal count), and freelancer profiles (rate, rating, Job Success Score, feedback), as normalized JSON. Credential-free.
Search Upwork job postings and get job detail and freelancer profiles back as structured JSON.
Endpoint families
3
Documented params
7
Examples
3
Live catalog snapshot
Active endpoints
3
Methods
GET
Required params
6
Schema refs
3
{
"platform": "Upwork",
"endpoint": "upwork-search",
"method": "GET",
"path": "/upwork/search",
"auth": "apiKey"
}Use cases
Search Upwork job postings and get job detail and freelancer profiles back as structured JSON.
Use Upwork endpoints to turn freelance-market and rate research into repeatable API requests with documented inputs and JSON responses.
Use Upwork endpoints to turn job posting aggregation and monitoring into repeatable API requests with documented inputs and JSON responses.
Use Upwork endpoints to turn freelancer sourcing and vetting into repeatable API requests with documented inputs and JSON responses.
Managed execution
Every figure below is read from the live Upwork endpoint catalog — 3 endpoints, 7 documented request parameters, and 3 published response schemas — the same catalog Docs and Playground run against.
3 documented Upwork endpoints, grouped into 3 request families — Freelancer, Job and Search.
7 request parameters are documented across those Upwork endpoints, 6 of them required — the full input contract is public before you write any integration code.
3 of the 3 Upwork endpoints ship a recorded example response, and 3 carry a documented response schema — you can code against the real JSON before the first request.
Upwork endpoints document their error responses (400, 404, 500 and 503) alongside the success schema, so a block, a rate limit, or a missing record comes back as a typed error rather than silently empty data.
3 hosted MCP tools back the Upwork endpoints, so an agent can call the same routes with the same parameters and the same JSON contract, with no custom glue.
Coverage map
These cards are generated from the active endpoint catalog, so the landing page reflects the same API surface used by Docs and Playground.
/upwork/freelancer/{id}
/upwork/job/{id}
/upwork/search
Endpoint catalog
/upwork/searchSearches Upwork's public job listings by free-text keyword, returning normalized job summaries (title, budget, experience level, duration, posted date, description snippet, skill tags). Public data sourced from Upwork's own server-rendered search pages via a real browser-rendering backend.
Response notes
- `id` is Upwork's own opaque job identifier (the digits after `~` in the job's URL) — pass it directly as the `id` path parameter to [`GET /upwork/job/{id}`](upwork-job.md) for full job detail. - `budget_type` is `hourly` or `fixed`, inferred from the search card's own budget label text; it is omitted when the label doesn't match either pattern. - `duration` and `experience_level` are omitted when Upwork doesn't render them for a given posting (e.g. some fixed-price jobs omit duration). - A genuine zero-result search (Upwork's own "There are no results that match your search" page) returns `jobs: []` with a `200`, distinct from a parser-drift or blocked-page failure, which returns an error instead. Example response: ```json { "code": 200, "msg": "OK", "data": { "query": "python developer", "page": 1, "jobs": [ { "id": "2085006288356888767", "title": "Python full stack developer, python automation", "url": "https://www.upwork.com/jobs/span-class-highlight-Python-span-full-stack-developer_~022085006288356888767/", "description": "We are seeking a python full stack developer to join our team...", "posted_at": "Posted 2 days ago", "budget_type": "hourly", "budget_text": "Hourly: $60.00 - $75.00", "experience_level": "Expert", "duration": "1 to 3 months, 30+ hrs/week", "skills": ["Python", "Django", "Flask"] } ] } } ```
MCP tool upwork_search
/upwork/job/{id}Returns a normalized Upwork job posting: title, full description, employment type, budget (hourly range or fixed amount), location/remote type, experience level, duration, project type, proposal count, allowed applicant countries, and a summary of the posting client (member since, location, total spend, hires, hours, industry, company size). Public data sourced from Upwork's own server-rendered job pages via a real browser-rendering backend.
Response notes
- `budget_type` is `hourly` (with `hourly_min`/`hourly_max` populated) or `fixed` (with `fixed_budget` populated), read from the page's schema.org `JobPosting` structured data. - `duration`, `experience_level`, and `project_type` are omitted when Upwork doesn't render them for a given posting. - `client` fields are individually omitted (not "unknown") when Upwork itself doesn't show them for a given client — not every client displays every field (e.g. some hide location or industry). Example response: ```json { "code": 200, "msg": "OK", "data": { "id": "022085006288356888767", "url": "https://www.upwork.com/freelance-jobs/apply/Python-full-stack-developer_~022085006288356888767/", "title": "Python full stack developer, python automation - Contract to Hire", "description": "We are seeking a python full stack developer to join our team...", "posted_at": "2026-08-05T14:13:31.761Z", "employment_type": ["CONTRACTOR", "TEMPORARY"], "location_type": "TELECOMMUTE", "country": "US", "budget_type": "hourly", "currency": "USD", "hourly_min": 60, "hourly_max": 75, "experience_level": "Expert", "duration": "1 to 3 months", "project_type": "Ongoing project", "proposals": "50+", "applicant_countries": ["United States", "Canada"], "client": { "member_since": "Aug 30, 2023", "country": "UKR", "location": "Olexandria, 10:03 AM", "total_spent": "$9K total spent", "hires": "32 hires, 1 active", "total_hours": "207 hours", "industry": "Engineering & Architecture", "company_size": "Small company (2-9 people)" } } } ```
MCP tool upwork_job
/upwork/freelancer/{id}Returns a normalized Upwork freelancer profile: name, title, verification badge, overview, hourly rate, rating and review count, Job Success Score, location and local time, total jobs/hours worked, and recent client feedback (title, comment, date, client name, rating). Public data sourced from Upwork's own server-rendered profile pages via a real browser-rendering backend.
Response notes
- `verified` reflects Upwork's own identity-verification badge on the profile, not payment or account status. - `job_success_score` is Upwork's own Job Success Score percentage (0-100); omitted (`0`) when the profile doesn't display one (e.g. a new freelancer with no completed jobs yet). - `feedback` returns the client reviews visible on the profile's default view — not necessarily the freelancer's full review history. Example response: ```json { "code": 200, "msg": "OK", "data": { "id": "0157e03059a690281f", "url": "https://www.upwork.com/freelancers/~0157e03059a690281f", "name": "Eugene K.", "title": "Python Developer", "verified": true, "overview": "I have 8 years of experience in Python development...", "hourly_rate": "$37.00/hr", "rating": 4.9, "review_count": 67, "job_success_score": 100, "location": "San Diego, CA, USA", "local_time": "12:06 am local time", "total_jobs": 82, "total_hours": 394, "feedback": [ { "title": "Scraping for Tattoo Shops", "comment": "I will hire Eugene again if we need him.", "date": "October 17, 2025", "rating": 5.0 } ] } } ```
MCP tool upwork_freelancer
Related APIs
Business & Market Intelligence
Turn public GitHub ecosystem signals into structured data for developer-market research, open-source intelligence, recruiting, and AI-agent workflows.
Business & Market Intelligence
Collect public TrustMRR startup marketplace and leaderboard data as normalized JSON for startup research, SaaS discovery, and market intelligence workflows.
Business & Market Intelligence
Add website and competitive intelligence signals from SimilarWeb to research pipelines.
How to scrape Upwork
Crawlora's Upwork endpoints return job search, job detail with client history, and freelancer profiles as normalized JSON with one API key. The job detail is the useful part for market research. Beyond the brief, it shows how many proposals a job has drawn (for example 20 to 50) and the client's track record: total spend, number of hires, hours billed, industry, and company size.
/upwork/search takes q and page and returns about 10 jobs per page. Each card has budget_type (hourly or fixed), the raw budget_text such as Hourly: $50.00 - $80.00, experience_level (Entry Level, Intermediate, or Expert), skills, and a relative posted_at such as Posted 2 weeks ago. For web scraping on 2026-09-18, 7 of 10 were hourly.
Pass the search id to /upwork/job/{id}. The detail adds an ISO posted_at, project_type (One-time project), proposals as a band, applicant_countries, and a client block with member_since, total_spent ($7.5K total spent), hires (8 hires, 2 active), total_hours, industry, and company_size. Clients can hide some of these fields, and hidden fields are omitted rather than filled with a placeholder.
Hourly jobs populate hourly_min and hourly_max in detail, and fixed jobs populate fixed_budget. Split on budget_type before averaging rates, because the search card's budget_text only says Fixed price for fixed jobs.
/upwork/freelancer/{id} returns the hourly rate, rating, Job Success Score (0 to 100, or 0 when a new profile shows none), an identity-verified flag, and the client feedback visible on the profile's default view, which is not the full history.
FAQ
Yes. /upwork/job/{id} returns proposals as Upwork's band (for example 20 to 50) together with the client's hire count and spend, which indicates how likely the client is to hire.
Whatever the job page shows: member_since, country and location, total_spent, hires, total_hours, industry, and company_size. Fields a client hides are omitted.
Use /upwork/job/{id}. hourly_min and hourly_max are numeric there, while search cards only carry the budget_text label.