Upwork Automation Suite - Lead Scoring and CRM Sync by Kenny DunnUpwork Automation Suite - Lead Scoring and CRM Sync by Kenny Dunn

Upwork Automation Suite - Lead Scoring and CRM Sync

Kenny Dunn

Kenny Dunn

The Problem

Freelancing on Upwork means constant manual overhead: refreshing the job feed, eyeballing budgets and client history for signal, and separately tracking every proposal's status. That overhead either eats billable hours or gets skipped — and skipped tracking means leads fall through the cracks.

The Build

An n8n system with three integrated pipelines, running on Gmail triggers and a Telegram bot control surface:
Job discovery & scoring
Gmail trigger polls for Upwork job alert emails every 15 minutes
A custom parser extracts budget, duration, hours/week, required skills, client payment-verification status, total client spend, and rating directly from the raw email — no manual review needed
A spam/quality filter kills known low-value categories (data entry, VA work, content mills) before they ever reach a human
A weighted scoring model ranks matches against high-value signals (PMP, ClickUp, n8n, Ableton, Max/MSP, retainer language, client spend history, rating) and tiers each job: High Signal / Good Match / Moderate / Low Signal
New (non-duplicate) jobs are logged to Sheets and pushed to Telegram with the full scoring breakdown, then auto-created as prioritized ClickUp tasks in the Leads CRM list
Proposal logging (chat-driven)
A Telegram bot accepts a simple pipe-delimited command (proposal | Job Title | Client | Category | Bid | Notes) or a raw pasted Upwork proposal, which an LLM call parses into structured fields when the shorthand format isn't used
Every proposal is appended/updated into a Proposals sheet with an idempotent match key
Auto-sync to CRM: once a proposal is logged, the workflow searches open "New Lead" tasks in ClickUp, fuzzy-matches the job title against the proposal, and automatically flips that task's status to "Proposal Submitted" — closing the loop between "I applied" and "my CRM reflects that" without touching ClickUp by hand
Status updates
A second bot command (status | Job Title | new_status) updates proposal status (Viewed/Replied/Hired/Archived) directly from chat, validated against an allowed status list
Error handling & observability
Dedicated error trigger logs every failure (execution ID, workflow, node, message) to a separate error-tracking sheet
Unmatched/malformed bot messages get an explicit "no route matched" alert instead of failing silently
Fuzzy-match failures on the CRM sync trigger a manual-review alert rather than guessing wrong

Why It Matters

This isn't a single webhook — it's a closed-loop business development system: discovery, scoring, CRM entry, proposal logging, and CRM status sync, with fallback logic and error visibility at every hop. The same pattern generalizes to any lead-gen or CRM-sync problem: parse unstructured input, score it against weighted business rules, and keep two systems of record in sync without manual double-entry.

Result

Eliminated manual job-feed monitoring entirely. Every qualifying lead lands in the CRM pre-scored and pre-prioritized. Proposal tracking and CRM status now update from a single chat message — no app-switching, no forgotten follow-ups.
Like this project

Posted Jul 21, 2026

Closed-loop Upwork lead system: Gmail parsing, weighted job scoring, and chat-driven proposal logging with automatic ClickUp CRM status sync.