# How OpportunityScorer Calculates 8-Factor Weighted Scoring for SEO Opportunities

> Learn how OpportunityScorer calculates 8-factor weighted scoring for SEO opportunities. Discover how it normalizes metrics and applies weights for prioritized insights.

- Repository: [Craig/seomachine](https://github.com/TheCraigHewitt/seomachine)
- Tags: deep-dive
- Published: 2026-03-12

---

**OpportunityScorer calculates SEO opportunity scores by normalizing eight distinct metrics—Search Volume, Current Position, Search Intent, Competition, Cluster Relevance, CTR, Freshness, and Trend—then applying specific weights ranging from 5% to 25% to generate a composite 0-100 score for prioritization.**

TheCraigHewitt/seomachine is an open-source SEO analysis platform that uses data-driven algorithms to identify high-value content opportunities. At the core of its prioritization engine lies the **8-factor weighted scoring algorithm** implemented in the `OpportunityScorer` class, which transforms raw search metrics into actionable priority scores.

## The 8-Factor Weighted Scoring Methodology

The scoring system implemented in [`data_sources/modules/opportunity_scorer.py`](https://github.com/TheCraigHewitt/seomachine/blob/main/data_sources/modules/opportunity_scorer.py) follows a four-step pipeline: raw metric collection, normalization, weight application, and aggregation.

### Step 1: Raw Metric Collection

For each keyword or page under evaluation, the system gathers raw data across eight distinct factors:

- **Search Volume** (25% weight) – Average monthly search queries for the target keyword.
- **Current Position** (20% weight) – Existing SERP ranking of the target URL.
- **Search Intent** (20% weight) – Classification as commercial, informational, transactional, or navigational.
- **Competition** (15% weight) – SEO difficulty score or density of competing pages.
- **Cluster Relevance** (10% weight) – Alignment with existing topic clusters in the content architecture.
- **Click-Through Rate (CTR)** (5% weight) – Expected CTR based on current position.
- **Freshness** (5% weight) – Recency of top-ranking content in days.
- **Trend** (5% weight) – Momentum of search interest over recent weeks or months.

### Step 2: Normalization Process

Raw values cannot be combined directly due to differing scales and units. The `OpportunityScorer` transforms each metric to a **0-1 normalized scale** using factor-specific methods:

- **Log-scaling** for high-variance metrics like Search Volume.
- **Inverse scaling** for competitive factors where lower values indicate better opportunity (e.g., Competition).
- **Linear scaling** for bounded metrics like Current Position (where position 1 is best) and Cluster Relevance.

### Step 3: Weight Application and Aggregation

After normalization, each factor is multiplied by its predefined weight. The weighted values are summed to produce a final opportunity score ranging from 0 to 100.

The calculation follows this formula:

```

Score = (
    Volume_norm × 0.25 +
    Position_norm × 0.20 +
    Intent_norm × 0.20 +
    Competition_norm × 0.15 +
    Cluster_norm × 0.10 +
    CTR_norm × 0.05 +
    Freshness_norm × 0.05 +
    Trend_norm × 0.05
) × 100

```

## Implementation in opportunity_scorer.py

The core logic resides in [`data_sources/modules/opportunity_scorer.py`](https://github.com/TheCraigHewitt/seomachine/blob/main/data_sources/modules/opportunity_scorer.py), where the `OpportunityScorer` class encapsulates the normalization and weighting pipeline. The `calculate()` method orchestrates the transformation of raw metrics into the final priority score.

```python

# Example: Using the Opportunity Scorer

from data_sources.modules.opportunity_scorer import OpportunityScorer

# Raw metrics collected from the various data sources

metrics = {
    "volume": 12000,          # monthly searches

    "position": 12,           # current SERP rank

    "intent": "commercial",   # classified intent

    "competition": 0.35,      # difficulty score (0-1)

    "cluster_score": 0.8,     # relevance to existing cluster

    "ctr": 0.12,              # expected click-through rate

    "freshness": 30,          # days since newest top result

    "trend": 1.15             # 15% upward trend

}

scorer = OpportunityScorer()
opportunity_score = scorer.calculate(metrics)

print(f"Opportunity score: {opportunity_score:.2f}")

```

The `calculate` method internally normalizes each metric, applies the weights listed above, and returns the aggregated score.

## Supporting Data Sources

The `OpportunityScorer` depends on specialized modules to supply raw metrics:

- **[`data_sources/modules/keyword_analyzer.py`](https://github.com/TheCraigHewitt/seomachine/blob/main/data_sources/modules/keyword_analyzer.py)** – Provides Search Volume and Competition data.
- **[`data_sources/modules/search_intent_analyzer.py`](https://github.com/TheCraigHewitt/seomachine/blob/main/data_sources/modules/search_intent_analyzer.py)** – Classifies intent categories.
- **[`data_sources/modules/content_length_comparator.py`](https://github.com/TheCraigHewitt/seomachine/blob/main/data_sources/modules/content_length_comparator.py)** – Supplies Freshness and Trend metrics by analyzing top-ranking content.

These modules work together to ensure the scorer receives normalized, accurate inputs for the 8-factor calculation.

## Summary

- **OpportunityScorer** implements an 8-factor weighted algorithm in [`data_sources/modules/opportunity_scorer.py`](https://github.com/TheCraigHewitt/seomachine/blob/main/data_sources/modules/opportunity_scorer.py) to prioritize SEO opportunities.
- The eight factors are **Search Volume** (25%), **Current Position** (20%), **Search Intent** (20%), **Competition** (15%), **Cluster Relevance** (10%), **CTR** (5%), **Freshness** (5%), and **Trend** (5%).
- Raw metrics undergo **normalization** (log-scaling, inverse scaling, or linear scaling) before weights are applied.
- The final score ranges from **0 to 100**, enabling data-driven prioritization of high-ROI content opportunities.

## Frequently Asked Questions

### What are the 8 factors used in OpportunityScorer?

The eight factors are Search Volume, Current Position, Search Intent, Competition, Cluster Relevance, Click-Through Rate (CTR), Freshness, and Trend. Each factor contributes a specific percentage to the final score, with Volume carrying the highest weight at 25% and CTR, Freshness, and Trend each contributing 5%.

### How does OpportunityScorer normalize metrics?

The scorer uses factor-specific normalization methods to transform raw values onto a 0-1 scale. It applies log-scaling for high-variance metrics like Search Volume, inverse scaling for competitive factors where lower values are better (such as Competition), and linear scaling for bounded metrics like Current Position and Cluster Relevance.

### Where is the scoring logic implemented in the codebase?

The core scoring logic resides in [`data_sources/modules/opportunity_scorer.py`](https://github.com/TheCraigHewitt/seomachine/blob/main/data_sources/modules/opportunity_scorer.py), specifically within the `OpportunityScorer` class and its `calculate()` method. This module orchestrates the normalization pipeline and applies the weighted aggregation formula to produce the final 0-100 opportunity score.

### How can I customize the weights in OpportunityScorer?

To modify the default weights, you would edit the weight constants defined in [`data_sources/modules/opportunity_scorer.py`](https://github.com/TheCraigHewitt/seomachine/blob/main/data_sources/modules/opportunity_scorer.py) before the calculation step. The current implementation uses fixed percentages (Volume 25%, Position 20%, Intent 20%, Competition 15%, Cluster 10%, and 5% each for CTR, Freshness, and Trend), but you can adjust these values to align with your specific SEO strategy or market conditions.