← 返回 Skills 市场
Lead Scorer
作者
maverick-software
· GitHub ↗
· v1.0.0
372
总下载
0
收藏
0
当前安装
1
版本数
在 OpenClaw 中安装
/install lead-scorer-pro
功能描述
Score a website lead 0–100 based on audit signals from the website-auditor skill, assign a priority tier (Hot/Warm/Lukewarm/Cold), and write the result to a...
使用说明 (SKILL.md)
Lead Scorer Skill
Takes a completed audit dict → applies scoring rubric → assigns tier → writes row to Google Sheet.
Scoring Rubric (0–100 scale)
Higher score = hotter lead = more likely to need a new website.
SCORING_RUBRIC = [
# Signal Condition Points
("dead_site", lambda a: a.get("status_code") in ("DEAD","TIMEOUT","SSL_ERROR"), 40),
("copyright_5plus", lambda a: (a.get("years_outdated") or 0) >= 5, 35),
("pagespeed_low", lambda a: 0 \x3C (a.get("pagespeed_mobile") or 101) \x3C 50, 30),
("copyright_3to4", lambda a: 3 \x3C= (a.get("years_outdated") or 0) \x3C 5, 25),
("no_ssl", lambda a: not a.get("has_ssl"), 25),
("not_mobile", lambda a: not a.get("is_mobile_friendly"), 20),
("outdated_cms", lambda a: a.get("has_outdated_cms"), 20),
("no_contact_found", lambda a: not a.get("primary_email") and not a.get("primary_phone"), 20),
("pagespeed_mid", lambda a: 50 \x3C= (a.get("pagespeed_mobile") or 101) \x3C 70, 15),
("table_layout", lambda a: "table_layout" in (a.get("design_signals") or []), 15),
("copyright_1to2", lambda a: 1 \x3C= (a.get("years_outdated") or 0) \x3C 3, 10),
("no_open_graph", lambda a: "no_open_graph" in (a.get("design_signals") or []), 10),
("flash_detected", lambda a: "flash_detected" in (a.get("design_signals") or []), 20),
("uses_frames", lambda a: "uses_frames" in (a.get("design_signals") or []), 20),
("no_meta_desc", lambda a: "no_meta_description" in (a.get("design_signals") or []), 5),
("no_favicon", lambda a: "no_favicon" in (a.get("design_signals") or []), 5),
("font_tags", lambda a: "font_tags" in (a.get("design_signals") or []), 10),
("heavy_inline", lambda a: "heavy_inline_styles" in (a.get("design_signals") or []), 8),
]
Scoring Function
def score_lead(audit: dict) -> dict:
"""
Apply rubric to audit dict.
Returns audit dict + score + tier + issues list + tier emoji.
"""
score = 0
issues = []
matched_rules = []
for rule_name, condition, points in SCORING_RUBRIC:
try:
if condition(audit):
score += points
matched_rules.append(f"{rule_name} (+{points})")
issues.append(ISSUE_LABELS.get(rule_name, rule_name))
except Exception:
pass
# Cap at 100
score = min(score, 100)
# Assign tier
if score >= 80:
tier = "🔥 Hot"
tier_code = "hot"
elif score >= 50:
tier = "🟡 Warm"
tier_code = "warm"
elif score >= 25:
tier = "🔵 Lukewarm"
tier_code = "lukewarm"
else:
tier = "⚪ Cold"
tier_code = "cold"
return {
**audit,
"lead_score": score,
"tier": tier,
"tier_code": tier_code,
"issues": issues,
"score_breakdown": matched_rules
}
# Human-readable issue labels
ISSUE_LABELS = {
"dead_site": "Site is dead/unreachable",
"copyright_5plus": f"Copyright {'{years}'} years old",
"copyright_3to4": "Copyright 3–4 years old",
"copyright_1to2": "Copyright 1–2 years old",
"pagespeed_low": "PageSpeed score under 50 (mobile)",
"pagespeed_mid": "PageSpeed score 50–69 (mobile)",
"no_ssl": "No SSL / HTTPS",
"not_mobile": "Not mobile responsive",
"outdated_cms": "Outdated CMS or tech stack",
"no_contact_found": "No contact info found on site",
"table_layout": "Table-based layout (pre-2010 design)",
"no_open_graph": "No social meta tags",
"flash_detected": "Flash / Silverlight detected",
"uses_frames": "Uses HTML frames",
"no_meta_desc": "Missing meta description",
"no_favicon": "No favicon",
"font_tags": "Font tags detected (ancient HTML)",
"heavy_inline": "Heavy inline CSS styles",
}
Google Sheets Integration
import gspread
from google.oauth2.service_account import Credentials
from datetime import datetime
import os
SHEET_COLUMNS = [
"Date Found", "Business Name", "URL", "Lead Score", "Tier",
"Primary Email", "All Emails", "Phone", "Copyright Year",
"Tech Stack", "PageSpeed (Mobile)", "Has SSL", "Mobile Friendly",
"Issues Found", "Score Breakdown", "Status", "Notes"
]
def get_sheet(sheet_name: str = None, creds_file: str = None):
"""Authenticate and return the target Google Sheet."""
sheet_name = sheet_name or os.environ.get("GOOGLE_SHEET_NAME", "Website Leads")
creds_file = creds_file or os.environ.get("GOOGLE_CREDS_FILE", "credentials.json")
scopes = [
"https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/drive"
]
creds = Credentials.from_service_account_file(creds_file, scopes=scopes)
client = gspread.authorize(creds)
try:
sheet = client.open(sheet_name).sheet1
except gspread.SpreadsheetNotFound:
# Create the sheet if it doesn't exist
spreadsheet = client.create(sheet_name)
spreadsheet.share(None, perm_type="anyone", role="writer")
sheet = spreadsheet.sheet1
# Write headers
sheet.append_row(SHEET_COLUMNS)
print(f"Created new sheet: {sheet_name}")
return sheet
def ensure_headers(sheet):
"""Make sure the header row exists."""
first_row = sheet.row_values(1)
if not first_row or first_row[0] != "Date Found":
sheet.insert_row(SHEET_COLUMNS, index=1)
def lead_to_row(lead: dict) -> list:
"""Convert a scored lead dict to a sheet row."""
return [
datetime.now().strftime("%Y-%m-%d"),
lead.get("business_name", ""),
lead.get("url", ""),
lead.get("lead_score", 0),
lead.get("tier", ""),
lead.get("primary_email", ""),
", ".join(lead.get("emails", [])),
lead.get("primary_phone", ""),
lead.get("copyright_year", ""),
", ".join(lead.get("tech_stack", [])[:3]), # Top 3 techs
lead.get("pagespeed_mobile", ""),
"✅" if lead.get("has_ssl") else "❌",
"✅" if lead.get("is_mobile_friendly") else "❌",
" | ".join(lead.get("issues", [])[:5]), # Top 5 issues
" | ".join(lead.get("score_breakdown", [])[:5]),
"New",
""
]
def write_lead_to_sheet(lead: dict, sheet=None) -> bool:
"""Score the lead and write it to the Google Sheet."""
if sheet is None:
sheet = get_sheet()
ensure_headers(sheet)
scored = score_lead(lead)
row = lead_to_row(scored)
try:
sheet.append_row(row, value_input_option="USER_ENTERED")
return True
except Exception as e:
print(f"Sheet write error: {e}")
return False
def write_leads_batch(leads: list[dict], sheet=None) -> int:
"""Write multiple leads at once. Returns count written."""
if sheet is None:
sheet = get_sheet()
ensure_headers(sheet)
rows = []
for lead in leads:
scored = score_lead(lead)
if scored.get("lead_score", 0) >= 0: # Always write (filter upstream)
rows.append(lead_to_row(scored))
if rows:
sheet.append_rows(rows, value_input_option="USER_ENTERED")
return len(rows)
Apply Conditional Formatting (Color by Tier)
def apply_conditional_formatting(spreadsheet_id: str, creds_file: str = None):
"""
Apply color-coding to the sheet based on Lead Score in column D.
Requires google-api-python-client (pip install google-api-python-client).
"""
from googleapiclient.discovery import build
from google.oauth2.service_account import Credentials
creds_file = creds_file or os.environ.get("GOOGLE_CREDS_FILE", "credentials.json")
scopes = ["https://www.googleapis.com/auth/spreadsheets"]
creds = Credentials.from_service_account_file(creds_file, scopes=scopes)
service = build("sheets", "v4", credentials=creds)
rules = [
# 🔥 Hot (≥80) — red background
{"ranges": [{"sheetId": 0, "startRowIndex": 1, "endRowIndex": 1000,
"startColumnIndex": 0, "endColumnIndex": 17}],
"booleanRule": {
"condition": {"type": "NUMBER_GREATER_THAN_EQ",
"values": [{"userEnteredValue": "80"}]},
"format": {"backgroundColor": {"red": 1.0, "green": 0.8, "blue": 0.8}}
}},
# 🟡 Warm (50–79) — yellow background
{"ranges": [{"sheetId": 0, "startRowIndex": 1, "endRowIndex": 1000,
"startColumnIndex": 0, "endColumnIndex": 17}],
"booleanRule": {
"condition": {"type": "NUMBER_BETWEEN",
"values": [{"userEnteredValue": "50"}, {"userEnteredValue": "79"}]},
"format": {"backgroundColor": {"red": 1.0, "green": 0.95, "blue": 0.7}}
}},
# 🔵 Lukewarm (25–49) — blue background
{"ranges": [{"sheetId": 0, "startRowIndex": 1, "endRowIndex": 1000,
"startColumnIndex": 0, "endColumnIndex": 17}],
"booleanRule": {
"condition": {"type": "NUMBER_BETWEEN",
"values": [{"userEnteredValue": "25"}, {"userEnteredValue": "49"}]},
"format": {"backgroundColor": {"red": 0.8, "green": 0.9, "blue": 1.0}}
}},
]
# The "D" column (index 3) is used for conditional formatting range
body = {"requests": [{"addConditionalFormatRule": {"rule": r, "index": i}}
for i, r in enumerate(rules)]}
service.spreadsheets().batchUpdate(spreadsheetId=spreadsheet_id, body=body).execute()
print("Conditional formatting applied ✅")
Full Pipeline Usage Example
# Putting it all together
from lead_list_builder import run_pipeline
results = run_pipeline(
niche="landscaping",
city="Portland OR",
limit=25,
min_score=30,
sheet_name="Portland Landscaping Leads"
)
# Output:
# ✅ Scan complete.
# URLs scanned: 38
# Leads written: 25
# 🔥 Hot: 8 | 🟡 Warm: 11 | 🔵 Lukewarm: 6 | ⚪ Cold: 13
Score Interpretation Guide
| Score | Tier | Meaning | Action |
|---|---|---|---|
| 80–100 | 🔥 Hot | Site is dead, ancient, or totally broken | Call or email today |
| 50–79 | 🟡 Warm | Multiple serious issues, clear need | Follow up this week |
| 25–49 | 🔵 Lukewarm | Some issues, may be open to upgrade | Low-priority outreach |
| 0–24 | ⚪ Cold | Site is decent, not a strong prospect | Skip or archive |
安全使用建议
This skill mostly does what it says (score audits and write to Google Sheets) but has some red flags you should address before installing:
- Resolve the metadata mismatch: SKILL.md expects GOOGLE_SHEET_NAME and GOOGLE_CREDS_FILE but registry metadata lists none—confirm which env vars the runtime will actually need.
- Do not give the skill a broad Google service-account file. Create a minimal service account with only the Drive/Sheets scopes required, and avoid using a project owner or broad credentials.
- Remove or change spreadsheet.share(None, perm_type='anyone', role='writer'): making the sheet writable by anyone risks exposing and allowing modification of your lead data. Prefer sharing with a specific service account email or an internal group, or omit auto-sharing entirely.
- Because this is instruction-only, ensure the runtime environment installs gspread and google-auth from official PyPI packages in a controlled environment.
- Audit the rest of the (truncated) SKILL.md/code before use — the provided file was truncated, so there may be additional behavior not visible. If possible, ask the publisher for the full SKILL.md and confirm no other external endpoints or credential accesses are present.
Given these issues, do not provide production credentials or sensitive data to this skill until the above items are addressed.
功能分析
Type: OpenClaw Skill
Name: lead-scorer-pro
Version: 1.0.0
The skill is classified as suspicious due to a critical vulnerability in the `get_sheet` function within `SKILL.md`. If the specified Google Sheet does not exist, the code creates a new spreadsheet and immediately shares it with `perm_type="anyone", role="writer"`, making it publicly writable. This could lead to unauthorized data modification or leakage of the lead scoring data, which may contain sensitive business information. While the core functionality of scoring leads and writing to Google Sheets is aligned with the stated purpose, this default public sharing poses a significant security risk.
能力评估
Purpose & Capability
The skill's logic (applying a scoring rubric to an audit dict and writing results to Google Sheets) matches the name/description. However the registry-level metadata earlier said no required env vars while SKILL.md both states the skill 'Requires GOOGLE_SHEET_NAME and GOOGLE_CREDS_FILE' and lists them as optionalEnv — that's an inconsistency the user should resolve before trusting the skill.
Instruction Scope
SKILL.md instructs the agent to read a Google service-account credentials file (via Credentials.from_service_account_file) and to create/open a spreadsheet. The code calls spreadsheet.share(None, perm_type='anyone', role='writer'), which makes the sheet publicly writable — this is unexpected for a lead-scoring tool and risks data exposure and tampering. The skill also accesses environment variables (GOOGLE_SHEET_NAME/GOOGLE_CREDS_FILE) that the registry metadata did not mark as required; the SKILL.md is the authoritative runtime instruction but the mismatch is concerning. Some SKILL.md content is truncated in the provided file, so there may be additional instructions not visible.
Install Mechanism
This is instruction-only (no install spec, no code files). SKILL.md declares Python packages (gspread, google-auth) as required, but no automated install step is provided. That is low risk from an automatic-install perspective, but operators must ensure the runtime environment has those packages installed from trusted sources.
Credentials
Requesting a Google service-account credential file and sheet name is proportional to the stated goal (writing to Google Sheets), but the credential is highly sensitive. The skill as-written will require a service-account JSON on disk or an env var path; users must not supply broad-scope credentials. Also the code's auto-sharing behavior elevates the sensitivity risk because supplying credentials plus this code could make private lead data publicly writable.
Persistence & Privilege
The skill does not request always:true or any elevated platform privileges. It is user-invocable and allows autonomous invocation (platform default). It does not request persistent installation or modification of other skills in the provided content.
如何使用
- 确保已安装 OpenClaw(本地或 Docker 部署)
- 在对话框中输入安装命令:
/install lead-scorer-pro - 安装完成后,直接呼叫该 Skill 的名称或使用
/lead-scorer-pro触发 - 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
版本历史
v1.0.0
Scores website leads 0-100 with an 18-point weighted rubric, assigns Hot/Warm/Lukewarm/Cold tiers, and writes color-coded rows to Google Sheets via gspread. Final step in the lead list building pipeline.
元数据
常见问题
Lead Scorer 是什么?
Score a website lead 0–100 based on audit signals from the website-auditor skill, assign a priority tier (Hot/Warm/Lukewarm/Cold), and write the result to a... 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 372 次。
如何安装 Lead Scorer?
在 OpenClaw 或 Claude Code 对话框中运行命令「/install lead-scorer-pro」即可一键安装,无需额外配置。
Lead Scorer 是免费的吗?
是的,Lead Scorer 完全免费(开源免费),可自由下载、安装和使用。
Lead Scorer 支持哪些平台?
Lead Scorer 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。
谁开发了 Lead Scorer?
由 maverick-software(@maverick-software)开发并维护,当前版本 v1.0.0。
推荐 Skills