Freelance Gig Finder
Search Upwork, Contra, We Work Remotely, Freelancer, and Toptal simultaneously for fresh freelance and contract opportunities matching your skill set — filtered to recent postings so you're not looking at stale listings.
Pre-flight Check (REQUIRED)
Before making any TinyFish call, always run BOTH checks:
1. CLI installed?
bashwhich tinyfish && tinyfish --version || echo "TINYFISH_CLI_NOT_INSTALLED"
If not installed, stop and tell the user:
Install the TinyFish CLI:
npm install -g @tiny-fish/cli
2. Authenticated?
bashtinyfish auth status
If not authenticated, stop and tell the user:
You need a TinyFish API key. Get one at: https://agent.tinyfish.ai/api-keys
Then authenticate:
tinyfish auth login
Do NOT proceed until both checks pass.
Step 1 — Gather inputs
You need:
- Skill or role — e.g.
React developer,Python,UI/UX designer,copywriter,DevOps,mobile developer - Budget preference (optional) — e.g.
hourly,fixed price,$50+/hr - Recency (optional) — default to listings posted in the last 7 days
If skill is not provided, ask before proceeding.
Step 2 — Parallel search
Fire all agents simultaneously.
bash# Agent 1 — Upwork tinyfish agent run \ --url "https://www.upwork.com/nx/search/jobs/?sort=recency&q={SKILL_ENCODED}" \ "You are on Upwork job search results for '{SKILL}', sorted by most recent. Extract the first 8 visible job listings. For each listing extract: - title - client description snippet (what they need) - budget (hourly rate range or fixed price if shown) - posted time (e.g. '2 hours ago', 'yesterday') - required skills listed - job type (hourly/fixed) - direct URL to the listing STRICT RULES: - Do NOT click any listing - Read only what is visible in the search result cards - Only include listings posted within the last 7 days - Maximum 8 listings then stop Return JSON array: [{title, description, budget, posted, skills: [], job_type, url}]" \ --sync > /tmp/fg_upwork.json & # Agent 2 — Contra tinyfish agent run \ --url "https://contra.com/opportunities?query={SKILL_ENCODED}&sort=recent" \ "You are on Contra job listings for '{SKILL}', sorted by newest. Extract the first 8 visible job listings. For each listing extract: - title - client/company name - description snippet - budget or rate (if shown) - posted time - required skills - direct URL STRICT RULES: - Do NOT click any listing - Read only what is visible in the listing cards - Maximum 8 listings then stop - If no results found, return {found: false} Return JSON array: [{title, client, description, budget, posted, skills: [], url}]" \ --sync > /tmp/fg_contra.json & # Agent 3 — We Work Remotely tinyfish agent run \ --url "https://weworkremotely.com/remote-jobs/search?term={SKILL_ENCODED}" \ "You are on We Work Remotely job search results for '{SKILL}'. Extract the first 8 visible job listings. For each listing extract: - title - company name - category (e.g. Front-End, Back-End, Design, etc.) - posted date - direct URL to the listing STRICT RULES: - Do NOT click any listing - Read only what is visible in the search results - Maximum 8 listings then stop - If no results, return {found: false} Return JSON array: [{title, company, category, posted, url}]" \ --sync > /tmp/fg_wwr.json & # Agent 4 — Freelancer.com tinyfish agent run \ --url "https://www.freelancer.com/jobs/?keyword={SKILL_ENCODED}" \ "You are on Freelancer.com job listings for '{SKILL}'. Extract the first 8 visible job listings. For each listing extract: - title - budget range (fixed or hourly) - number of bids (if shown) - posted time - required skills listed - direct URL STRICT RULES: - Do NOT click any listing - Read only what is visible in the listing cards - Maximum 8 listings then stop Return JSON array: [{title, budget, bids, posted, skills: [], url}]" \ --sync > /tmp/fg_freelancer.json & # Agent 5 — LinkedIn (contract/freelance filter) tinyfish agent run \ --url "https://www.linkedin.com/jobs/search/?keywords={SKILL_ENCODED}&f_JT=C%2CF&f_WT=2&sortBy=DD" \ "You are on LinkedIn job search results for '{SKILL}' filtered to Contract and Freelance jobs, remote, sorted by most recent. Extract the first 8 visible job listings. For each listing extract: - title - company name - location or remote status - posted time - salary or rate if shown - direct URL STRICT RULES: - Do NOT click any listing - Read only what is visible in the job cards - Maximum 8 listings then stop Return JSON array: [{title, company, location, posted, salary, url}]" \ --sync > /tmp/fg_linkedin.json & wait echo "=== UPWORK ===" && cat /tmp/fg_upwork.json echo "=== CONTRA ===" && cat /tmp/fg_contra.json echo "=== WWR ===" && cat /tmp/fg_wwr.json echo "=== FREELANCER ===" && cat /tmp/fg_freelancer.json echo "=== LINKEDIN ===" && cat /tmp/fg_linkedin.json
Before running, replace:
{SKILL}— e.g.React developer{SKILL_ENCODED}— URL-encoded e.g.React%20developer
Step 3 — Filter and present
From all results, deduplicate any listings that appear on multiple platforms and filter to only show listings posted within the last 7 days. Sort by recency — newest first.
## Freelance Gigs — {SKILL} *Scraped live from Upwork · Contra · We Work Remotely · Freelancer · LinkedIn* *{N} listings found · Posted in the last 7 days · {date}* --- ### 🔥 Fresh Listings #### {Title} **Platform:** {platform} · **Posted:** {posted} **Budget:** {budget or rate} **Skills:** {skills} {description snippet} 🔗 {url} --- #### {Title} [same structure] --- [up to 15 listings total, sorted by most recent] --- ### 📊 Quick Summary | Platform | Listings Found | Avg Budget | |---|---|---| | Upwork | {n} | {avg} | | Contra | {n} | - | | We Work Remotely | {n} | - | | Freelancer | {n} | {avg} | | LinkedIn | {n} | {avg} | --- ### 💡 Tips for These Listings {1-2 sentences of context — e.g. "Upwork has the most volume but high competition. Contra listings tend to be higher quality clients at better rates. LinkedIn contract roles are typically longer engagements."}
Edge Cases
- Upwork requires login to view listings — extract whatever is visible before the gate, note the limitation
- No listings found for skill — try alternative phrasings (e.g. "React" → "React.js", "frontend developer"; "Python" → "Python developer", "Django")
- Very niche skill — We Work Remotely and LinkedIn may have the richest results; Upwork/Freelancer tend to have more volume for common skills
- User wants a specific budget range — add budget filters to Upwork and Freelancer URLs before running
- User is in a specific country — note that Upwork and Freelancer are global but some listings are location-restricted; LinkedIn can be filtered by country
- All platforms return few results — suggest the user check back in a few days or broaden the skill (e.g. "React" instead of "React Native")

