SEO Analyzer - Score Any Website avatar

SEO Analyzer - Score Any Website

Under maintenance

Pricing

Pay per usage

Go to Apify Store
SEO Analyzer - Score Any Website

SEO Analyzer - Score Any Website

Under maintenance

Comprehensive SEO analysis tool. Analyze any URL for meta tags, heading structure, image optimization, internal/external links, performance metrics, and get an overall SEO score with actionable recommendations.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

2x lazymac

2x lazymac

Maintained by Community

Actor stats

0

Bookmarked

4

Total users

2

Monthly active users

6 days ago

Last modified

Categories

Share

SEO Analyzer

Analyze the SEO health of any webpage in seconds. Get a detailed score (0-100), letter grade (A-F), and actionable recommendations across 9 key categories. Compare two URLs side by side to see which one wins. No API keys required, no browser needed -- just pass a URL and get results.

Built for marketers, developers, agencies, and anyone who wants fast, automated SEO audits at scale.


What It Does

SEO Analyzer fetches any public webpage and runs a comprehensive audit covering titles, meta descriptions, headings, images, links, Open Graph tags, technical SEO, Schema.org structured data, and content quality. Each category receives an individual score, and these are combined into a weighted overall score with a letter grade.

You can also compare two URLs head-to-head. The comparison output shows per-category winners and an overall champion, making it ideal for competitive analysis, A/B testing landing pages, or benchmarking against competitors.

Key Capabilities

  • Single URL Analysis: Full audit with score, grade, issues, and recommendations
  • Two-URL Comparison: Side-by-side SEO comparison with per-category winners
  • 9 Analysis Categories: Title, Meta Description, Headings, Images, Links, Open Graph, Technical SEO, Schema.org, Content Quality
  • Weighted Scoring: Each category has a specific weight reflecting its SEO importance
  • Actionable Output: Every issue comes with a clear recommendation for how to fix it
  • Zero Dependencies: No external APIs, no browser rendering -- uses lightweight HTML parsing only
  • Fast Execution: Typical analysis completes in 2-5 seconds

What Data You Get

Single URL Analysis Output Fields

FieldTypeDescription
urlstringThe final URL after redirects
analyzedAtstringISO 8601 timestamp of the analysis
statusCodenumberHTTP status code returned by the page
fetchTimeMsnumberTime taken to fetch the page in milliseconds
overallScorenumberWeighted overall score from 0 to 100
gradestringLetter grade: A (90+), B (80-89), C (70-79), D (60-69), F (below 60)
scoresobjectIndividual scores for each of the 9 categories
details.titleobjectTitle tag text, length, score, issues, recommendations
details.metaDescriptionobjectMeta description content, length, score, issues, recommendations
details.headingsobjectFull heading hierarchy (H1-H6), counts, texts, score, issues
details.imagesobjectTotal images, missing alt count, empty alt count, problematic sources
details.linksobjectInternal/external/nofollow/broken link counts, score, issues
details.openGraphobjectAll OG tags found, Twitter Card tags, completeness percentage, missing tags
details.technicalobjectViewport, canonical, lang, charset, robots, favicon, HTML size, resource counts
details.schemaobjectJSON-LD, Microdata, and RDFa schemas detected with types
details.contentobjectWord count, estimated reading time in minutes, score
summary.totalIssuesnumberTotal number of issues found across all categories
summary.issuesarrayComplete list of all issues found
summary.recommendationsarrayComplete list of all actionable recommendations

Comparison Output Fields

FieldTypeDescription
comparedAtstringISO 8601 timestamp
resultsarrayFull analysis results for both URLs (same structure as single analysis)
comparisonobjectPer-category scores for both URLs with winner
overallWinnerstringURL of the overall winner, or "tie"

How to Use

