
Copywriting
- 103 installs
- 451 repo stars
- Updated July 21, 2026
- borghei/claude-skills
Copywriting is a Claude skill for writing persuasive marketing copy for homepages, landing, pricing, feature, and product pages using headline formulas and frameworks like PAS and AIDA.
About
Copywriting produces persuasive marketing copy for homepages, landing pages, pricing pages, feature pages, and product pages. It supplies headline formulas, CTA frameworks, page-structure templates, and copywriting frameworks like PAS, AIDA, BAB, and QUEST, plus objection handling. A marketer uses it to write or improve page copy, headlines, and CTAs with a benefit-driven, specificity-first approach.
- Writes conversion copy for homepages, landing, pricing, feature, and product pages
- Includes headline formulas, CTA frameworks, and page-structure templates
- Covers PAS, AIDA, BAB, 4 Ps, and QUEST copywriting frameworks with objection handling
Copywriting by the numbers
- 103 all-time installs (skills.sh)
- Ranked #1,139 of 1,879 Marketing & SEO skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
copywriting capabilities & compatibility
- Capabilities
- copywriting · headline writing · cta writing · landing page copy
- Use cases
- copywriting · marketing
- Pricing
- Free
What copywriting says it does
Conversion-focused marketing copy that is clear, compelling, and drives action across every page type.
Write the headline using a formula from the library (generate 5 options)
PAS: Problem > Agitate > Solution
npx skills add https://github.com/borghei/claude-skills --skill copywritingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 103 |
|---|---|
| repo stars | ★ 451 |
| Last updated | July 21, 2026 |
| Repository | borghei/claude-skills ↗ |
What it does
Write or improve conversion copy for homepages, landing, pricing, and product pages.
Who is it for?
Writing and improving conversion copy for marketing pages
Skip if: Long-form editorial articles or proofreading existing copy
When should I use this skill?
Writing page copy, improving headlines, crafting CTAs, or rewriting marketing pages
What you get
Produces clear, benefit-driven page copy with strong headlines, proof, and CTAs.
- page copy
- headlines
- CTAs
By the numbers
- Provides 5 copywriting frameworks (PAS, AIDA, BAB, 4 Ps, QUEST)
- Recommends generating 5 headline options
Files
Copywriting
Conversion-focused marketing copy that is clear, compelling, and drives action across every page type.
---
Table of Contents
- Keywords
- Quick Start
- Core Principles
- Copywriting Frameworks
- Page Structure by Type
- Headline Formula Library
- CTA Framework
- Objection Handling in Copy
- Voice and Tone Calibration
- Best Practices
- Integration Points
---
Keywords
copywriting, marketing copy, conversion copy, headline writing, CTA copy, landing page copy, homepage copy, pricing page copy, feature page copy, persuasive writing, value proposition, benefit-driven copy, sales copy, page copy, web copy, product copy, SaaS copy, PAS framework, AIDA framework, BAB framework, objection handling
---
Quick Start
Write Page Copy
1. Define the page purpose, target audience, and desired action 2. Select the appropriate page structure template 3. Write the headline using a formula from the library (generate 5 options) 4. Write each section following the structure framework 5. Add social proof, objection handling, and CTA 6. Review against the quality checklist
Improve Existing Copy
1. Identify the page goal and target audience 2. Audit headline for specificity and benefit clarity 3. Check every feature for a corresponding benefit ("which means...") 4. Verify social proof is specific and attributed 5. Evaluate CTA for action orientation and friction level 6. Test: Would a first-time visitor understand the value in 5 seconds?
---
Core Principles
1. Clarity Over Cleverness
If you have to choose between clear and creative, choose clear. A confused reader does not convert.
2. Benefits Over Features
Features describe what it does. Benefits describe what it means for the customer.
| Feature | Benefit |
|---|---|
| "Real-time analytics dashboard" | "See exactly what's working right now — no waiting for reports" |
| "AI-powered recommendations" | "Get suggestions that actually match your data, not generic advice" |
| "99.99% uptime SLA" | "Your customers never see a down page" |
| "SOC 2 Type II certified" | "Pass your enterprise security review without the 6-month scramble" |
3. Specificity Over Vagueness
- Vague: "Save time on your workflow"
- Specific: "Cut your weekly reporting from 4 hours to 15 minutes"
- Vague: "Trusted by thousands"
- Specific: "Used by 2,847 teams including Stripe, Notion, and Linear"
4. Customer Language Over Company Language
Mirror the words your customers use. Pull language from reviews, support tickets, sales calls, and interviews.
5. One Idea Per Section
Each section advances one argument. Build a logical flow down the page: problem > solution > proof > action.
6. Honest Over Sensational
Never fabricate statistics, testimonials, or claims. Exaggeration erodes trust. Specificity and honesty convert better than hype.
---
Copywriting Frameworks
PAS: Problem > Agitate > Solution
Best for: landing pages, email subject lines, ad copy, product pages
[Problem]: Name the pain in the reader's language
[Agitate]: Show what happens if they don't fix it
[Solution]: Introduce your product as the answerExample:
Your team spends 4 hours every week manually compiling reports. That is 200 hours a year — the equivalent of losing a full-time employee to spreadsheets. [Product] automates your reporting in 10 minutes. Set it once, get reports delivered every Monday morning.
AIDA: Attention > Interest > Desire > Action
Best for: homepage, awareness campaigns, long-form sales pages
[Attention]: Bold statement or surprising claim
[Interest]: Expand with relevant details
[Desire]: Show proof and paint the transformation
[Action]: Clear CTABAB: Before > After > Bridge
Best for: case studies, testimonial framing, email sequences
[Before]: Current painful state
[After]: Desired future state
[Bridge]: How your product gets them there4 Ps: Promise > Picture > Proof > Push
Best for: sales pages, feature pages, product launches
[Promise]: State the key benefit
[Picture]: Help them visualize the outcome
[Proof]: Show evidence it works
[Push]: Call to action with urgencyQUEST: Qualify > Understand > Educate > Stimulate > Transition
Best for: long-form content, webinar scripts, nurture sequences
[Qualify]: Identify the right audience
[Understand]: Show you get their problem
[Educate]: Teach them something valuable
[Stimulate]: Create excitement about the solution
[Transition]: Move to the ask---
Page Structure by Type
Homepage Structure
The homepage serves multiple audiences. Lead with the broadest value proposition.
| Section | Purpose | Guidelines |
|---|---|---|
| Hero | Communicate core value in 5 seconds | Headline + subheadline + primary CTA + visual |
| Social proof bar | Build instant credibility | Customer logos, review scores, or customer count |
| Problem statement | Show you understand their pain | 2-3 pain points in their language |
| Solution overview | Present your answer (3-5 key benefits) | Benefit-first, not feature-first |
| How it works | Reduce perceived complexity | 3-4 steps maximum |
| Use cases | Help different audiences see themselves | 2-3 use case tabs or sections |
| Testimonials | Proof from real customers | Named, specific, with measurable outcomes |
| Objection handling | Remove barriers | FAQ or guarantee section |
| Final CTA | Repeat the ask | Recap value + CTA + risk reversal |
Landing Page Structure
Single message, single CTA. Everything on the page serves one conversion goal.
| Section | Purpose | Guidelines |
|---|---|---|
| Hero | Match headline to traffic source | Exact message match with ad or email |
| Value proposition | One clear benefit | Subheadline expands on headline |
| Problem / Pain | Why they need this now | 2-3 bullet points of pain |
| Solution | What they get | Feature > Benefit mapping |
| Social proof | Relevant proof | Testimonial from similar customer |
| CTA | The one ask | Action verb + what they get |
| Risk reversal | Remove hesitation | Guarantee, no CC, cancel anytime |
Pricing Page Structure
Help visitors choose the right plan. Reduce comparison anxiety.
| Section | Purpose | Guidelines |
|---|---|---|
| Value summary | Remind them why before asking for money | One line connecting price to value |
| Plan comparison | Help them choose | 2-4 tiers, recommended plan highlighted |
| Feature matrix | Detailed comparison | Checkmarks with tooltips for complex features |
| FAQ | Address pricing objections | "Can I switch plans?", "What happens after trial?" |
| Social proof | Proof near the buy button | Testimonial or customer count |
| Enterprise CTA | Catch high-value prospects | "Need custom pricing? Talk to us" |
Feature Page Structure
Connect every feature to a business outcome.
| Section | Purpose | Guidelines |
|---|---|---|
| Feature hero | What it does + why it matters | Headline = outcome, subheadline = mechanism |
| Visual demo | Show it in action | Screenshot, GIF, or video |
| Benefits | Why this feature matters | 3-4 benefits with "which means..." bridges |
| Use case | Concrete scenario | "When [situation], you can [action] to [outcome]" |
| Technical details | For evaluators | Expandable section for technical specs |
| Related features | Cross-sell | Links to complementary features |
| CTA | Drive trial or demo | "Try [feature] free" or "See it in action" |
---
Headline Formula Library
Outcome-First Formulas
[Achieve outcome] without [pain point]- "Build landing pages in minutes without writing code"
- "Hire senior engineers without the 4-month wait"
[Achieve outcome] in [timeframe]- "Get your first 1,000 customers in 90 days"
- "Set up analytics tracking in under 10 minutes"
Problem-First Formulas
Stop [pain point]. Start [desired state].- "Stop guessing what's working. Start knowing."
- "Stop chasing approvals. Start shipping."
[Pain point] is costing you [specific cost]- "Manual reporting is costing you 200 hours per year"
- "Slow page loads are costing you 23% of mobile visitors"
Category-Definition Formulas
The [category] for [specific audience]- "The analytics platform for product teams"
- "The CRM for founders who hate CRMs"
[Category], but [key differentiator]- "Project management, but built for remote teams"
- "Email marketing, but with deliverability built in"
Social Proof Formulas
[Number] [people/companies] [outcome]- "2,847 teams ship faster with [Product]"
- "Join 40,000 marketers who read this newsletter"
[Specific customer] [specific result] with [Product]- "How Stripe reduced onboarding time by 60% with [Product]"
Question Formulas
[Question that highlights pain]?- "Still spending your Sunday nights on reporting?"
- "What if your analytics actually told you what to do next?"
Generating Headline Options
For every page, generate minimum 5 headline options across different formula types: 1. One outcome-first headline 2. One problem-first headline 3. One category-definition headline 4. One social proof headline 5. One question or bold claim headline
Select the strongest. Test the top 2-3 if possible.
---
CTA Framework
CTA Formula
[Action Verb] + [What They Get] + [Qualifier if needed]CTA Strength Spectrum
| Weak (avoid) | Moderate | Strong (use) |
|---|---|---|
| Submit | Sign Up | Start My Free Trial |
| Click Here | Get Started | Get the Complete Checklist |
| Learn More | Try Free | See [Product] in Action |
| Contact Us | Book a Demo | Create My First [Thing] |
| Send | Download | Get My Free Analysis |
CTA Friction Calibration
Match CTA friction to visitor readiness:
| Visitor State | CTA Friction Level | Examples |
|---|---|---|
| Cold (first visit) | Very low | "See how it works," "Watch 2-min demo" |
| Warm (return visit) | Low | "Start free trial," "Try it free" |
| Hot (pricing page) | Medium | "Start my plan," "Get started today" |
| Returning (abandoned) | Low + urgency | "Pick up where you left off" |
Supporting CTA Copy
Below the CTA button, reduce friction:
- "No credit card required"
- "Free for 14 days, cancel anytime"
- "Takes 2 minutes to set up"
- "Join 2,847 teams already using [Product]"
---
Objection Handling in Copy
Common Objections and Copy Responses
| Objection | Where to Address | Copy Approach |
|---|---|---|
| "Too expensive" | Pricing page, FAQ | ROI framing: "Saves X hours/week at $Y/hour = $Z saved" |
| "Not sure it works" | Social proof sections | Named testimonials with specific metrics |
| "Too complex to set up" | How it works section | "3 steps, 10 minutes, no code required" |
| "What if I don't like it?" | Near CTA | Guarantee: "30-day money-back, no questions asked" |
| "I need to check with my team" | Near CTA | "Share a free trial with your team" |
| "Is it secure?" | Trust section or footer | Certifications: "SOC 2, GDPR, ISO 27001" |
| "Will it integrate?" | Feature or FAQ section | "Connects with 200+ tools including [key ones]" |
Risk Reversal Techniques
Position risk reversals near CTAs:
- Money-back guarantee with specific timeframe
- Free trial (no credit card)
- "Cancel anytime" commitment
- Success guarantee ("If you don't see X result in Y days...")
- "Keep the content/data even if you cancel"
---
Voice and Tone Calibration
Formality Spectrum
| Level | When | Example |
|---|---|---|
| Casual | Consumer, community, social | "Let's make your reporting suck less." |
| Conversational | SaaS, mid-market, blog | "Your weekly reports shouldn't take 4 hours." |
| Professional | B2B, enterprise, sales | "Reduce reporting overhead by 80% with automated dashboards." |
| Formal | Legal, healthcare, finance | "Our platform ensures compliance with regulatory reporting requirements." |
Personality Calibration
| Bold | Understated |
|---|---|
| "We built the fastest analytics platform. Period." | "Our analytics platform is designed for speed." |
| Strong opinions, definitive statements | Measured claims, qualified statements |
| Best for: Startups, challenger brands | Best for: Enterprise, regulated industries |
Consistency Rules
- Headlines can be bolder than body copy
- Body copy should be clearer than clever
- CTAs should be action-oriented regardless of formality
- Maintain the same personality throughout the entire page
- Adjust intensity, not identity, between sections
---
Best Practices
1. Write the CTA first — Know what action you want before writing anything else. Every sentence leads to that action.
2. Lead with "you," not "we" — Count how many sentences start with "We" or your brand name. Rewrite to lead with the customer.
3. Cut 30% on the second pass — First drafts are always too long. The second pass should cut ruthlessly.
4. Show, don't tell — "Fast" means nothing. "Page loads in 200ms" means something. Replace every adjective with evidence.
5. One argument per scroll — Each scroll depth should advance exactly one argument. Problem, then solution, then proof, then action.
6. Match headline to traffic source — A landing page headline must mirror the ad, email, or link that brought the visitor. Mismatched expectations cause bounce.
7. Social proof near CTAs — Place testimonials and trust signals near every CTA. Proof reduces friction at the moment of decision.
8. Provide alternatives, not just options — "Start free trial" + "Book a demo" + "See pricing" gives three paths for three readiness levels.
9. Read it aloud — If it sounds like a brochure, rewrite it. If it sounds like a person explaining the product to a friend, it is close.
10. Test headlines relentlessly — The headline is the highest-leverage element on any page. A/B test the top 2-3 options.
---
Integration Points
- Copy Editing — Use after drafting to systematically polish through the seven sweeps (clarity, voice, so what, prove it, specificity, emotion, risk).
- Content Strategy — Use for deciding what pages to create. Copywriting handles the writing.
- Landing Page Generator — Use for generating the code/design. Copywriting handles the words.
- Marketing Psychology — Use psychological principles (anchoring, social proof, loss aversion) to strengthen copy.
- Brand Guidelines — Reference brand voice and visual standards for consistency.
- Ad Creative — Use for platform-specific ad copy. Copywriting handles page-level copy.
- Content Humanizer — Use if AI-drafted copy sounds robotic and needs voice injection.
---
Troubleshooting
| Symptom | Likely Cause | Fix |
|---|---|---|
| Page not converting despite traffic | Headline-to-traffic mismatch or weak CTA | Verify headline matches the ad/email source. Run headline_scorer.py. |
| Visitors bounce without scrolling | Hero section fails the 5-second test | Rewrite headline: benefit + specificity. Remove jargon. |
| High scroll depth but no clicks | CTA is weak, buried, or too many options | Run cta_optimizer.py. Place CTA above fold and after every major section. |
| Copy sounds like a brochure | Too company-focused, not customer-focused | Run page_copy_auditor.py. Ensure you/your outnumbers we/our 2:1. |
| Features listed without impact | Missing "which means..." bridges | Connect every feature to a business outcome the reader cares about. |
| Social proof feels generic | "Great product!" without specifics | Replace with named testimonials + specific metrics + outcomes. |
| Pricing page has high drop-off | No objection handling or risk reversal | Add FAQ, guarantees, and "no credit card required" near CTA. |
---
Success Criteria
- Every headline passes the 5-second test: visitor understands value without scrolling
- You/your language outnumbers we/our by at least 2:1 across the page
- Every feature has a corresponding benefit with "which means..." bridge
- CTA appears 2-3 times on every page (hero, mid-page, footer)
- Risk reversal text appears near every CTA ("No credit card," "Cancel anytime")
- Specific numbers used instead of vague claims ("2,847 teams" not "thousands")
- A/B test running on headline at all times for top-traffic pages
---
Scope & Limitations
In Scope: Marketing page copy for homepages, landing pages, pricing pages, feature pages, and product pages. Headline formulas, CTA frameworks, objection handling, voice calibration.
Out of Scope: Ad copy (use ad-creative), email copy (use email-sequence), blog/content writing (use content-creator), page design/code (use landing-page-generator), copy editing (use copy-editing).
---
Python Automation Tools
1. Headline Scorer (scripts/headline_scorer.py)
Scores marketing headlines for clarity, benefit strength, specificity, and conversion potential.
python scripts/headline_scorer.py "Build landing pages in minutes without writing code"
python scripts/headline_scorer.py --file headlines.txt --json2. CTA Optimizer (scripts/cta_optimizer.py)
Analyzes and scores CTA text for action strength, specificity, ownership language, and friction level.
python scripts/cta_optimizer.py "Start my free trial"
python scripts/cta_optimizer.py --file ctas.txt --json3. Page Copy Auditor (scripts/page_copy_auditor.py)
Audits marketing page copy for customer focus, specificity, social proof, CTA presence, objection handling, and readability.
python scripts/page_copy_auditor.py page.txt
python scripts/page_copy_auditor.py page.html --json#!/usr/bin/env python3
"""
CTA Optimizer
Analyzes and scores call-to-action text for strength,
friction level, and conversion potential.
Usage:
python cta_optimizer.py "Start my free trial"
python cta_optimizer.py --file ctas.txt --json
"""
import argparse
import json
import re
import sys
STRONG_CTAS = {
"start": 90, "get": 85, "create": 85, "build": 85, "try": 80,
"discover": 80, "claim": 85, "unlock": 80, "see": 75, "join": 80,
"book": 75, "download": 75, "access": 80, "activate": 85,
}
WEAK_CTAS = {
"submit": 30, "click here": 25, "click": 30, "send": 35,
"go": 40, "enter": 35, "continue": 40,
}
MODERATE_CTAS = {
"learn more": 50, "sign up": 60, "get started": 65,
"contact us": 45, "request": 55, "register": 55,
"subscribe": 55, "buy now": 60, "order": 55,
}
FRICTION_REDUCERS = [
"free", "no credit card", "no card", "cancel anytime",
"2 minutes", "instant", "no commitment", "risk-free",
"money-back", "guarantee", "try", "no obligation",
]
OWNERSHIP_WORDS = ["my", "your", "our"]
def score_cta(cta: str) -> dict:
lower = cta.lower().strip()
words = lower.split()
result = {
"cta": cta,
"word_count": len(words),
"scores": {},
"analysis": {},
"improvements": [],
}
# Action strength
first_word = words[0] if words else ""
action_score = 50
if first_word in STRONG_CTAS:
action_score = STRONG_CTAS[first_word]
result["analysis"]["action_strength"] = "strong"
elif lower in WEAK_CTAS or first_word in WEAK_CTAS:
action_score = WEAK_CTAS.get(lower, WEAK_CTAS.get(first_word, 35))
result["analysis"]["action_strength"] = "weak"
result["improvements"].append(f"Replace '{first_word}' with a stronger verb (start, get, create, build).")
elif lower in MODERATE_CTAS or first_word in MODERATE_CTAS:
action_score = MODERATE_CTAS.get(lower, MODERATE_CTAS.get(first_word, 55))
result["analysis"]["action_strength"] = "moderate"
else:
action_score = 55
result["analysis"]["action_strength"] = "unknown"
result["scores"]["action_strength"] = action_score
# Specificity -- does it tell them what they get?
has_what = len(words) > 2
has_benefit_word = bool(re.search(r"(trial|demo|guide|report|analysis|dashboard|account|plan|checklist|template)", lower))
specificity = 40
if has_what and has_benefit_word:
specificity = 90
result["analysis"]["specificity"] = "high -- tells user what they receive"
elif has_what:
specificity = 65
result["analysis"]["specificity"] = "medium -- action but vague outcome"
result["improvements"].append("Add what they get: 'Start my free trial' > 'Start'")
else:
specificity = 35
result["analysis"]["specificity"] = "low -- too generic"
result["improvements"].append("Expand CTA: [Action Verb] + [What They Get]")
result["scores"]["specificity"] = specificity
# Ownership language
has_ownership = any(w in words for w in OWNERSHIP_WORDS)
if has_ownership:
result["scores"]["ownership"] = 85
result["analysis"]["ownership"] = "Uses ownership language ('my/your') -- increases click rate"
else:
result["scores"]["ownership"] = 50
result["improvements"].append("Try ownership: 'Start free trial' -> 'Start my free trial'")
# Friction assessment
friction_signals = [f for f in FRICTION_REDUCERS if f in lower]
if friction_signals:
result["scores"]["friction"] = 90
result["analysis"]["friction_level"] = "low -- friction reducers present"
elif any(w in lower for w in ["buy", "purchase", "pay", "subscribe", "commit"]):
result["scores"]["friction"] = 35
result["analysis"]["friction_level"] = "high -- purchase commitment"
else:
result["scores"]["friction"] = 60
result["analysis"]["friction_level"] = "medium"
result["improvements"].append("Add supporting text below CTA: 'No credit card required' or 'Free for 14 days'")
# Length
if 3 <= len(words) <= 6:
result["scores"]["length"] = 90
elif len(words) <= 2:
result["scores"]["length"] = 55
result["improvements"].append("CTA is too short. Aim for 3-6 words.")
else:
result["scores"]["length"] = 60
result["improvements"].append("CTA is long. Trim to 3-6 words.")
# Overall
weights = {"action_strength": 0.30, "specificity": 0.25, "ownership": 0.15, "friction": 0.15, "length": 0.15}
overall = sum(result["scores"].get(k, 50) * w for k, w in weights.items())
result["overall_score"] = round(overall)
result["grade"] = "A" if overall >= 85 else "B" if overall >= 70 else "C" if overall >= 55 else "D" if overall >= 40 else "F"
if not result["improvements"]:
result["improvements"].append("Strong CTA. A/B test against 2-3 variants.")
return result
def format_human(results: list) -> str:
lines = ["\n" + "=" * 55, " CTA OPTIMIZER", "=" * 55]
for r in results:
lines.append(f"\n \"{r['cta']}\"")
lines.append(f" Score: {r['overall_score']}/100 ({r['grade']})")
for k, v in r["analysis"].items():
lines.append(f" {k.replace('_', ' ').title()}: {v}")
for imp in r["improvements"]:
lines.append(f" > {imp}")
lines.append("-" * 55)
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(description="Score and optimize CTA copy.")
parser.add_argument("cta", nargs="?")
parser.add_argument("--file", "-f")
parser.add_argument("--json", action="store_true", dest="json_output")
args = parser.parse_args()
ctas = []
if args.file:
with open(args.file) as f:
ctas = [l.strip() for l in f if l.strip()]
elif args.cta:
ctas = [args.cta]
else:
parser.print_help()
sys.exit(1)
results = [score_cta(c) for c in ctas]
if args.json_output:
print(json.dumps(results if len(results) > 1 else results[0], indent=2))
else:
print(format_human(results))
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Headline Scorer
Scores marketing headlines for clarity, benefit strength,
specificity, and conversion potential.
Usage:
python headline_scorer.py "Build landing pages in minutes without writing code"
python headline_scorer.py --file headlines.txt --json
"""
import argparse
import json
import re
import sys
POWER_WORDS = [
"free", "new", "proven", "guaranteed", "instant", "exclusive",
"secret", "discover", "revolutionary", "breakthrough", "simple",
"easy", "fast", "powerful", "ultimate", "complete", "essential",
]
ACTION_VERBS = [
"build", "create", "get", "start", "grow", "reduce", "cut", "save",
"boost", "increase", "automate", "ship", "hire", "scale", "stop",
"eliminate", "transform", "unlock", "achieve", "discover", "join",
]
VAGUE_WORDS = [
"innovative", "cutting-edge", "best-in-class", "world-class",
"industry-leading", "state-of-the-art", "next-generation",
"synergy", "holistic", "leverage", "optimize", "solutions",
"ecosystem", "paradigm",
]
WE_PATTERNS = re.compile(r"^(we |our |at \w+)", re.IGNORECASE)
YOU_PATTERNS = re.compile(r"\b(you|your|you're)\b", re.IGNORECASE)
def score_headline(headline: str) -> dict:
words = headline.split()
lower = headline.lower()
result = {
"headline": headline,
"word_count": len(words),
"char_count": len(headline),
"scores": {},
"strengths": [],
"weaknesses": [],
"suggestions": [],
}
total = 100
# Length
wc = len(words)
if 6 <= wc <= 12:
result["scores"]["length"] = 95
result["strengths"].append("Optimal headline length (6-12 words).")
elif 4 <= wc <= 15:
result["scores"]["length"] = 75
elif wc < 4:
result["scores"]["length"] = 50
result["weaknesses"].append("Headline may be too short to convey full value.")
total -= 8
else:
result["scores"]["length"] = 45
result["weaknesses"].append("Headline is too long. Cut to 6-12 words.")
total -= 12
# Specificity
has_number = bool(re.search(r"\d+", headline))
has_specific_metric = bool(re.search(r"\d+%|\d+ (hours|minutes|days|weeks|x|teams|customers)", headline, re.IGNORECASE))
has_timeframe = bool(re.search(r"in \d+ (minutes|hours|days|weeks|months)", headline, re.IGNORECASE))
specificity_score = 40
if has_specific_metric:
specificity_score += 35
result["strengths"].append("Specific metric makes claim believable.")
if has_number:
specificity_score += 15
if has_timeframe:
specificity_score += 10
result["strengths"].append("Timeframe adds credibility.")
found_vague = [w for w in VAGUE_WORDS if w in lower]
if found_vague:
specificity_score -= 20
result["weaknesses"].append(f"Vague words: {', '.join(found_vague)}. Replace with specifics.")
total -= 10
result["scores"]["specificity"] = min(100, specificity_score)
# Benefit clarity
has_action = any(lower.startswith(v) or f" {v} " in lower for v in ACTION_VERBS)
has_benefit = bool(re.search(r"(without|in \d|save|reduce|increase|grow|cut|boost|get|achieve)", lower))
has_pain_removal = bool(re.search(r"(without|no |stop |eliminate|never )", lower))
benefit_score = 40
if has_action:
benefit_score += 20
result["strengths"].append("Starts with or contains an action verb.")
if has_benefit:
benefit_score += 25
if has_pain_removal:
benefit_score += 15
result["strengths"].append("Includes pain removal framing (strong for conversion).")
result["scores"]["benefit_clarity"] = min(100, benefit_score)
# Customer focus
starts_with_we = bool(WE_PATTERNS.match(headline))
has_you = bool(YOU_PATTERNS.search(headline))
if starts_with_we:
result["weaknesses"].append("Starts with 'We/Our' -- lead with the customer's world instead.")
total -= 8
if has_you:
result["strengths"].append("Uses 'you/your' -- customer-focused language.")
# Emotional resonance
power_found = [w for w in POWER_WORDS if w in lower]
emotional_score = 50
if power_found:
emotional_score += min(30, len(power_found) * 10)
if "?" in headline:
emotional_score += 10
result["strengths"].append("Question format creates curiosity.")
result["scores"]["emotional_pull"] = min(100, emotional_score)
# Overall
weights = {"length": 0.15, "specificity": 0.30, "benefit_clarity": 0.35, "emotional_pull": 0.20}
weighted = sum(result["scores"].get(k, 50) * w for k, w in weights.items())
total = min(100, max(0, int(weighted)))
result["overall_score"] = total
result["grade"] = "A" if total >= 85 else "B" if total >= 70 else "C" if total >= 55 else "D" if total >= 40 else "F"
if not result["suggestions"]:
if total < 70:
result["suggestions"].append("Try formula: '[Achieve outcome] without [pain point]'")
result["suggestions"].append("Add a specific number or metric for credibility.")
else:
result["suggestions"].append("Test 2-3 variants of this headline via A/B testing.")
return result
def format_human(results: list) -> str:
lines = ["\n" + "=" * 60, " HEADLINE SCORER", "=" * 60]
for r in results:
lines.append(f"\n \"{r['headline']}\"")
lines.append(f" Score: {r['overall_score']}/100 ({r['grade']}) | {r['word_count']} words, {r['char_count']} chars")
for k, v in r["scores"].items():
lines.append(f" {k.replace('_', ' ').title()}: {v}/100")
for s in r["strengths"]:
lines.append(f" + {s}")
for w in r["weaknesses"]:
lines.append(f" - {w}")
for s in r["suggestions"]:
lines.append(f" > {s}")
lines.append("-" * 60)
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(description="Score marketing headlines for conversion potential.")
parser.add_argument("headline", nargs="?")
parser.add_argument("--file", "-f")
parser.add_argument("--json", action="store_true", dest="json_output")
args = parser.parse_args()
headlines = []
if args.file:
with open(args.file) as f:
headlines = [l.strip() for l in f if l.strip()]
elif args.headline:
headlines = [args.headline]
else:
parser.print_help()
sys.exit(1)
results = [score_headline(h) for h in headlines]
if args.json_output:
print(json.dumps(results if len(results) > 1 else results[0], indent=2))
else:
print(format_human(results))
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Page Copy Auditor
Audits marketing page copy for conversion principles:
benefit clarity, specificity, customer focus, CTA strength,
objection handling, and social proof.
Usage:
python page_copy_auditor.py page.txt
python page_copy_auditor.py page.html --json
"""
import argparse
import json
import re
import sys
from pathlib import Path
HTML_TAG = re.compile(r"<[^>]+>")
def audit_copy(text: str) -> dict:
# Strip HTML if present
plain = HTML_TAG.sub(" ", text)
plain = re.sub(r"\s+", " ", plain).strip()
sentences = [s.strip() for s in re.split(r"[.!?]+", plain) if s.strip()]
words = plain.split()
word_count = len(words)
result = {
"word_count": word_count,
"sentence_count": len(sentences),
"scores": {},
"checks": [],
"issues": [],
"suggestions": [],
}
# 1. Customer focus (you vs we)
you_count = len(re.findall(r"\b(you|your|you're|yourself)\b", plain, re.IGNORECASE))
we_count = len(re.findall(r"\b(we|our|we're|us)\b", plain, re.IGNORECASE))
ratio = you_count / max(we_count, 1)
if ratio >= 2:
result["checks"].append({"name": "Customer Focus", "status": "PASS", "detail": f"You/Your: {you_count}, We/Our: {we_count} (ratio: {ratio:.1f}:1)"})
result["scores"]["customer_focus"] = 90
elif ratio >= 1:
result["checks"].append({"name": "Customer Focus", "status": "OK", "detail": f"You: {you_count}, We: {we_count}"})
result["scores"]["customer_focus"] = 65
else:
result["checks"].append({"name": "Customer Focus", "status": "FAIL", "detail": f"We/Our ({we_count}) outnumbers You/Your ({you_count})"})
result["scores"]["customer_focus"] = 35
result["issues"].append("Copy is company-focused. Rewrite to lead with 'you' and the customer's world.")
# 2. Specificity
numbers = re.findall(r"\d+", plain)
specific_metrics = re.findall(r"\d+%|\d+x|\$\d+|\d+ (hours|minutes|days|teams|customers|companies)", plain, re.IGNORECASE)
has_named_companies = bool(re.search(r"(Stripe|Notion|Slack|Linear|Figma|Shopify|HubSpot|\w+\.com)", plain))
specificity = 30
if len(specific_metrics) >= 3:
specificity = 90
elif len(specific_metrics) >= 1:
specificity = 65
if has_named_companies:
specificity += 10
if len(numbers) == 0:
result["issues"].append("No numbers or metrics found. Add specific data for credibility.")
result["scores"]["specificity"] = min(100, specificity)
result["checks"].append({"name": "Specificity", "status": "PASS" if specificity >= 70 else "WARN", "detail": f"{len(specific_metrics)} specific metrics, {len(numbers)} numbers total"})
# 3. Social proof
social_proof_patterns = [
re.compile(r"(trusted by|used by|join|loved by)\s+\d+", re.IGNORECASE),
re.compile(r"\d+\s*(teams|companies|customers|users|businesses)", re.IGNORECASE),
re.compile(r"(testimonial|review|rating|stars?|4\.\d|5\.0)", re.IGNORECASE),
re.compile(r'".+"\s*[-—]\s*\w+', re.IGNORECASE), # quoted testimonial
]
proof_found = sum(1 for p in social_proof_patterns if p.search(plain))
if proof_found >= 2:
result["scores"]["social_proof"] = 85
result["checks"].append({"name": "Social Proof", "status": "PASS", "detail": f"{proof_found} social proof elements found"})
elif proof_found == 1:
result["scores"]["social_proof"] = 55
result["checks"].append({"name": "Social Proof", "status": "WARN", "detail": "Limited social proof"})
result["suggestions"].append("Add more social proof: testimonials with names, metrics, and specific outcomes.")
else:
result["scores"]["social_proof"] = 20
result["checks"].append({"name": "Social Proof", "status": "FAIL", "detail": "No social proof detected"})
result["issues"].append("No social proof found. Add testimonials, customer counts, or review scores.")
# 4. CTA presence
cta_patterns = [
re.compile(r"(start|get|try|book|sign up|create|download|claim|unlock|begin|join)\b", re.IGNORECASE),
]
cta_found = sum(1 for p in cta_patterns if p.search(plain))
cta_mentions = len(re.findall(r"(start|get started|try free|book|sign up|free trial)", plain, re.IGNORECASE))
if cta_mentions >= 2:
result["scores"]["cta_presence"] = 85
result["checks"].append({"name": "CTA Presence", "status": "PASS", "detail": f"{cta_mentions} CTA mentions"})
elif cta_mentions >= 1:
result["scores"]["cta_presence"] = 60
result["checks"].append({"name": "CTA Presence", "status": "WARN", "detail": "Single CTA -- add 2-3 throughout page"})
else:
result["scores"]["cta_presence"] = 25
result["checks"].append({"name": "CTA Presence", "status": "FAIL", "detail": "No clear CTA found"})
result["issues"].append("No clear CTA detected. Add action-oriented CTAs throughout the page.")
# 5. Objection handling
objection_patterns = [
re.compile(r"(no credit card|cancel anytime|money.back|guarantee|refund|free trial|risk.free)", re.IGNORECASE),
re.compile(r"(faq|frequently asked|common questions)", re.IGNORECASE),
re.compile(r"(secure|encrypted|privacy|gdpr|soc 2|iso|compliant)", re.IGNORECASE),
]
objection_count = sum(1 for p in objection_patterns if p.search(plain))
if objection_count >= 2:
result["scores"]["objection_handling"] = 85
elif objection_count == 1:
result["scores"]["objection_handling"] = 55
result["suggestions"].append("Add risk reversal near CTAs: 'No credit card required' or 'Cancel anytime'.")
else:
result["scores"]["objection_handling"] = 20
result["issues"].append("No objection handling found. Add FAQs, guarantees, or risk reversal copy.")
result["checks"].append({"name": "Objection Handling", "status": "PASS" if objection_count >= 2 else "WARN" if objection_count == 1 else "FAIL", "detail": f"{objection_count} objection-handling elements"})
# 6. Readability
avg_words_per_sentence = word_count / max(len(sentences), 1)
if avg_words_per_sentence <= 15:
result["scores"]["readability"] = 90
elif avg_words_per_sentence <= 20:
result["scores"]["readability"] = 70
else:
result["scores"]["readability"] = 45
result["suggestions"].append("Sentences are too long. Break into shorter, punchier sentences.")
# Overall
weights = {"customer_focus": 0.20, "specificity": 0.20, "social_proof": 0.20, "cta_presence": 0.15, "objection_handling": 0.15, "readability": 0.10}
overall = sum(result["scores"].get(k, 50) * w for k, w in weights.items())
result["overall_score"] = round(overall)
result["grade"] = "A" if overall >= 85 else "B" if overall >= 70 else "C" if overall >= 55 else "D" if overall >= 40 else "F"
return result
def format_human(result: dict) -> str:
lines = ["\n" + "=" * 60, " PAGE COPY AUDITOR", "=" * 60]
lines.append(f"\n Score: {result['overall_score']}/100 ({result['grade']}) | {result['word_count']} words, {result['sentence_count']} sentences")
lines.append(f"\n Checks:")
for c in result["checks"]:
icon = {"PASS": "+", "WARN": "!", "FAIL": "X", "OK": "~"}
lines.append(f" [{icon.get(c['status'], '?')}] {c['name']}: {c['detail']}")
lines.append(f"\n Scores:")
for k, v in sorted(result["scores"].items(), key=lambda x: -x[1]):
lines.append(f" {k.replace('_', ' ').title():<20} {v}/100")
if result["issues"]:
lines.append(f"\n Issues:")
for i in result["issues"]:
lines.append(f" X {i}")
if result["suggestions"]:
lines.append(f"\n Suggestions:")
for s in result["suggestions"]:
lines.append(f" > {s}")
lines.append("")
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(description="Audit marketing page copy for conversion potential.")
parser.add_argument("file", help="Text or HTML file to audit")
parser.add_argument("--json", action="store_true", dest="json_output")
args = parser.parse_args()
try:
text = Path(args.file).read_text()
except FileNotFoundError:
print(f"Error: {args.file} not found", file=sys.stderr)
sys.exit(1)
result = audit_copy(text)
if args.json_output:
print(json.dumps(result, indent=2))
else:
print(format_human(result))
if __name__ == "__main__":
main()
Related skills
FAQ
Which frameworks does it use?
PAS, AIDA, BAB, 4 Ps, and QUEST, matched to page type.
What page types does it cover?
Homepages, landing pages, pricing pages, feature pages, and product pages.