Package Exports
- easy-seo-checker
- easy-seo-checker/react
Readme
easy-seo-checker
Lightweight client-side SEO analyzer for web pages.
Analyzes the rendered DOM, calculates an SEO score (0β100) with clear labels, and generates actionable suggestions β all directly in the browser with zero runtime dependencies.
Features
- π SEO scoring (0β100) with clear labels
- π DOM analysis for titles, meta tags, headings, images, links, and more
- π§ Actionable SEO recommendations you can surface in UIs
- β‘ Zero runtime dependencies
- π Browser-only (runs after page render)
- βοΈ Optional React hook (
easy-seo-checker/react) - π― Ignore elements with
[data-seo-ignore] - π¦ Small bundle size
Installation
npm install easy-seo-checkerThat's it β the core library has zero runtime dependencies and works with any browser framework.
Framework Compatibility
The core entry (easy-seo-checker) is framework-agnostic. It works anywhere the browser DOM is available:
| Framework | Supported | Entry point |
|---|---|---|
| Vanilla JS | Yes | easy-seo-checker |
| React | Yes | easy-seo-checker + optional easy-seo-checker/react hook |
| Angular | Yes | easy-seo-checker |
| Vue | Yes | easy-seo-checker |
| Svelte | Yes | easy-seo-checker |
| Next.js / Nuxt / Angular Universal | Client-side only | Call after mount, not during SSR |
| Node.js / Deno / Bun (server) | No | Requires browser DOM |
The optional easy-seo-checker/react sub-path provides a useSeoPageAnalysis hook for React projects. React is listed as an optional peer dependency β non-React projects won't install or download it.
Quick Start
Vanilla / any framework
Run the analyzer after the page has rendered:
import { getSeoPageAnalysis, getScoreLabel } from "easy-seo-checker";
const result = getSeoPageAnalysis(window.location.pathname);
console.log("Score:", result.score);
console.log("Label:", getScoreLabel(result.score));
console.log("Suggestions:", result.recommendations);With options
import { getSeoPageAnalysis } from "easy-seo-checker";
const result = getSeoPageAnalysis(window.location.pathname, {
ignoreSelector: ".admin-panel, [data-seo-ignore]",
});Angular
import { Component, AfterViewInit } from "@angular/core";
import { getSeoPageAnalysis, getScoreLabel } from "easy-seo-checker";
@Component({ selector: "app-seo", template: `<p>Score: {{ result?.score }}</p>` })
export class SeoComponent implements AfterViewInit {
result: ReturnType<typeof getSeoPageAnalysis> | null = null;
ngAfterViewInit() {
this.result = getSeoPageAnalysis(window.location.pathname);
}
}Vue
<script setup>
import { ref, onMounted } from "vue";
import { getSeoPageAnalysis, getScoreLabel } from "easy-seo-checker";
const result = ref(null);
onMounted(() => {
result.value = getSeoPageAnalysis(window.location.pathname);
});
</script>
<template>
<p v-if="result">Score: {{ result.score }} β {{ getScoreLabel(result.score) }}</p>
</template>Svelte
<script>
import { onMount } from "svelte";
import { getSeoPageAnalysis, getScoreLabel } from "easy-seo-checker";
let result = null;
onMount(() => {
result = getSeoPageAnalysis(window.location.pathname);
});
</script>
{#if result}
<p>Score: {result.score} β {getScoreLabel(result.score)}</p>
{/if}React (optional hook)
import { useEffect } from "react";
import { getScoreLabel } from "easy-seo-checker";
import { useSeoPageAnalysis } from "easy-seo-checker/react";
function SeoReviewPanel() {
const pathname = typeof window !== "undefined" ? window.location.pathname : null;
const { result, run, reset, loading, error } = useSeoPageAnalysis(pathname, {
runOnMount: false,
});
useEffect(() => {
if (!pathname) return;
run();
}, [pathname, run]);
if (loading) return <p>Analyzingβ¦</p>;
if (error) return <p>Error: {error.message}</p>;
if (!result) return <button onClick={run}>Run SEO analysis</button>;
return (
<div>
<p>
Score: {result.score} β {getScoreLabel(result.score)}
</p>
<ul>
{result.recommendations.map((r, i) => (
<li key={i}>{r}</li>
))}
</ul>
<button onClick={reset}>Clear</button>
</div>
);
}Example Output
{
score: 82,
label: "Good",
recommendations: [
"Meta description is missing",
"Add alt text to 3 images",
"Consider adding structured data (JSON-LD)"
]
}Browser Only
This package runs only in the browser because it relies on:
documentwindowlocation
Do not run during SSR (Next.js, Nuxt, etc.).
Instead, run it after the page mounts (e.g. in useEffect, onMounted, ngAfterViewInit, onMount, etc.).
Ignore Selector
Elements with the attribute [data-seo-ignore] are excluded from analysis by default. Add this attribute to admin UI, modals, or chatbots you want excluded:
<div data-seo-ignore>
<!-- This block is ignored by the analyzer -->
</div>You can customize this via the ignoreSelector option or pass your own ignoreSelector when calling getSeoPageAnalysis.
API
Main entry (easy-seo-checker)
| Export | Description |
|---|---|
getSeoPageAnalysis(pathname, options?) |
Full DOM analysis; returns SeoPageAnalysisResult |
getMainContentRoot(ignoreSelector?) |
First main, article, or .content outside ignored containers |
getPageParagraphs(ignoreSelector?) |
All <p> elements outside ignored containers |
calculateSeoScore(result) |
Score 0β100 from a SeoAnalysisResult |
generateSeoSuggestions(result) |
Suggestion strings from a SeoAnalysisResult |
getScoreColor(score) |
Hex color string (e.g. "#16a34a" for green) |
getScoreLabel(score) |
Label: "Excellent", "Good", "Needs Improvement", or "Poor" |
Options
interface SeoAnalyzerOptions {
/** CSS selector for elements to exclude. Default: "[data-seo-ignore]" */
ignoreSelector?: string;
}React entry (easy-seo-checker/react)
| Export | Description |
|---|---|
useSeoPageAnalysis(pathname, options?) |
Returns { result, run, reset, loading, error } |
Hook Options
interface UseSeoPageAnalysisOptions extends SeoAnalyzerOptions {
/** Run analysis once when pathname is set. Default: false */
runOnMount?: boolean;
}Types
All types are exported from the main entry:
SeoAnalyzerOptionsSeoAnalysisResultSeoPageAnalysisResultSeoPageImagesResultSeoPageKeywordsResultSeoPageAiSignalsResultSeoPageContentStructureResultSeoPageKeywordDensityResultSeoPageUrlSlugResult
Score Breakdown (100 points)
| Category | Points | Criteria |
|---|---|---|
| Meta tags | 30 | Title present (10), title length 30β60 (5), description present (10), description length 120β160 (5) |
| Open Graph | 20 | og:title (5), og:description (5), og:image (5), twitter:card (5) |
| Headings | 20 | Single H1 (15) or multiple H1s (5), H2 present (5) |
| Images | 15 | Scaled by alt-text coverage; full marks if no images |
| Links | 10 | Internal links (5), external links (5) |
| Structured data | 5 | Valid JSON-LD present |
Use Cases
- SEO audit tools
- CMS SEO panels
- Browser extensions
- Admin dashboards
- Static site SEO validation
- Content publishing workflows
Performance
The analyzer scans the rendered DOM once and is designed to be lightweight.
Typical runtime: <10β―ms for most pages (depends on page size and device).
Browser Support
- Chrome
- Edge
- Firefox
- Safari
Requires modern DOM APIs.
SEO Score: 82 (Good)
β Title tag present
β H1 found
β Missing meta description
β 3 images missing alt textYou can build your own UI on top of SeoPageAnalysisResult to match your product.
Development
npm install # Install dependencies
npm run dev # Watch mode
npm run build # Production build
npm test # Run tests
npm run lint # Run linterSee CONTRIBUTING.md for guidelines.
License
MIT β Akash Arora