Technical SEO Audit
Comprehensive technical SEO audit workflow that analyzes website health, performance, and optimization opportunities
Workflow Information
ID: technical_seo_audit_v2
Namespace: default
Version: 2.0.0
Created: 2025-07-07
Updated: 2025-07-07
Tasks: 11
Quick Actions
Inputs
| Name | Type | Required | Default |
|---|---|---|---|
target_url |
string | Required | None |
audit_depth |
string | Optional |
standard
|
crawl_limit |
integer | Optional |
50
|
Outputs
| Name | Type | Source |
|---|---|---|
score |
string | Overall SEO health score (0-100) |
audit_report |
string | Complete Technical SEO Audit Report |
critical_issues |
string | List of critical issues found |
recommendations |
string | AI-generated recommendations |
Tasks
parse_url
scriptNo description
analyze_page
mcpNo description
parse_content
mcpNo description
get_serp_data
mcpNo description
domain_overview
mcpNo description
ranked_keywords
mcpNo description
backlink_analysis
mcpNo description
process_audit_data
scriptNo description
generate_recommendations
ai_agentNo description
compile_report
scriptNo description
store_results
storageNo description
YAML Source
id: technical_seo_audit_v2
name: Technical SEO Audit
tasks:
- id: parse_url
type: script
script: "import json\nfrom urllib.parse import urlparse\nimport os\n\ntarget_url\
\ = os.environ.get('target_url', '')\nparsed = urlparse(target_url)\n\nresult\
\ = {\n \"domain\": parsed.netloc,\n \"scheme\": parsed.scheme,\n \"\
path\": parsed.path or \"/\",\n \"base_url\": f\"{parsed.scheme}://{parsed.netloc}\"\
,\n \"is_homepage\": parsed.path in [\"\", \"/\"]\n}\n\nprint(f\"__OUTPUTS__\
\ {json.dumps(result)}\")\n"
timeout_seconds: 10
- id: analyze_page
type: mcp
tool_name: on_page_instant_pages
depends_on:
- parse_url
retry_policy:
max_attempts: 3
initial_interval: 5
deployment_id: pod-ow0pvk2h
tool_arguments:
url: ${target_url}
accept_language: en-US
enable_javascript: true
timeout_seconds: 120
- id: parse_content
type: mcp
tool_name: on_page_content_parsing
depends_on:
- parse_url
retry_policy:
max_attempts: 2
deployment_id: pod-ow0pvk2h
tool_arguments:
url: ${target_url}
enable_javascript: true
timeout_seconds: 90
- id: get_serp_data
type: mcp
when: audit_depth != 'basic'
tool_name: serp_organic_live_advanced
depends_on:
- analyze_page
retry_policy:
max_attempts: 2
deployment_id: pod-ow0pvk2h
tool_arguments:
depth: 10
keyword: ${parse_content.items[0].meta.title || parse_url.domain}
language_code: en
location_name: United States
search_engine: google
timeout_seconds: 60
- id: domain_overview
type: mcp
when: audit_depth != 'basic'
tool_name: dataforseo_labs_google_domain_rank_overview
depends_on:
- parse_url
retry_policy:
max_attempts: 2
deployment_id: pod-ow0pvk2h
tool_arguments:
target: ${parse_url.domain}
language_code: en
location_name: United States
timeout_seconds: 90
- id: ranked_keywords
type: mcp
when: audit_depth == 'comprehensive'
tool_name: dataforseo_labs_google_ranked_keywords
depends_on:
- parse_url
deployment_id: pod-ow0pvk2h
tool_arguments:
limit: 20
target: ${parse_url.domain}
language_code: en
location_name: United States
timeout_seconds: 120
- id: backlink_analysis
type: mcp
when: audit_depth == 'comprehensive'
tool_name: backlinks_summary
depends_on:
- parse_url
deployment_id: pod-ow0pvk2h
tool_arguments:
target: ${parse_url.domain}
timeout_seconds: 90
- id: process_audit_data
type: script
script: "import json\nimport os\nfrom datetime import datetime\n\n# Get data from\
\ previous tasks\ntry:\n page_analysis = json.loads(os.environ.get('analyze_page',\
\ '{}'))\n content_data = json.loads(os.environ.get('parse_content', '{}'))\n\
\ domain_overview = json.loads(os.environ.get('domain_overview', '{}'))\nexcept:\n\
\ page_analysis = {}\n content_data = {}\n domain_overview = {}\n\n#\
\ Extract key metrics with safe navigation\ntry:\n on_page_result = page_analysis.get('tasks',\
\ [{}])[0].get('result', [{}])[0]\n items = on_page_result.get('items', [{}])[0]\n\
except:\n items = {}\n\n# Basic metrics\nmetrics = {\n \"url\": items.get('url',\
\ ''),\n \"status_code\": items.get('status_code', 0),\n \"load_time\":\
\ items.get('page_timing', {}).get('time_to_secure_connection', 0),\n \"size\"\
: items.get('size', 0),\n \"encoded_size\": items.get('encoded_size', 0),\n\
\ \"total_transfer_size\": items.get('total_transfer_size', 0),\n \"is_https\"\
: items.get('meta', {}).get('charset', {}).get('scheme', '') == 'https'\n}\n\n\
# SEO elements\nmeta = items.get('meta', {})\nhtags = meta.get('htags', {})\n\n\
seo_elements = {\n \"title\": meta.get('title', ''),\n \"title_length\"\
: meta.get('title_length', 0),\n \"description\": meta.get('description', ''),\n\
\ \"description_length\": meta.get('description_length', 0),\n \"canonical\"\
: meta.get('canonical', ''),\n \"robots\": meta.get('robots', ''),\n \"\
og_properties\": meta.get('open_graph', {}),\n \"h1_count\": len(htags.get('h1',\
\ [])),\n \"h2_count\": len(htags.get('h2', [])),\n \"images_without_alt\"\
: meta.get('images_without_alt', [])\n}\n\n# Technical checks\nchecks = items.get('checks',\
\ {})\n\n# Issues and warnings\nissues = []\nwarnings = []\n\n# Check for critical\
\ issues\nif metrics['status_code'] != 200:\n issues.append(f\"Page returns\
\ {metrics['status_code']} status code\")\n\nif not metrics['is_https']:\n \
\ issues.append(\"Site is not using HTTPS\")\n\nif not seo_elements['title']:\n\
\ issues.append(\"Missing page title\")\nelif seo_elements['title_length']\
\ > 60:\n warnings.append(f\"Title too long ({seo_elements['title_length']}\
\ chars, recommended: <60)\")\nelif seo_elements['title_length'] < 30:\n warnings.append(f\"\
Title too short ({seo_elements['title_length']} chars, recommended: 30-60)\")\n\
\nif not seo_elements['description']:\n issues.append(\"Missing meta description\"\
)\nelif seo_elements['description_length'] > 160:\n warnings.append(f\"Description\
\ too long ({seo_elements['description_length']} chars, recommended: <160)\")\n\
elif seo_elements['description_length'] < 120:\n warnings.append(f\"Description\
\ too short ({seo_elements['description_length']} chars, recommended: 120-160)\"\
)\n\nif seo_elements['h1_count'] == 0:\n issues.append(\"Missing H1 tag\")\n\
elif seo_elements['h1_count'] > 1:\n warnings.append(f\"Multiple H1 tags found\
\ ({seo_elements['h1_count']})\")\n\nif len(seo_elements['images_without_alt'])\
\ > 0:\n warnings.append(f\"{len(seo_elements['images_without_alt'])} images\
\ missing alt text\")\n\n# Performance warnings\nif metrics['load_time'] and metrics['load_time']\
\ > 3000:\n warnings.append(f\"Slow load time ({metrics['load_time']/1000:.1f}s)\"\
)\n\nif metrics['total_transfer_size'] and metrics['total_transfer_size'] > 3000000:\n\
\ warnings.append(f\"Large page size ({metrics['total_transfer_size']/1048576:.1f}MB)\"\
)\n\n# Domain metrics (if available)\ndomain_metrics = {}\nif domain_overview:\n\
\ try:\n domain_data = domain_overview.get('tasks', [{}])[0].get('result',\
\ [{}])[0]\n domain_metrics = {\n \"organic_keywords\": domain_data.get('metrics',\
\ {}).get('organic', {}).get('count', 0),\n \"organic_traffic\": domain_data.get('metrics',\
\ {}).get('organic', {}).get('etv', 0),\n \"paid_keywords\": domain_data.get('metrics',\
\ {}).get('paid', {}).get('count', 0),\n \"paid_traffic\": domain_data.get('metrics',\
\ {}).get('paid', {}).get('etv', 0)\n }\n except:\n pass\n\n\
# Compile audit results\naudit_results = {\n \"audit_date\": datetime.now().isoformat(),\n\
\ \"target_url\": os.environ.get('target_url'),\n \"metrics\": metrics,\n\
\ \"seo_elements\": seo_elements,\n \"technical_checks\": checks,\n \"\
domain_metrics\": domain_metrics,\n \"issues\": issues,\n \"warnings\":\
\ warnings,\n \"score\": max(0, 100 - len(issues) * 15 - len(warnings) * 5)\n\
}\n\nprint(f\"__OUTPUTS__ {json.dumps(audit_results)}\")\n"
depends_on:
- analyze_page
- parse_content
requirements:
- beautifulsoup4==4.12.2
timeout_seconds: 30
- id: generate_recommendations
type: ai_agent
prompt: 'Analyze this Technical SEO Audit data and provide actionable recommendations:
Audit Results:
${process_audit_data}
Provide:
1. Executive Summary (2-3 sentences)
2. Critical Issues to Fix Immediately
3. High Priority Recommendations
4. Quick Wins (easy fixes with high impact)
5. Long-term Optimization Opportunities
Format your response as structured JSON with these sections.
'
agent_type: analyst
depends_on:
- process_audit_data
model_client_id: seo_analyzer
timeout_seconds: 60
- id: compile_report
type: script
script: "import json\nimport os\nfrom datetime import datetime\n\naudit_data = json.loads(os.environ.get('process_audit_data',\
\ '{}'))\nrecommendations = json.loads(os.environ.get('generate_recommendations',\
\ '{}'))\n\n# Create comprehensive report\nreport = {\n \"report_metadata\"\
: {\n \"title\": \"Technical SEO Audit Report\",\n \"generated_at\"\
: datetime.now().isoformat(),\n \"target_url\": os.environ.get('target_url'),\n\
\ \"audit_depth\": os.environ.get('audit_depth', 'standard')\n },\n\
\ \"executive_summary\": {\n \"overall_score\": audit_data.get('score',\
\ 0),\n \"critical_issues\": len(audit_data.get('issues', [])),\n \
\ \"warnings\": len(audit_data.get('warnings', [])),\n \"summary\": recommendations.get('executive_summary',\
\ '')\n },\n \"technical_analysis\": {\n \"performance_metrics\"\
: audit_data.get('metrics', {}),\n \"seo_elements\": audit_data.get('seo_elements',\
\ {}),\n \"technical_checks\": audit_data.get('technical_checks', {}),\n\
\ \"domain_authority\": audit_data.get('domain_metrics', {})\n },\n\
\ \"issues_and_warnings\": {\n \"critical_issues\": audit_data.get('issues',\
\ []),\n \"warnings\": audit_data.get('warnings', [])\n },\n \"recommendations\"\
: recommendations,\n \"next_steps\": [\n \"Fix critical issues identified\
\ in the report\",\n \"Implement quick wins for immediate improvements\"\
,\n \"Plan long-term optimization based on recommendations\",\n \
\ \"Re-run audit after implementing changes to measure improvement\"\n ]\n\
}\n\nprint(f\"__OUTPUTS__ {json.dumps(report)}\")\n"
depends_on:
- process_audit_data
- generate_recommendations
timeout_seconds: 20
- id: store_results
data:
warnings: ${compile_report.executive_summary.warnings}
audit_date: ${execution.started_at}
target_url: ${target_url}
full_report: ${compile_report}
workflow_id: ${workflow.id}
execution_id: ${execution.id}
overall_score: ${compile_report.executive_summary.overall_score}
critical_issues: ${compile_report.executive_summary.critical_issues}
type: storage
table: seo_audit_results
operation: insert
depends_on:
- compile_report
inputs:
- name: target_url
type: string
required: true
validation:
pattern: ^https?://[\w\-\.]+(\.[\w\-]+)+.*$
description: The website URL to audit (e.g., https://example.com)
- enum:
- basic
- standard
- comprehensive
name: audit_depth
type: string
default: standard
description: 'Depth of audit: basic, standard, or comprehensive'
- name: crawl_limit
type: integer
default: 50
validation:
maximum: 500
minimum: 10
description: Maximum number of pages to crawl
outputs:
score:
source: compile_report.executive_summary.overall_score
description: Overall SEO health score (0-100)
audit_report:
source: compile_report
description: Complete Technical SEO Audit Report
critical_issues:
source: compile_report.issues_and_warnings.critical_issues
description: List of critical issues found
recommendations:
source: generate_recommendations
description: AI-generated recommendations
version: 2.0.0
description: Comprehensive technical SEO audit workflow that analyzes website health,
performance, and optimization opportunities
model_clients:
- id: seo_analyzer
config:
model: gpt-4o-mini
api_key: ${env.OPENAI_API_KEY}
provider: openai