# SEO Fix Priority Engine — Turn Audit Issues into Action (`riad_h/seo-fix-priority-engine`) Actor

Turn SEO audit issues into an actionable fix roadmap. Prioritize technical SEO problems by impact, affected pages, and estimated fix effort.

- **URL**: https://apify.com/riad\_h/seo-fix-priority-engine.md
- **Developed by:** [Riad Hossain](https://apify.com/riad_h) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## SEO Fix Priority Engine — Turn Audit Issues into Action

> Turn a confusing SEO audit containing hundreds or thousands of issues into a prioritized action plan. This Actor accepts SEO issues from any crawler, normalizes them, estimates impact and effort, and generates an actionable fix roadmap with quick-win identification.

### The Problem This Solves

You ran an SEO audit. It found 500 issues. Now what?

Generic auditors list every problem but don't tell you which ones matter most. You're left wondering:

- Which issues should I fix first?
- Which problems affect the most pages?
- What are the quick wins?
- What can wait?

**This Actor answers those questions.**

### Who Is It For?

- **SEO agencies** — Import audit results → generate priority roadmap → share top fixes with client
- **Website owners** — Upload issue list → understand what matters first → fix quick wins
- **Developers** — Get a prioritized task list with effort estimates
- **Automated pipelines** — SEO crawler → dataset export → this Actor → prioritized dataset

### How It Works

```
SEO Issues (from any source)
       ↓
Input Validation & Normalization
       ↓
Synonym Mapping (404 internal links → broken_internal_links)
       ↓
Duplicate Grouping (sum affected pages)
       ↓
Impact Estimation (LOW / MEDIUM / HIGH / CRITICAL)
       ↓
Effort Estimation (LOW / MEDIUM / HIGH)
       ↓
Priority Scoring (Impact × log10(pages+1) ÷ Effort)
       ↓
Quick-Win Detection (HIGH impact + LOW effort)
       ↓
Recommendation Generation
       ↓
Ranked Output + Executive Summary
```

### Supported Issue Types (22)

| Category | Issue Types |
|----------|------------|
| **Links** | broken\_internal\_links, broken\_external\_links |
| **Redirects** | redirect\_chains, redirect\_loops |
| **Titles** | missing\_title, duplicate\_title, title\_too\_long, title\_too\_short |
| **Meta** | missing\_meta\_description, duplicate\_meta\_description |
| **Headings** | missing\_h1, multiple\_h1 |
| **Canonical** | canonical\_error, missing\_canonical |
| **Content** | duplicate\_content |
| **Indexing** | noindex\_problem, robots\_txt\_problem |
| **Performance** | slow\_page, large\_page |
| **Images** | missing\_alt\_text |
| **Architecture** | orphan\_page, internal\_linking\_problem |
| **Structured Data** | structured\_data\_error |

### Priority Methodology

#### Priority Formula

```
Priority Score = (Impact Weight × log10(affectedPages + 1) ÷ Effort Weight) / MAX_RAW_SCORE × 100
```

#### Impact Weights

| Level | Weight | Description |
|-------|--------|-------------|
| CRITICAL | 10 | Can remove pages from search results entirely |
| HIGH | 6 | Significant negative effect on SEO |
| MEDIUM | 3 | Moderate effect, should be addressed |
| LOW | 1 | Minor or cosmetic issue |

#### Effort Weights

| Level | Weight | Description |
|-------|--------|-------------|
| LOW | 1 | Quick fix, often sitewide template change |
| MEDIUM | 2 | Requires individual page review |
| HIGH | 4 | Significant development work |

#### Priority Labels

| Score | Label | Meaning |
|-------|-------|---------|
| 75-100 | CRITICAL | Fix immediately |
| 50-74 | HIGH | Fix soon |
| 25-49 | MEDIUM | Plan to address |
| 0-24 | LOW | Low priority |

#### Quick Wins

Quick wins are issues with **HIGH or CRITICAL impact** AND **LOW effort** — the highest-ROI fixes.

> **Note:** Priority scores are decision-support heuristics, not guarantees of search ranking improvements.

### Input

```json
{
  "seoIssues": [
    {"type": "broken_internal_links", "affectedPages": 47},
    {"type": "missing_meta_description", "affectedPages": 132},
    {"type": "canonical_error", "affectedPages": 12},
    {"type": "missing_alt_text", "affectedPages": 300},
    {"type": "redirect_loops", "affectedPages": 4},
    {"type": "orphan_page", "affectedPages": 7}
  ],
  "analysisMode": "balanced",
  "groupSimilarIssues": true,
  "includeRecommendations": true,
  "siteName": "Example Site"
}
```

#### Alternative Input Formats

The Actor normalizes diverse field names:

| Canonical Field | Accepted Alternatives |
|-----------------|-----------------------|
| `type` | `issue`, `issue_type`, `problem`, `category` |
| `affectedPages` | `affected_pages`, `count`, `pages` |
| `seoIssues` | `issues` |

#### Synonym Normalization

Different tools use different names. The Actor maps them:

| Input | Normalized To |
|-------|---------------|
| "Broken Internal Links" | `broken_internal_links` |
| "404 internal links" | `broken_internal_links` |
| "Internal broken URL" | `broken_internal_links` |
| "Missing meta description" | `missing_meta_description` |
| "No meta description" | `missing_meta_description` |

### Output

The Actor pushes structured items to the dataset:

#### 1. Analysis Summary (first item)

```json
{
  "type": "analysis_summary",
  "summary": {
    "totalIssueRecords": 6,
    "recognizedIssues": 6,
    "unknownIssues": 0,
    "totalAffectedPages": 502,
    "quickWinCount": 2
  },
  "executiveSummary": {
    "overview": "The audit found 502 affected pages across 6 issue records...",
    "topPriority": "The highest priority is 'Broken Internal Links'...",
    "quickWinsText": "The best quick wins are:\n1. Broken Internal Links\n2. Missing Title Tags"
  },
  "topPriorities": [...],
  "quickWins": [...]
}
```

#### 2. Prioritized Issues (subsequent items)

```json
{
  "type": "prioritized_issue",
  "rank": 1,
  "issueType": "broken_internal_links",
  "displayName": "Broken Internal Links",
  "affectedPages": 47,
  "impact": {"level": "HIGH", "weight": 6},
  "effort": {"level": "LOW", "weight": 1},
  "priorityScore": 68.5,
  "priority": "HIGH",
  "quickWin": true,
  "recommendedAction": "Update links to valid URLs, remove obsolete links, or add 301 redirects...",
  "whyItMatters": "Broken internal links waste crawl budget...",
  "explanation": "Internal links point to pages that return a 4xx or 5xx error..."
}
```

#### 3. Unknown Issues

Issues not in the taxonomy are preserved with `priority: "REVIEW_REQUIRED"`:

```json
{
  "type": "unknown_issue",
  "issueType": "javascript_hydration_warning",
  "priority": "REVIEW_REQUIRED",
  "note": "This issue type is not in the known taxonomy. Manual review recommended."
}
```

### Performance

| Issues | Time | Per Issue |
|--------|------|-----------|
| 10 | 0.2ms | 0.02ms |
| 100 | 0.8ms | 0.008ms |
| 1,000 | 7.4ms | 0.007ms |
| 10,000 | 86.4ms | 0.009ms |

### Pricing

**Pay-per-event: `$0.25` per `seo-analysis` event**

Each event = one complete SEO issue prioritization report.

**Example costs:**

- 1 analysis (up to 10,000 issues) = $0.25
- 10 analyses = $2.50
- 100 analyses = $25.00

### Limitations

- **Does not crawl websites** — accepts issues you provide from another tool
- **Deterministic** — uses keyword/pattern matching, not AI (this is a feature: explainable, fast, free of API costs)
- **English issue names** — synonym dictionary is English-based
- **22 issue types** — additional types can be added by extending `src/rules/seo_issue_rules.py`

### Privacy

- No data sent to external APIs
- No credentials stored
- All processing within Apify platform

### License

MIT

# Actor input Schema

## `seoIssues` (type: `array`):

List of SEO issues to prioritize. Each issue must have a 'type' (or 'issue', 'issue\_type', 'problem', 'category') and optionally 'affectedPages' (or 'count', 'pages').

## `analysisMode` (type: `string`):

Analysis depth. Fast = priority scores only. Balanced = includes recommendations. Deep = same as balanced in v1.

## `groupSimilarIssues` (type: `boolean`):

Whether to group duplicate or similar issues after normalization (e.g. 'Broken Internal Links' + '404 internal links' → one entry).

## `includeRecommendations` (type: `boolean`):

Whether to include actionable recommendations in the output.

## `siteName` (type: `string`):

Optional site name for the analysis report.

## Actor input object example

```json
{
  "seoIssues": [
    {
      "type": "broken_internal_links",
      "affectedPages": 47
    },
    {
      "type": "missing_meta_description",
      "affectedPages": 132
    },
    {
      "type": "canonical_error",
      "affectedPages": 12
    },
    {
      "type": "missing_alt_text",
      "affectedPages": 300
    },
    {
      "type": "redirect_loops",
      "affectedPages": 4
    },
    {
      "type": "orphan_page",
      "affectedPages": 7
    }
  ],
  "analysisMode": "balanced",
  "groupSimilarIssues": true,
  "includeRecommendations": true,
  "siteName": ""
}
```

# Actor output Schema

## `results` (type: `string`):

View all prioritized SEO issues with scores, recommendations, and quick-win flags.

## `run_details` (type: `string`):

Full run metadata including input, output, and logs.

# 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 = {
    "seoIssues": [
        {
            "type": "broken_internal_links",
            "affectedPages": 47
        },
        {
            "type": "missing_meta_description",
            "affectedPages": 132
        },
        {
            "type": "canonical_error",
            "affectedPages": 12
        },
        {
            "type": "missing_alt_text",
            "affectedPages": 300
        },
        {
            "type": "redirect_loops",
            "affectedPages": 4
        },
        {
            "type": "orphan_page",
            "affectedPages": 7
        }
    ],
    "analysisMode": "balanced",
    "groupSimilarIssues": true,
    "includeRecommendations": true,
    "siteName": ""
};