Basic Usage

  1. Open the SEO Analyzer on Apify
  2. Enter a URL in the "URL" field (e.g., https://example.com)
  3. Click "Start"
  4. View results in the "Dataset" tab

Comparison Mode

  1. Enter the primary URL in the "URL" field
  2. Enter a second URL in the "Compare URL" field
  3. Click "Start"
  4. The output will include full analysis for both URLs plus a comparison summary

Input Configuration

FieldTypeRequiredDefaultDescription
urlstringYes--The URL to analyze. Must be a publicly accessible webpage. Supports both HTTP and HTTPS. If the protocol is omitted, HTTPS is assumed. The analyzer follows up to 5 redirects automatically.
compareUrlstringNo--A second URL for side-by-side SEO comparison. When provided, the actor runs a full analysis on both URLs and outputs a comparison with per-category winners and an overall winner.

Output Example

Single URL Analysis

{
"url": "https://example.com",
"analyzedAt": "2026-04-16T12:00:00.000Z",
"statusCode": 200,
"fetchTimeMs": 342,
"overallScore": 72,
"grade": "C",
"scores": {
"title": 100,
"metaDescription": 0,
"headings": 60,
"images": 100,
"links": 70,
"openGraph": 0,
"technical": 76,
"schema": 0,
"content": 30
},
"details": {
"title": {
"text": "Example Domain",
"length": 14,
"score": 100,
"issues": ["Title too short (14 chars, recommended 30-60)"],
"recommendations": ["Expand the title to include primary keywords"]
},
"metaDescription": {
"content": null,
"length": 0,
"score": 0,
"issues": ["Missing meta description"],
"recommendations": ["Add a compelling meta description between 120-160 characters"]
},
"headings": {
"hierarchy": {
"h1": { "count": 1, "texts": ["Example Domain"] },
"h2": { "count": 0, "texts": [] },
"h3": { "count": 0, "texts": [] },
"h4": { "count": 0, "texts": [] },
"h5": { "count": 0, "texts": [] },
"h6": { "count": 0, "texts": [] }
},
"totalHeadings": 1,
"score": 60,
"issues": [],
"recommendations": []
},
"images": {
"total": 0,
"missingAlt": 0,
"emptyAlt": 0,
"missingAltSrcs": [],
"score": 100,
"issues": [],
"recommendations": []
},
"links": {
"total": 1,
"internal": 0,
"external": 1,
"nofollow": 0,
"broken": 0,
"score": 70,
"issues": ["No internal links found"],
"recommendations": ["Add internal links to improve site structure and crawlability"]
},
"openGraph": {
"ogTags": {},
"twitterTags": {},
"completeness": 0,
"missing": ["og:title", "og:description", "og:image", "og:url", "og:type"],
"score": 0,
"issues": ["No Open Graph tags found", "No Twitter Card meta tags found"],
"recommendations": [
"Add og:title, og:description, og:image, og:url, and og:type",
"Add twitter:card, twitter:title, twitter:description for better social sharing"
]
},
"technical": {
"viewport": "width=device-width, initial-scale=1",
"canonical": null,
"lang": null,
"charset": "utf-8",
"robots": null,
"favicon": null,
"htmlSizeKB": 1,
"resources": { "scripts": 0, "stylesheets": 0, "inlineStyles": 1, "iframes": 0 },
"score": 76,
"issues": ["Missing canonical URL", "Missing lang attribute on <html>", "No favicon detected"],
"recommendations": [
"Add a canonical link to prevent duplicate content issues",
"Add lang attribute (e.g., <html lang=\"en\">)",
"Add a favicon for better branding and browser tab appearance"
]
},
"schema": {
"schemas": [],
"count": 0,
"score": 0,
"issues": ["No structured data (Schema.org) detected"],
"recommendations": ["Add JSON-LD structured data for rich search results"]
},
"content": {
"wordCount": 28,
"readingTimeMin": 1,
"score": 9,
"issues": ["Low word count (28)"],
"recommendations": ["Aim for at least 300 words of meaningful content for better SEO"]
}
},
"summary": {
"totalIssues": 6,
"issues": [
"Title too short (14 chars, recommended 30-60)",
"Missing meta description",
"No internal links found",
"No Open Graph tags found",
"No Twitter Card meta tags found",
"Missing canonical URL",
"Missing lang attribute on <html>",
"No favicon detected",
"No structured data (Schema.org) detected",
"Low word count (28)"
],
"recommendations": [
"Expand the title to include primary keywords",
"Add a compelling meta description between 120-160 characters",
"Add internal links to improve site structure and crawlability",
"Add og:title, og:description, og:image, og:url, and og:type",
"Add twitter:card, twitter:title, twitter:description for better social sharing",
"Add a canonical link to prevent duplicate content issues",
"Add lang attribute (e.g., <html lang=\"en\">)",
"Add a favicon for better branding and browser tab appearance",
"Add JSON-LD structured data for rich search results",
"Aim for at least 300 words of meaningful content for better SEO"
]
}
}

Comparison Output

{
"comparedAt": "2026-04-16T12:00:00.000Z",
"results": [
{ "url": "https://github.com", "overallScore": 78, "grade": "C", "..." : "..." },
{ "url": "https://gitlab.com", "overallScore": 71, "grade": "C", "..." : "..." }
],
"comparison": {
"title": { "url1": 100, "url2": 85, "winner": "https://github.com" },
"metaDescription": { "url1": 90, "url2": 100, "winner": "https://gitlab.com" },
"headings": { "url1": 80, "url2": 70, "winner": "https://github.com" },
"images": { "url1": 100, "url2": 90, "winner": "https://github.com" },
"links": { "url1": 85, "url2": 85, "winner": "tie" },
"openGraph": { "url1": 100, "url2": 80, "winner": "https://github.com" },
"technical": { "url1": 92, "url2": 84, "winner": "https://github.com" },
"schema": { "url1": 100, "url2": 0, "winner": "https://github.com" },
"content": { "url1": 30, "url2": 50, "winner": "https://gitlab.com" }
},
"overallWinner": "https://github.com"
}

Scoring System

Category Weights

CategoryWeightWhat It Checks
Title15%Presence of <title> tag, optimal length (30-60 characters), no duplicates
Meta Description10%Presence, optimal length (120-160 characters)
Headings10%H1 presence and uniqueness, heading hierarchy, no skipped levels
Images8%Alt text on all <img> elements for accessibility and SEO
Links7%Internal/external link balance, no broken or empty hrefs
Open Graph10%og:title, og:description, og:image, og:url, og:type, Twitter Card tags
Technical SEO20%Viewport meta, canonical URL, lang attribute, charset, favicon, HTML size, script/stylesheet counts
Schema.org10%JSON-LD, Microdata, or RDFa structured data detection
Content Quality10%Word count (minimum 300 recommended), reading time estimation

Grade Scale

GradeScore RangeMeaning
A90 - 100Excellent SEO -- minimal or no issues
B80 - 89Good SEO -- minor improvements possible
C70 - 79Average SEO -- several areas need attention
D60 - 69Below average -- significant issues found
F0 - 59Poor SEO -- major problems across multiple categories

Cost Estimation

This actor uses the pay-per-event pricing model. You are charged per analysis performed.

ActionEventEstimated Cost
Single URL analysis1 event~$0.01 - $0.05 per run
Two-URL comparison1 event~$0.01 - $0.05 per run

Typical run uses minimal compute (128 MB RAM, under 10 seconds) because there is no browser involved -- only lightweight HTTP fetching and HTML parsing.


Integration Guide

Python

from apify_client import ApifyClient
client = ApifyClient("YOUR_API_TOKEN")
# Single URL analysis
run = client.actor("lazymac/seo-analyzer").call(run_input={
"url": "https://example.com"
})
# Get results
dataset = client.dataset(run["defaultDatasetId"])
for item in dataset.iterate_items():
print(f"Score: {item['overallScore']}/100 ({item['grade']})")
print(f"Issues: {item['summary']['totalIssues']}")
for issue in item['summary']['issues']:
print(f" - {issue}")
# Compare two URLs
run = client.actor("lazymac/seo-analyzer").call(run_input={
"url": "https://github.com",
"compareUrl": "https://gitlab.com"
})
dataset = client.dataset(run["defaultDatasetId"])
for item in dataset.iterate_items():
print(f"Winner: {item['overallWinner']}")

Node.js

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });
// Single URL analysis
const run = await client.actor('lazymac/seo-analyzer').call({
url: 'https://example.com',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const result = items[0];
console.log(`Score: ${result.overallScore}/100 (${result.grade})`);
console.log(`Total issues: ${result.summary.totalIssues}`);
result.summary.recommendations.forEach(rec => console.log(` - ${rec}`));
// Compare two URLs
const compareRun = await client.actor('lazymac/seo-analyzer').call({
url: 'https://github.com',
compareUrl: 'https://gitlab.com',
});
const { items: compareItems } = await client.dataset(compareRun.defaultDatasetId).listItems();
console.log(`Winner: ${compareItems[0].overallWinner}`);

Apify API (cURL)

# Start a run
curl -X POST "https://api.apify.com/v2/acts/lazymac~seo-analyzer/runs" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com"}'
# Get results from the default dataset
curl "https://api.apify.com/v2/datasets/DATASET_ID/items?format=json" \
-H "Authorization: Bearer YOUR_API_TOKEN"

Scheduled Monitoring

You can schedule this actor to run daily or weekly on your most important pages to track SEO health over time. Set up a schedule in Apify Console and export results to Google Sheets, Slack, or any webhook.


Use Cases

  • Site Audit: Run a quick SEO health check on any page before publishing
  • Competitive Analysis: Compare your landing page against a competitor's page
  • CI/CD Integration: Add SEO checks to your deployment pipeline
  • Client Reporting: Generate SEO reports for agency clients
  • Content Optimization: Identify missing meta tags, heading issues, and content gaps
  • Technical Debt: Find missing canonical URLs, viewport tags, and structured data
  • Social Media Preview: Verify Open Graph and Twitter Card tags are properly set
  • Migration Validation: Verify SEO elements are preserved after a site redesign or CMS migration
  • Multi-Language Sites: Audit hreflang and lang attributes across localized pages
  • E-Commerce Product Pages: Ensure product Schema.org markup, canonical URLs, and meta descriptions are in place

Integration with Other Tools

Zapier

  1. Create a new Zap with a trigger (e.g., "Every Day" schedule or "New Row in Google Sheets")
  2. Add an action: Apify -- Run Actor
  3. Select lazymac/seo-analyzer and configure the URL input
  4. Add a downstream action to send results to Slack, Google Sheets, email, or any other Zapier-connected app
  5. Map the overallScore, grade, and summary.issues fields to your destination

Make (Integromat)

  1. Create a new scenario
  2. Add the Apify module and select "Run an Actor"
  3. Set the actor to lazymac/seo-analyzer with your desired URL
  4. Add a router to branch based on the score (e.g., send Slack alert if score < 70)
  5. Connect to Google Sheets, Airtable, or a webhook for downstream processing

Google Sheets Integration

Export SEO results directly to a spreadsheet for tracking and reporting:

from apify_client import ApifyClient
import gspread
from oauth2client.service_account import ServiceAccountCredentials
# Run the SEO analysis
client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("lazymac/seo-analyzer").call(run_input={"url": "https://example.com"})
dataset = client.dataset(run["defaultDatasetId"])
results = list(dataset.iterate_items())
# Write to Google Sheets
scope = ["https://spreadsheets.google.com/feeds"]
creds = ServiceAccountCredentials.from_json_keyfile_name("credentials.json", scope)
gc = gspread.authorize(creds)
sheet = gc.open("SEO Tracker").sheet1
for item in results:
sheet.append_row([
item["url"],
item["overallScore"],
item["grade"],
item["summary"]["totalIssues"],
item["analyzedAt"]
])

Webhooks

Use the Apify webhook feature to get notified when an analysis completes:

  1. Go to Actor runs in the Apify Console
  2. Set up a webhook with event ACTOR.RUN.SUCCEEDED
  3. Point the webhook URL to your endpoint (Slack incoming webhook, Discord webhook, custom API)
  4. The webhook payload includes the dataset ID so you can fetch full results

CI/CD Pipeline Integration

Add SEO checks to your GitHub Actions, GitLab CI, or Jenkins pipeline:

# GitHub Actions example
- name: SEO Check
run: |
RESULT=$(curl -s -X POST "https://api.apify.com/v2/acts/lazymac~seo-analyzer/run-sync-get-dataset-items" \
-H "Authorization: Bearer ${{ secrets.APIFY_TOKEN }}" \
-H "Content-Type: application/json" \
-d '{"url": "${{ env.DEPLOY_URL }}"}')
SCORE=$(echo $RESULT | jq '.[0].overallScore')
echo "SEO Score: $SCORE"
if [ "$SCORE" -lt 70 ]; then
echo "::warning::SEO score is below 70 ($SCORE). Review the issues before merging."
fi

Tips and Tricks

  1. Start with your most important pages. Analyze your homepage, top landing pages, and highest-traffic blog posts first. These have the biggest impact on organic search performance.

  2. Use comparison mode for competitive research. Compare your page against a direct competitor to see where you win and where you lose. Focus improvement efforts on categories where the competitor outscores you.

  3. Schedule weekly audits for key pages. SEO health can degrade over time as content changes, plugins update, or developers modify templates. A weekly scheduled run catches regressions early.

  4. Pay attention to Technical SEO first. It carries the highest weight (20%) and includes foundational elements like canonical URLs and viewport tags. Fixing these often provides the biggest score improvement.

  5. Don't chase a perfect 100. A score of 85+ (grade B or A) means the page is well-optimized. Diminishing returns kick in quickly above that threshold. Focus on fixing critical issues rather than perfecting every metric.

  6. Use the recommendations array for action items. Each issue in the output comes with a specific recommendation. These can be exported directly to a project management tool as tasks.

  7. Check Open Graph tags before social campaigns. If you're about to share a page on social media or run ads, verify that OG tags are set correctly. Missing og:image means your shared link will have no preview image.

  8. Monitor Schema.org markup after CMS updates. Structured data is often generated by CMS plugins that can break during updates. A sudden drop in the Schema.org score signals that your rich results may disappear from Google.


Frequently Asked Questions

Q: Does this actor render JavaScript? A: No. The analyzer fetches raw HTML using a lightweight HTTP client. This means it analyzes what search engine crawlers see by default (server-rendered HTML). For single-page apps (React, Vue, Angular) that require JavaScript rendering, the raw HTML may differ from what users see in a browser.

Q: How many URLs can I analyze at once? A: In single mode, one URL per run. In comparison mode, two URLs per run. For bulk analysis, you can call the actor programmatically in a loop or use the Apify scheduler.

Q: Does it follow redirects? A: Yes. The analyzer follows up to 5 HTTP redirects (301, 302, 303, 307, 308) and reports the final URL in the output.

Q: What happens if the page returns an error? A: The actor will report the HTTP status code and still attempt to analyze whatever HTML was returned. For non-HTML responses or timeouts (15-second limit), the actor will throw an error.

Q: Is the scoring algorithm customizable? A: The current version uses fixed weights. The category weights reflect industry-standard SEO priorities, with Technical SEO (20%) and Title (15%) having the highest impact on the overall score.

Q: How accurate is the SEO score? A: The score is based on well-established SEO best practices. It checks for the same issues that tools like Lighthouse, Moz, and Ahrefs flag. However, no automated tool can fully replace human SEO expertise -- treat the score as a directional indicator and prioritize the specific issues listed.

Q: Can I use this for monitoring SEO changes over time? A: Yes. Schedule the actor to run on a regular interval (daily, weekly) and store results in a dataset. You can then track score changes, new issues, and resolved issues over time using the Apify API or integrations.

Q: Does this actor check for broken external links? A: The actor identifies empty, hash-only, and javascript: href values as "broken." It does not follow external links to check their HTTP status, as that would significantly increase execution time and cost.

Q: What is the difference between this and Google Lighthouse? A: Lighthouse runs in a full browser and measures performance, accessibility, PWA compliance, and more. SEO Analyzer is a focused, lightweight tool that runs without a browser and concentrates exclusively on SEO factors. It is faster, cheaper, and easier to integrate into automated workflows.

Q: Can I analyze pages behind authentication? A: No. The analyzer can only access publicly available URLs. Pages requiring login or behind paywalls will return the login page HTML instead of the actual content.

Q: How does the weighted scoring work? A: Each of the 9 categories has a weight (e.g., Technical SEO = 20%, Title = 15%). The overall score is the sum of each category score multiplied by its weight. For example, if your Title score is 80 and its weight is 15%, that category contributes 12 points to the overall score.

Q: Can I use this actor with the Apify CLI? A: Yes. Install the Apify CLI (npm install -g apify-cli), then run: apify call lazymac/seo-analyzer -i '{"url": "https://example.com"}'. Results are saved to the local dataset.

Q: What HTTP method does the analyzer use? A: It sends a GET request with a standard browser-like User-Agent header. The request includes Accept: text/html and follows standard HTTP semantics.

Q: Does the actor support HTTPS-only pages? A: Yes. HTTPS is fully supported and is the default protocol if you omit the scheme. The actor handles TLS certificates automatically. Self-signed certificates will cause the request to fail.

Q: How large can the analyzed page be? A: There is no hard limit on page size, but extremely large pages (over 5 MB of HTML) may increase processing time. Typical web pages (under 500 KB) are processed in 2-5 seconds.

Q: Can I get results in CSV format? A: Yes. After the run completes, access your results via the Apify API with ?format=csv appended to the dataset items endpoint. You can also download CSV directly from the Apify Console dataset view.


Limitations

  • Does not execute JavaScript (static HTML analysis only)
  • Cannot access pages behind authentication
  • Maximum 5 redirects followed
  • 15-second timeout for page fetching
  • Single URL or two-URL comparison per run (use API for bulk)
  • Does not check external link HTTP status codes

Changelog

  • v1.0 - Initial release with 9 analysis categories, comparison mode, and pay-per-event pricing