SEO Analyzer - Score Any Website
Pricing
Pay per usage
SEO Analyzer - Score Any Website
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
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
| Field | Type | Description |
|---|---|---|
url | string | The final URL after redirects |
analyzedAt | string | ISO 8601 timestamp of the analysis |
statusCode | number | HTTP status code returned by the page |
fetchTimeMs | number | Time taken to fetch the page in milliseconds |
overallScore | number | Weighted overall score from 0 to 100 |
grade | string | Letter grade: A (90+), B (80-89), C (70-79), D (60-69), F (below 60) |
scores | object | Individual scores for each of the 9 categories |
details.title | object | Title tag text, length, score, issues, recommendations |
details.metaDescription | object | Meta description content, length, score, issues, recommendations |
details.headings | object | Full heading hierarchy (H1-H6), counts, texts, score, issues |
details.images | object | Total images, missing alt count, empty alt count, problematic sources |
details.links | object | Internal/external/nofollow/broken link counts, score, issues |
details.openGraph | object | All OG tags found, Twitter Card tags, completeness percentage, missing tags |
details.technical | object | Viewport, canonical, lang, charset, robots, favicon, HTML size, resource counts |
details.schema | object | JSON-LD, Microdata, and RDFa schemas detected with types |
details.content | object | Word count, estimated reading time in minutes, score |
summary.totalIssues | number | Total number of issues found across all categories |
summary.issues | array | Complete list of all issues found |
summary.recommendations | array | Complete list of all actionable recommendations |
Comparison Output Fields
| Field | Type | Description |
|---|---|---|
comparedAt | string | ISO 8601 timestamp |
results | array | Full analysis results for both URLs (same structure as single analysis) |
comparison | object | Per-category scores for both URLs with winner |
overallWinner | string | URL of the overall winner, or "tie" |
How to Use
Basic Usage
- Open the SEO Analyzer on Apify
- Enter a URL in the "URL" field (e.g.,
https://example.com) - Click "Start"
- View results in the "Dataset" tab
Comparison Mode
- Enter the primary URL in the "URL" field
- Enter a second URL in the "Compare URL" field
- Click "Start"
- The output will include full analysis for both URLs plus a comparison summary
Input Configuration
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
url | string | Yes | -- | 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. |
compareUrl | string | No | -- | 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
| Category | Weight | What It Checks |
|---|---|---|
| Title | 15% | Presence of <title> tag, optimal length (30-60 characters), no duplicates |
| Meta Description | 10% | Presence, optimal length (120-160 characters) |
| Headings | 10% | H1 presence and uniqueness, heading hierarchy, no skipped levels |
| Images | 8% | Alt text on all <img> elements for accessibility and SEO |
| Links | 7% | Internal/external link balance, no broken or empty hrefs |
| Open Graph | 10% | og:title, og:description, og:image, og:url, og:type, Twitter Card tags |
| Technical SEO | 20% | Viewport meta, canonical URL, lang attribute, charset, favicon, HTML size, script/stylesheet counts |
| Schema.org | 10% | JSON-LD, Microdata, or RDFa structured data detection |
| Content Quality | 10% | Word count (minimum 300 recommended), reading time estimation |
Grade Scale
| Grade | Score Range | Meaning |
|---|---|---|
| A | 90 - 100 | Excellent SEO -- minimal or no issues |
| B | 80 - 89 | Good SEO -- minor improvements possible |
| C | 70 - 79 | Average SEO -- several areas need attention |
| D | 60 - 69 | Below average -- significant issues found |
| F | 0 - 59 | Poor SEO -- major problems across multiple categories |
Cost Estimation
This actor uses the pay-per-event pricing model. You are charged per analysis performed.
| Action | Event | Estimated Cost |
|---|---|---|
| Single URL analysis | 1 event | ~$0.01 - $0.05 per run |
| Two-URL comparison | 1 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 ApifyClientclient = ApifyClient("YOUR_API_TOKEN")# Single URL analysisrun = client.actor("lazymac/seo-analyzer").call(run_input={"url": "https://example.com"})# Get resultsdataset = 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 URLsrun = 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 analysisconst 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 URLsconst 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 runcurl -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 datasetcurl "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
- Create a new Zap with a trigger (e.g., "Every Day" schedule or "New Row in Google Sheets")
- Add an action: Apify -- Run Actor
- Select
lazymac/seo-analyzerand configure the URL input - Add a downstream action to send results to Slack, Google Sheets, email, or any other Zapier-connected app
- Map the
overallScore,grade, andsummary.issuesfields to your destination
Make (Integromat)
- Create a new scenario
- Add the Apify module and select "Run an Actor"
- Set the actor to
lazymac/seo-analyzerwith your desired URL - Add a router to branch based on the score (e.g., send Slack alert if score < 70)
- 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 ApifyClientimport gspreadfrom oauth2client.service_account import ServiceAccountCredentials# Run the SEO analysisclient = 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 Sheetsscope = ["https://spreadsheets.google.com/feeds"]creds = ServiceAccountCredentials.from_json_keyfile_name("credentials.json", scope)gc = gspread.authorize(creds)sheet = gc.open("SEO Tracker").sheet1for 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:
- Go to Actor runs in the Apify Console
- Set up a webhook with event
ACTOR.RUN.SUCCEEDED - Point the webhook URL to your endpoint (Slack incoming webhook, Discord webhook, custom API)
- 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 Checkrun: |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 ]; thenecho "::warning::SEO score is below 70 ($SCORE). Review the issues before merging."fi
Tips and Tricks
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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