// Run the Actor and wait for it to finish
const run = await client.actor("riad_h/seo-fix-priority-engine").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 = {
    "seoIssues": [
        {
            "type": "broken_internal_links",
            "affectedPages": 47,
        },
        {
            "type": "missing_meta_description",
            "affectedPages": 132,
        },
        {
            "type": "canonical_error",
            "affectedPages": 12,
        },
        {
            "type": "missing_alt_text",
            "affectedPages": 300,
        },
        {
            "type": "redirect_loops",
            "affectedPages": 4,
        },
        {
            "type": "orphan_page",
            "affectedPages": 7,
        },
    ],
    "analysisMode": "balanced",
    "groupSimilarIssues": True,
    "includeRecommendations": True,
    "siteName": "",
}

# Run the Actor and wait for it to finish
run = client.actor("riad_h/seo-fix-priority-engine").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 '{
  "seoIssues": [
    {
      "type": "broken_internal_links",
      "affectedPages": 47
    },
    {
      "type": "missing_meta_description",
      "affectedPages": 132
    },
    {
      "type": "canonical_error",
      "affectedPages": 12
    },
    {
      "type": "missing_alt_text",
      "affectedPages": 300
    },
    {
      "type": "redirect_loops",
      "affectedPages": 4
    },
    {
      "type": "orphan_page",
      "affectedPages": 7
    }
  ],
  "analysisMode": "balanced",
  "groupSimilarIssues": true,
  "includeRecommendations": true,
  "siteName": ""
}' |
apify call riad_h/seo-fix-priority-engine --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,riad_h/seo-fix-priority-engine"
        }
    }
}

```

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/VFVOtvcqSb8Xn2C4n/builds/jLpsu3zpVtK4esYUL/openapi.json
