# Freelance Lead Radar — No-Noise Job Leads with ROI Score (`contributory_garnet_hyz/freelance-lead-radar`) Actor

Scans GitHub bounties, Hacker News contract threads and Freelancer.com, drops the noise (for-hire posts, $5 bounties, bait repos, duplicates), estimates effort in hours, and ranks every lead by USD per hour. Get a short list worth quoting on.

- **URL**: https://apify.com/contributory_garnet_hyz/freelance-lead-radar.md
- **Developed by:** [Radar Labs](https://apify.com/contributory_garnet_hyz) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $15.00 / 1,000 leads

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Freelance Lead Radar

**One feed. No noise. Sorted by how much money you make per hour.**

Most freelance-job scrapers give you what the platforms give them: hundreds of listings, a third of which are people *looking* for work, a third of which have no budget, and a long tail of ₹200 data-entry gigs. You still spend 40 minutes a day triaging.

This Actor does the triage for you:

1. **Aggregates** five independent sources — GitHub bounty issues, Hacker News contract posts, Freelancer.com projects, YesWeHack public bug-bounty programs, and Remotive remote jobs.
2. **Removes the noise** — `[FOR HIRE]` posts, "seeking work" comments, listings with no stated budget, sub-$20 gigs, equity-only "co-founder" ads, and bounty-farm repos where forks outnumber stars 3:1 (the classic pattern of a repo that manufactures fake $8k bounties for engagement).
3. **Scores every survivor 0–100** on money, effort, fit, freshness, and competition, then reports **USD/hour** so you can pick by return rather than by headline number.

You pay **per lead that survives the filter**. Noise we removed is not billed.

***

### What you get

One dataset row per lead:

| Field | Meaning |
| --- | --- |
| `title` | The lead headline |
| `url` | Direct link to the issue / comment / project |
| `source` | `github` · `hn` · `freelancer` · `yeswehack` · `remote` |
| `kind` | `bounty` (fixed-price task) · `gig` (contract) · `job` (salaried) |
| `org` | Repo (`owner/name`), company, or posting author |
| `payoutUsd` | Budget converted to USD |
| `effortHours` | Estimated hours to deliver |
| `roiUsdPerHour` | `payoutUsd / effortHours` |
| `valueScore` | 0–100 composite |
| `postedAt` | ISO timestamp |
| `bidCount` | Competing bids already placed (Freelancer.com only) |
| `labels` | Repo labels or required skills |
| `summary` | First ~300 chars of the description |

A `SUMMARY` key-value record reports how many items were scraped, how many survived de-noising, and which sources failed — so a partial run is visible rather than silent.

***

### Why the noise filter matters

Run against live data at the time of writing, one default run pulled **101 raw items and delivered 85 usable leads** — 16 were rejected as noise, before de-duplication removed several more. Across a week of runs the rejected share is typically 20–30%, and it is dominated by three things:

- **Bounty farms.** A repo with 14 stars and 200 forks posting `[Bounty $8k]` titles is not paying $8k. Real bounty repos have more stars than forks.
- **Job-seeker posts.** The monthly HN freelancer thread is roughly half people advertising themselves, not hiring.
- **Unpriced listings.** A gig with no number is usually a "how much would you charge?" fishing expedition.

Filtering these is the entire product. Everything else is plumbing.

***

### Input

| Field | Default | Notes |
| --- | --- | --- |
| `sources` | `["github","hn","freelancer","yeswehack"]` | Add `remote` for salaried roles |
| `maxLeads` | `25` | Each returned lead is one billed event |
| `minScore` | `0` | Raise to ~50 for a high-precision feed |
| `minPayoutUsd` | `0` | Hard floor on money |
| `perSource` | `max(maxLeads*2, 30)` | Raw items pulled per source before filtering |

#### Example: high-precision, high-payout only

```json
{
  "sources": ["github", "freelancer"],
  "maxLeads": 10,
  "minScore": 55,
  "minPayoutUsd": 300
}
```

#### Example: broad daily sweep

```json
{
  "sources": ["github", "hn", "freelancer", "yeswehack", "remote"],
  "maxLeads": 50,
  "minScore": 0
}
```

***

### Pricing

**Pay per event — you pay for results, not for noise.**

| Event | Price | Charged when |
| --- | ---: | --- |
| `lead-returned` | **$0.015** | once for each lead written to the dataset |
| `apify-actor-start` | **$0.005** | once per run (one event per GB of memory, minimum one) |

With the default `maxLeads: 25`, a run costs roughly **$0.38**. Ask for 5 leads and it's about **$0.08**.

Why this model:

- A run that finds nothing costs only the start event.
- **Filtered-out noise is never billed.** You pay for leads that survived, not for what we threw away.
- `maxLeads` caps your maximum spend per run, so cost is predictable.

Apify bills platform usage separately (compute, proxy, storage); this Actor uses no proxies, no browser and no SERP calls, so that part stays in the sub-cent range.

***

### Scheduling

Set a daily schedule (08:00 local) and point a notification at the run. The feed is meant to be read once a day over coffee, not monitored.

***

### Limits and honest caveats

- **Freelancer.com is rate-limited.** Requests are spaced out; a run takes roughly 60–120 seconds. This is why the Actor is not instant.
- **GitHub's `label:bounty` signal is polluted.** That is precisely why the repo-health check exists. Without it, roughly 95% of that label's newest issues come from a single farm repo.
- **`effortHours` is a keyword heuristic**, not an LLM estimate. It is directionally right (a typo fix is 0.5h, a mobile app is 60h) and deliberately conservative on unknowns (6h default).
- **Unpriced listings are ranked low on purpose.** A post that never states a number scores 55% lower than an identical priced one, because "how much would you charge?" leads are the single biggest time sink. If you want them anyway, they are still in the dataset — just further down.
- **Amounts in prose are read conservatively.** A GitHub issue whose body says "€230,000 across 214 programs" is a summary, not a €230,000 bounty, so it is not scored as one. Amounts must sit next to a word like *bounty*, *reward*, or *budget* and must not be part of a total/average statement.
- **Bug-bounty programs are ranges, not prices.** YesWeHack publishes `min`/`max` rewards per program, and taking the ceiling would fake a top result (one program's €100–230,000 range would score as $248,400). We take the geometric mean of the range, or `max/10` when only a ceiling exists, and keep the raw range in `summary`. Effort is pinned at 24h because scope is open-ended — you may hunt for three days, or land it in the first hour.
- **No bidding, no applying.** This Actor only finds and ranks. Submitting proposals is against the terms of every platform it reads from, and automating it gets accounts banned. You still click submit.
- **Payout parsing prefers the first amount in the text.** A post that mentions "$500 budget, previously paid $50k" yields $500. Prefer the `summary` field when a number looks wrong.

***

### Sources and their terms

All five are public read-only endpoints that require no login:

| Source | Endpoint | Auth |
| --- | --- | --- |
| GitHub | `api.github.com/search/issues` | none (optional token raises rate limit) |
| Hacker News | `hn.algolia.com/api/v1` | none |
| Freelancer.com | `freelancer.com/api/projects/0.1` | none |
| YesWeHack | `api.yeswehack.com/programs` | none (public program list only — we never submit reports or scan targets) |
| Remotive | `remotive.com/api/remote-jobs` | none |

None of these are scraped with a browser, so there is no fingerprinting, no CAPTCHA solving, and no proxy dependency. If a source changes its API the Actor logs the failure and returns the rest.

***

### Local development

```bash
pip install -r requirements.txt
python -m src            # runs against real APIs, writes to local storage
python tests/test_radar_core.py   # 53 offline unit tests, no network
```

The scoring and filtering logic lives in `src/radar_core.py` and has no Apify dependency, so it can be tested and reused standalone.

# Actor input Schema

## `sources` (type: `array`):

Which sources to aggregate. Default: GitHub bounties + Hacker News + Freelancer.com + YesWeHack bug bounties.

## `maxLeads` (type: `integer`):

How many leads to deliver after filtering. Each returned lead is one billed event.

## `minScore` (type: `number`):

Drop leads scoring below this. Raise it to see fewer but better leads. 0 = no filter.

## `minPayoutUsd` (type: `number`):

Drop leads paying less than this, in USD. Freelancer.com amounts are already converted from INR/EUR/etc.

## `perSource` (type: `integer`):

How many raw items to pull from each source before de-noising. Higher = slower but fewer misses. Default: max(maxLeads\*2, 30).

## Actor input object example

```json
{
  "sources": [
    "github",
    "hn",
    "freelancer",
    "yeswehack"
  ],
  "maxLeads": 25,
  "minScore": 0,
  "minPayoutUsd": 0,
  "perSource": 30
}
```

# Actor output Schema

## `leads` (type: `string`):

One row per surviving lead, sorted by value score (USD per hour). Read it from the default dataset.

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

Counts for this run: sources used, how many items were scraped, how many were dropped as noise, and how many leads were returned.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("contributory_garnet_hyz/freelance-lead-radar").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("contributory_garnet_hyz/freelance-lead-radar").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 '{}' |
apify call contributory_garnet_hyz/freelance-lead-radar --silent --output-dataset

```

## MCP server setup

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

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/8I2fTowGZhurtU5d4/builds/YMyxADIo56sBpioyL/openapi.json
