Technical SEO Audit Fixed
Fixed technical SEO audit workflow with improved error handling and compatibility
Workflow Information
ID: technical_seo_audit_fixed
Namespace: default
Version: 1.0.0
Created: 2025-07-07
Updated: 2025-07-07
Tasks: 6
Quick Actions
Inputs
| Name | Type | Required | Default |
|---|---|---|---|
target_url |
string | Required | None |
audit_depth |
string | Optional |
standard
|
Outputs
| Name | Type | Source |
|---|---|---|
seo_score |
string | Overall SEO health score (0-100) |
full_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
python_analysis
scriptNo description
try_dataforseo
mcpNo description
calculate_score
scriptNo description
generate_recommendations
ai_agentNo description
compile_final_report
scriptNo description
YAML Source
id: technical_seo_audit_fixed
name: Technical SEO Audit Fixed
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: python_analysis
type: script
script: "import json\nimport requests\nfrom bs4 import BeautifulSoup\nimport time\n\
import os\nfrom urllib.parse import urlparse, urljoin\n\ntarget_url = os.environ.get('target_url',\
\ '')\n\nresults = {\n \"url\": target_url,\n \"status\": \"analyzing\"\
,\n \"metrics\": {},\n \"seo_elements\": {},\n \"issues\": [],\n \"\
warnings\": []\n}\n\ntry:\n # Fetch page\n headers = {\n 'User-Agent':\
\ 'Mozilla/5.0 (compatible; SEO-Analyzer/1.0)'\n }\n start_time = time.time()\n\
\ response = requests.get(target_url, timeout=15, headers=headers, allow_redirects=True)\n\
\ load_time = time.time() - start_time\n \n soup = BeautifulSoup(response.text,\
\ 'html.parser')\n \n # Basic metrics\n results[\"metrics\"] = {\n \
\ \"status_code\": response.status_code,\n \"load_time\": round(load_time,\
\ 2),\n \"content_length\": len(response.text),\n \"is_https\":\
\ target_url.startswith('https'),\n \"final_url\": response.url\n }\n\
\ \n # SEO elements\n title = soup.find('title')\n meta_desc = soup.find('meta',\
\ attrs={'name': 'description'})\n canonical = soup.find('link', attrs={'rel':\
\ 'canonical'})\n \n # Headers\n h1_tags = soup.find_all('h1')\n h2_tags\
\ = soup.find_all('h2')\n \n # Images\n images = soup.find_all('img')\n\
\ images_without_alt = [img for img in images if not img.get('alt', '').strip()]\n\
\ \n # Open Graph\n og_tags = {}\n for tag in soup.find_all('meta',\
\ property=True):\n if tag.get('property', '').startswith('og:'):\n \
\ og_tags[tag['property']] = tag.get('content', '')\n \n results[\"\
seo_elements\"] = {\n \"title\": title.text.strip() if title else \"\"\
,\n \"title_length\": len(title.text.strip()) if title else 0,\n \
\ \"description\": meta_desc.get('content', '') if meta_desc else \"\",\n \
\ \"description_length\": len(meta_desc.get('content', '')) if meta_desc else\
\ 0,\n \"canonical\": canonical.get('href', '') if canonical else \"\"\
,\n \"h1_count\": len(h1_tags),\n \"h2_count\": len(h2_tags),\n\
\ \"h1_texts\": [h1.text.strip() for h1 in h1_tags[:3]],\n \"images_total\"\
: len(images),\n \"images_without_alt\": len(images_without_alt),\n \
\ \"has_og_tags\": len(og_tags) > 0,\n \"og_title\": og_tags.get('og:title',\
\ ''),\n \"og_description\": og_tags.get('og:description', '')\n }\n\
\ \n # Issues detection\n if results[\"metrics\"][\"status_code\"] !=\
\ 200:\n results[\"issues\"].append(f\"Page returns {results['metrics']['status_code']}\
\ status code\")\n \n if not results[\"metrics\"][\"is_https\"]:\n \
\ results[\"issues\"].append(\"Site is not using HTTPS\")\n \n if not\
\ results[\"seo_elements\"][\"title\"]:\n results[\"issues\"].append(\"\
Missing page title\")\n elif results[\"seo_elements\"][\"title_length\"] >\
\ 60:\n results[\"warnings\"].append(f\"Title too long ({results['seo_elements']['title_length']}\
\ chars)\")\n elif results[\"seo_elements\"][\"title_length\"] < 30:\n \
\ results[\"warnings\"].append(f\"Title too short ({results['seo_elements']['title_length']}\
\ chars)\")\n \n if not results[\"seo_elements\"][\"description\"]:\n \
\ results[\"issues\"].append(\"Missing meta description\")\n elif results[\"\
seo_elements\"][\"description_length\"] > 160:\n results[\"warnings\"].append(f\"\
Description too long ({results['seo_elements']['description_length']} chars)\"\
)\n elif results[\"seo_elements\"][\"description_length\"] < 70:\n results[\"\
warnings\"].append(f\"Description too short ({results['seo_elements']['description_length']}\
\ chars)\")\n \n if results[\"seo_elements\"][\"h1_count\"] == 0:\n \
\ results[\"issues\"].append(\"Missing H1 tag\")\n elif results[\"seo_elements\"\
][\"h1_count\"] > 1:\n results[\"warnings\"].append(f\"Multiple H1 tags\
\ found ({results['seo_elements']['h1_count']})\")\n \n if results[\"seo_elements\"\
][\"images_without_alt\"] > 0:\n results[\"warnings\"].append(f\"{results['seo_elements']['images_without_alt']}\
\ images missing alt text\")\n \n if results[\"metrics\"][\"load_time\"\
] > 3:\n results[\"warnings\"].append(f\"Slow page load time ({results['metrics']['load_time']}s)\"\
)\n \n if not results[\"seo_elements\"][\"has_og_tags\"]:\n results[\"\
warnings\"].append(\"Missing Open Graph tags\")\n \n results[\"status\"\
] = \"success\"\n \nexcept Exception as e:\n results[\"status\"] = \"error\"\
\n results[\"error\"] = str(e)\n results[\"issues\"].append(f\"Analysis\
\ failed: {str(e)}\")\n\nprint(f\"__OUTPUTS__ {json.dumps(results)}\")\n"
depends_on:
- parse_url
requirements:
- requests==2.31.0
- beautifulsoup4==4.12.2
- lxml==4.9.3
timeout_seconds: 30
- id: try_dataforseo
type: mcp
when: audit_depth != 'basic'
tool_name: dataforseo_labs_google_domain_rank_overview
depends_on:
- parse_url
retry_policy:
max_attempts: 2
initial_interval: 3
deployment_id: pod-hl7wh2lc
tool_arguments:
target: ${parse_url.domain}
language_code: en
location_name: United States
timeout_seconds: 60
- id: calculate_score
type: script
script: "import json\nimport os\nfrom datetime import datetime\n\n# Get analysis\
\ data\nanalysis = json.loads(os.environ.get('python_analysis', '{}'))\ndataforseo\
\ = json.loads(os.environ.get('try_dataforseo', '{}'))\n\n# Extract domain metrics\
\ if available\ndomain_metrics = {}\nif dataforseo and 'tasks' in dataforseo:\n\
\ try:\n result = dataforseo['tasks'][0]['result'][0]\n metrics\
\ = result.get('metrics', {})\n domain_metrics = {\n \"organic_keywords\"\
: metrics.get('organic', {}).get('count', 0),\n \"organic_traffic\"\
: metrics.get('organic', {}).get('etv', 0),\n \"domain_rank\": result.get('rank',\
\ 0)\n }\n except:\n pass\n\n# Calculate score\nissues_count\
\ = len(analysis.get('issues', []))\nwarnings_count = len(analysis.get('warnings',\
\ []))\nscore = max(0, 100 - issues_count * 15 - warnings_count * 5)\n\n# Compile\
\ results\nresults = {\n \"audit_date\": datetime.now().isoformat(),\n \"\
target_url\": os.environ.get('target_url', ''),\n \"audit_depth\": os.environ.get('audit_depth',\
\ 'standard'),\n \"score\": score,\n \"issues_count\": issues_count,\n \
\ \"warnings_count\": warnings_count,\n \"issues\": analysis.get('issues',\
\ []),\n \"warnings\": analysis.get('warnings', []),\n \"metrics\": analysis.get('metrics',\
\ {}),\n \"seo_elements\": analysis.get('seo_elements', {}),\n \"domain_metrics\"\
: domain_metrics\n}\n\nprint(f\"__OUTPUTS__ {json.dumps(results)}\")\n"
depends_on:
- python_analysis
timeout_seconds: 20
- id: generate_recommendations
type: ai_agent
prompt: "You are an expert SEO consultant. Analyze this technical SEO audit data\
\ and provide comprehensive, actionable recommendations.\n\nSEO Audit Results:\n\
${calculate_score}\n\nBased on the data, create a detailed analysis with:\n\n\
1. **Executive Summary** - A 2-3 sentence overview of the site's SEO health\n\
2. **Critical Issues** - Must-fix problems that severely impact SEO\n3. **High\
\ Priority Recommendations** - Important improvements for better rankings\n4.\
\ **Quick Wins** - Easy fixes that will have immediate positive impact\n5. **Long-term\
\ Optimization** - Strategic improvements for sustained growth\n\nReturn your\
\ response as a well-structured JSON object with these exact keys:\n{\n \"executive_summary\"\
: \"string\",\n \"critical_issues\": [\"issue1\", \"issue2\"],\n \"high_priority_recommendations\"\
: [\"rec1\", \"rec2\"],\n \"quick_wins\": [\"win1\", \"win2\"],\n \"long_term_improvements\"\
: [\"improvement1\", \"improvement2\"]\n}\n"
agent_type: analyst
depends_on:
- calculate_score
model_client_id: seo_analyzer
timeout_seconds: 60
- id: compile_final_report
type: script
script: "import json\nimport os\nfrom datetime import datetime\n\n# Get data\nscore_data\
\ = json.loads(os.environ.get('calculate_score', '{}'))\nai_recs = os.environ.get('generate_recommendations',\
\ '{}')\n\n# Parse AI recommendations\ntry:\n # Handle both string and dict\
\ responses\n if isinstance(ai_recs, str):\n # Try to extract JSON from\
\ the response\n start = ai_recs.find('{')\n end = ai_recs.rfind('}')\
\ + 1\n if start >= 0 and end > start:\n recommendations = json.loads(ai_recs[start:end])\n\
\ else:\n recommendations = {\"error\": \"Could not parse AI\
\ response\"}\n else:\n recommendations = ai_recs\nexcept:\n recommendations\
\ = {\n \"executive_summary\": \"SEO audit completed. Please review the\
\ findings below.\",\n \"critical_issues\": score_data.get('issues', []),\n\
\ \"high_priority_recommendations\": [\"Fix all critical issues\", \"Optimize\
\ page speed\"],\n \"quick_wins\": [\"Add missing meta tags\", \"Fix image\
\ alt texts\"],\n \"long_term_improvements\": [\"Implement structured data\"\
, \"Build quality backlinks\"]\n }\n\n# Create final report\nreport = {\n \
\ \"report_metadata\": {\n \"title\": \"Technical SEO Audit Report\"\
,\n \"generated_at\": datetime.now().isoformat(),\n \"target_url\"\
: score_data.get('target_url', ''),\n \"audit_depth\": score_data.get('audit_depth',\
\ 'standard'),\n \"workflow_version\": \"1.0.0\"\n },\n \"executive_summary\"\
: {\n \"overall_score\": score_data.get('score', 0),\n \"critical_issues_count\"\
: score_data.get('issues_count', 0),\n \"warnings_count\": score_data.get('warnings_count',\
\ 0),\n \"summary\": recommendations.get('executive_summary', '')\n \
\ },\n \"technical_analysis\": {\n \"performance_metrics\": score_data.get('metrics',\
\ {}),\n \"seo_elements\": score_data.get('seo_elements', {}),\n \
\ \"domain_authority\": score_data.get('domain_metrics', {})\n },\n \"\
issues_and_warnings\": {\n \"critical_issues\": score_data.get('issues',\
\ []),\n \"warnings\": score_data.get('warnings', [])\n },\n \"recommendations\"\
: {\n \"critical_fixes\": recommendations.get('critical_issues', []),\n\
\ \"high_priority\": recommendations.get('high_priority_recommendations',\
\ []),\n \"quick_wins\": recommendations.get('quick_wins', []),\n \
\ \"long_term\": recommendations.get('long_term_improvements', [])\n },\n\
\ \"next_steps\": [\n \"1. Address all critical issues immediately\"\
,\n \"2. Implement quick wins for fast improvements\",\n \"3. Plan\
\ high-priority recommendations implementation\",\n \"4. Schedule re-audit\
\ in 30 days to measure progress\"\n ],\n \"audit_status\": \"completed\"\
\n}\n\nprint(f\"__OUTPUTS__ {json.dumps(report)}\")\n"
depends_on:
- calculate_score
- generate_recommendations
timeout_seconds: 20
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'
outputs:
seo_score:
source: compile_final_report.executive_summary.overall_score
description: Overall SEO health score (0-100)
full_report:
source: compile_final_report
description: Complete Technical SEO Audit Report
critical_issues:
source: compile_final_report.issues_and_warnings.critical_issues
description: List of critical issues found
recommendations:
source: compile_final_report.recommendations
description: AI-generated recommendations
version: 1.0.0
description: Fixed technical SEO audit workflow with improved error handling and compatibility
model_clients:
- id: seo_analyzer
config:
model: gpt-4o-mini
api_key: ${env.OPENAI_API_KEY}
max_tokens: 2000
temperature: 0.3
provider: openai
| Execution ID | Status | Started | Duration | Actions |
|---|---|---|---|---|
4cddd026...
|
COMPLETED |
2025-07-07
09:07:00 |
N/A | View |