seo-manager-pro
v26.6.20
Published
SEO + AEO manager for Angular, React, Vue and Vanilla JS — search engines and AI answer engines.
Maintainers
Readme
SEO Manager Pro
A lightweight, framework-agnostic SEO + AEO manager for Angular, React, Vue, and Vanilla JS SPAs.
The package is split into two independent modules:
| Module | Class | Purpose |
|--------|-------|---------|
| SEO | SeoManager | Google, Bing, social previews (Open Graph, Twitter, canonical, robots) |
| AEO | AeoManager | AI answer engines (ChatGPT, Claude, Perplexity) — llms.txt, page summaries, AI robots, FAQ/HowTo schema |
Use them together or separately. Each has its own reset() method and does not interfere with the other.
Features
| Category | What you get |
|----------|--------------|
| Basic Meta | title, description, keywords, author, theme-color, language (<html lang>) |
| Open Graph | og:title, og:description, og:image, image alt/size, og:url, og:type, og:site_name, og:locale |
| Article OG | article:published_time, article:modified_time, article:author, article:section, article:tag |
| Twitter Cards | twitter:card, twitter:site, twitter:creator, title, description, image |
| Indexing | robots + googlebot, canonical URL |
| International | hreflang alternate links |
| Pagination / Feeds | prev, next, alternate, manifest, sitemap link tags |
| Structured Data | Built-in Schema.org types + raw jsonLd for anything else |
| Breadcrumbs | Auto-generates BreadcrumbList JSON-LD from a simple array |
| Icons | Dynamic favicon and apple-touch-icon |
| Cleanup | resetSeo() removes everything the library injected |
| SSR-safe | No-op when document is unavailable (Node / SSR) |
AEO (Answer Engine Optimization)
| Category | What you get |
|----------|--------------|
| Page Summary | Machine-readable JSON + abstract / summary meta for AI parsers |
| AI Crawlers | Per-bot meta hints (GPTBot, ClaudeBot, PerplexityBot, …) |
| llms.txt | generateLlmsTxt() + discoverable link tag |
| Markdown alt | Link to Markdown version of the page |
| FAQ / HowTo | Auto FAQPage and HowTo JSON-LD |
| Entities | @graph entity markup with sameAs for AI citation |
| Citation | Author, dates, license, publisher for AI attribution |
| Speakable | SpeakableSpecification for voice assistants |
| Presets | AeoPresets.article(), .product(), .faq(), .howTo() |
| Cleanup | resetAeo() removes all AEO-injected tags |
Installation
npm install seo-manager-proyarn add seo-manager-proQuick Start
import { SeoManager, AeoManager, AeoPresets } from 'seo-manager-pro';
// Classic SEO (search engines + social)
SeoManager.updateSeo({
title: 'Home Page | My Shop',
description: 'Welcome to the best online store.',
image: 'https://example.com/og-image.jpg',
canonicalUrl: 'https://example.com/',
robots: 'index,follow',
openGraph: { siteName: 'My Shop', locale: 'en_US' },
twitter: { card: 'summary_large_image', site: '@myshop' },
});
// AEO (AI answer engines)
AeoManager.updateAeo({
llmsTxtUrl: 'https://example.com/llms.txt',
pageSummary: {
title: 'My Shop',
description: 'Online store for electronics and accessories.',
url: 'https://example.com/',
keyPoints: ['Free shipping', '24/7 support', 'Secure checkout'],
topics: ['ecommerce', 'electronics'],
},
aiRobots: {
GPTBot: 'allow',
ClaudeBot: 'allow',
PerplexityBot: 'allow',
},
});
// Or use an AEO preset (ideal for AI coding tools)
AeoManager.updateAeo(
AeoPresets.article({
title: '10 SEO Tips',
description: 'Practical tips for SPA SEO.',
url: 'https://example.com/blog/seo-tips',
author: 'Jane Doe',
publishedAt: '2025-06-01T10:00:00Z',
keyPoints: ['Use canonical URLs', 'Add structured data'],
})
);
SeoManagerProis still exported as an alias forSeoManager(backward compatible).
API Reference
SEO — SeoManager.updateSeo(config: SeoConfig)
Updates all SEO tags for the current page. Previous SEO tags injected by this library are removed first.
SEO — SeoManager.resetSeo()
Removes every SEO tag/link/script the library added and clears document.title and <html lang>.
AEO — AeoManager.updateAeo(config: AeoConfig)
Injects AI-friendly metadata: page summary JSON, FAQ/HowTo schema, entity graphs, llms.txt link, and AI crawler hints.
AEO — AeoManager.resetAeo()
Removes all AEO-injected tags without touching SEO tags.
AEO — AeoManager.generateLlmsTxt(config: LlmsTxtConfig): string
Generates llms.txt markdown content. Host it at https://yoursite.com/llms.txt:
const content = AeoManager.generateLlmsTxt({
siteName: 'My Shop',
description: 'Online electronics store.',
pages: [
{ title: 'Products', url: 'https://example.com/products', summary: 'All products' },
{ title: 'FAQ', url: 'https://example.com/faq', summary: 'Common questions' },
],
});
// Serve `content` as a static file at /llms.txtAEO — AeoPresets
| Method | Use case |
|--------|----------|
| AeoPresets.article({...}) | Blog posts and articles |
| AeoPresets.product({...}) | Product pages |
| AeoPresets.faq({...}) | FAQ pages |
| AeoPresets.howTo({...}) | Tutorials and guides |
Subpath imports
import { SeoManager } from 'seo-manager-pro/seo';
import { AeoManager, AeoPresets } from 'seo-manager-pro/aeo';SeoConfig Options
Core fields
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| title | string | ✅ | Page title (<title>) |
| description | string | ✅ | Meta description |
| image | string | | Default image for Open Graph and Twitter |
| canonicalUrl | string | | Canonical URL (<link rel="canonical">) |
| robots | RobotsDirective | | Crawler directive — also sets googlebot |
| keywords | string \| string[] | | Meta keywords (comma-separated if array) |
| author | string | | Content author |
| themeColor | string | | Browser UI color (theme-color) |
| language | string | | Sets <html lang="..."> (e.g. en, fa, de) |
| favicon | string | | Favicon URL |
| appleTouchIcon | string | | Apple touch icon URL |
robots values
'index,follow' // default — allow indexing and following links
'noindex,nofollow' // hide page and don't follow links
'index,nofollow' // index page but don't follow links
'noindex,follow' // don't index but follow linksopenGraph
| Field | Type | Description |
|-------|------|-------------|
| title | string | Overrides og:title (defaults to title) |
| type | OpenGraphType | website, article, product, profile, book, video.other |
| url | string | Overrides og:url (defaults to canonicalUrl) |
| siteName | string | og:site_name |
| locale | string | e.g. en_US, fa_IR |
| imageAlt | string | og:image:alt |
| imageWidth | number | og:image:width |
| imageHeight | number | og:image:height |
| publishedTime | string | ISO 8601 — article:published_time |
| modifiedTime | string | ISO 8601 — article:modified_time |
| author | string | article:author |
| section | string | article:section |
| tags | string[] | Multiple article:tag meta tags |
twitter
| Field | Type | Description |
|-------|------|-------------|
| card | TwitterCardType | summary, summary_large_image, app, player |
| site | string | @username of the site |
| creator | string | @username of the content creator |
| title | string | Overrides page title for Twitter |
| description | string | Overrides description for Twitter |
| image | string | Overrides image for Twitter |
If
twitter.cardis omitted,summary_large_imageis used whenimageis set; otherwisesummary.
hreflang
For multilingual / regional SEO:
hreflang: [
{ lang: 'en', url: 'https://example.com/en/page' },
{ lang: 'fa', url: 'https://example.com/fa/page' },
{ lang: 'x-default', url: 'https://example.com/page' },
]alternateLinks
Pagination, feeds, manifest, and other <link rel="..."> tags:
alternateLinks: [
{ rel: 'prev', href: 'https://example.com/blog?page=1' },
{ rel: 'next', href: 'https://example.com/blog?page=3' },
{ rel: 'sitemap', href: 'https://example.com/sitemap.xml', type: 'application/xml' },
]breadcrumbs
Automatically builds a BreadcrumbList Schema.org script:
breadcrumbs: [
{ name: 'Home', url: 'https://example.com/' },
{ name: 'Blog', url: 'https://example.com/blog' },
{ name: 'Post Title', url: 'https://example.com/blog/post' },
]schema
Inject typed Schema.org JSON-LD:
schema: [
{
type: 'Product',
data: {
name: 'iPhone 15',
description: 'The best smartphone ever.',
image: 'https://example.com/iphone.jpg',
offers: {
'@type': 'Offer',
price: 999,
priceCurrency: 'USD',
availability: 'https://schema.org/InStock',
},
},
},
{
type: 'FAQPage',
data: {
mainEntity: [
{
'@type': 'Question',
name: 'Is it waterproof?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes, it has IP68 rating.',
},
},
],
},
},
]jsonLd
For schemas not covered by built-in types, pass raw JSON-LD objects:
jsonLd: [
{
'@context': 'https://schema.org',
'@type': 'HowTo',
name: 'How to install SEO Manager Pro',
step: [
{ '@type': 'HowToStep', text: 'Run npm install seo-manager-pro' },
{ '@type': 'HowToStep', text: 'Call SeoManagerPro.updateSeo(...)' },
],
},
]customMetaTags
Any extra <meta name="..." content="..."> tags:
customMetaTags: [
{ name: 'referrer', content: 'strict-origin-when-cross-origin' },
{ name: 'format-detection', content: 'telephone=no' },
]AeoConfig Options
| Field | Type | Description |
|-------|------|-------------|
| pageSummary | PageSummary | Title, description, key points, topics, entities — injected as JSON |
| aiRobots | Partial<Record<AiCrawlerBot, AiCrawlerPolicy>> | Per-bot policy: GPTBot, ClaudeBot, PerplexityBot, … |
| llmsTxtUrl | string | URL to /llms.txt (adds discoverable link tag) |
| markdownUrl | string | Alternate Markdown version of the page |
| faq | FaqItem[] | Auto-builds FAQPage JSON-LD |
| howTo | HowToConfig | Auto-builds HowTo JSON-LD |
| speakable | SpeakableConfig | CSS/XPath selectors for voice assistants |
| citation | CitationConfig | Author, dates, license for AI attribution |
| entities | EntityReference[] | Named entities with optional sameAs URLs |
| schema | AeoSchemaConfig[] | Typed AI-oriented Schema.org blocks |
| jsonLd | Record<string, unknown>[] | Raw JSON-LD |
| jsonLdGraph | Record<string, unknown>[] | Multiple nodes in one @graph |
| customAiMetaTags | { name, content }[] | Extra AI-oriented meta tags |
Supported AI crawlers (aiRobots)
GPTBot, ChatGPT-User, ClaudeBot, anthropic-ai, Google-Extended, PerplexityBot, Bytespider, Applebot-Extended, cohere-ai, CCBot
Full AEO example
AeoManager.updateAeo({
llmsTxtUrl: 'https://example.com/llms.txt',
markdownUrl: 'https://example.com/blog/seo-tips.md',
pageSummary: {
title: '10 SEO Tips for SPAs',
description: 'A practical guide to SPA SEO and AEO.',
url: 'https://example.com/blog/seo-tips',
language: 'en',
keyPoints: [
'Set canonical URLs on every route',
'Add FAQ schema for AI snippets',
'Publish llms.txt for agent discovery',
],
topics: ['seo', 'spa', 'aeo'],
entities: [
{ name: 'Google', type: 'Organization', sameAs: ['https://www.google.com'] },
],
},
aiRobots: {
GPTBot: 'allow',
ClaudeBot: 'allow',
'Google-Extended': 'disallow',
},
citation: {
author: 'Jane Doe',
publishedAt: '2025-06-01T10:00:00Z',
license: 'https://creativecommons.org/licenses/by/4.0/',
},
faq: [
{ question: 'What is AEO?', answer: 'Answer Engine Optimization for AI systems.' },
],
jsonLdGraph: [
{ '@type': 'WebSite', name: 'My Blog', url: 'https://example.com' },
{ '@type': 'WebPage', name: '10 SEO Tips', url: 'https://example.com/blog/seo-tips' },
],
});Supported Schema Types
| Type | Best for |
|------|----------|
| Product | E-commerce product pages |
| FAQPage | FAQ sections |
| Article | Generic articles |
| BlogPosting | Blog posts |
| Organization | Company / brand pages |
| WebSite | Site-wide search box, publisher info |
| WebPage | Generic landing pages |
| LocalBusiness | Local SEO (address, hours, geo) |
| Person | Author / profile pages |
| BreadcrumbList | Manual breadcrumb schema (or use breadcrumbs helper) |
| Event | Events, webinars, concerts |
| VideoObject | Video pages |
| Recipe | Recipe pages |
| SoftwareApplication | Apps, SaaS products |
Framework Examples
React (with useEffect)
import { useEffect } from 'react';
import { SeoManagerPro } from 'seo-manager-pro';
function ProductPage({ product }) {
useEffect(() => {
SeoManagerPro.updateSeo({
title: `${product.name} | My Shop`,
description: product.summary,
image: product.image,
canonicalUrl: `https://example.com/products/${product.slug}`,
robots: 'index,follow',
openGraph: { type: 'product' },
schema: [
{
type: 'Product',
data: {
name: product.name,
image: product.image,
offers: {
'@type': 'Offer',
price: product.price,
priceCurrency: 'USD',
},
},
},
],
});
return () => SeoManagerPro.resetSeo();
}, [product]);
return <div>{product.name}</div>;
}Vue 3 (onMounted / watch)
import { watch, onUnmounted } from 'vue';
import { SeoManagerPro } from 'seo-manager-pro';
watch(
() => route.fullPath,
() => {
SeoManagerPro.updateSeo({
title: 'My Vue App',
description: 'Built with Vue 3',
canonicalUrl: `https://example.com${route.fullPath}`,
});
},
{ immediate: true }
);
onUnmounted(() => SeoManagerPro.resetSeo());Angular (service or resolver)
import { Injectable } from '@angular/core';
import { SeoManagerPro, SeoConfig } from 'seo-manager-pro';
@Injectable({ providedIn: 'root' })
export class SeoService {
update(config: SeoConfig): void {
SeoManagerPro.updateSeo(config);
}
reset(): void {
SeoManagerPro.resetSeo();
}
}Use in a route resolver or ngOnInit / ngOnDestroy of your page component.
Vanilla JS
<script type="module">
import { SeoManagerPro } from 'seo-manager-pro';
SeoManagerPro.updateSeo({
title: 'Contact Us',
description: 'Get in touch with our team.',
canonicalUrl: 'https://example.com/contact',
});
</script>Blog Post Example (full SEO)
SeoManagerPro.updateSeo({
title: '10 SEO Tips for SPAs | My Blog',
description: 'Learn how to optimize single-page apps for search engines.',
image: 'https://example.com/blog/seo-tips/cover.jpg',
canonicalUrl: 'https://example.com/blog/seo-tips',
robots: 'index,follow',
author: 'Jane Doe',
language: 'en',
openGraph: {
type: 'article',
siteName: 'My Blog',
locale: 'en_US',
publishedTime: '2025-06-01T10:00:00Z',
modifiedTime: '2025-06-15T14:30:00Z',
author: 'Jane Doe',
section: 'SEO',
tags: ['seo', 'spa', 'javascript'],
imageAlt: 'SEO tips cover image',
},
twitter: {
card: 'summary_large_image',
site: '@myblog',
creator: '@janedoe',
},
breadcrumbs: [
{ name: 'Home', url: 'https://example.com/' },
{ name: 'Blog', url: 'https://example.com/blog' },
{ name: '10 SEO Tips for SPAs', url: 'https://example.com/blog/seo-tips' },
],
schema: [
{
type: 'BlogPosting',
data: {
headline: '10 SEO Tips for SPAs',
author: { '@type': 'Person', name: 'Jane Doe' },
datePublished: '2025-06-01T10:00:00Z',
dateModified: '2025-06-15T14:30:00Z',
image: 'https://example.com/blog/seo-tips/cover.jpg',
},
},
],
});Local Business Example
SeoManagerPro.updateSeo({
title: 'Coffee House Tehran | Best Coffee',
description: 'Specialty coffee in downtown Tehran. Open daily 8 AM – 10 PM.',
canonicalUrl: 'https://example.com/tehran-coffee',
robots: 'index,follow',
language: 'fa',
openGraph: {
type: 'website',
locale: 'fa_IR',
siteName: 'Coffee House',
},
schema: [
{
type: 'LocalBusiness',
data: {
name: 'Coffee House Tehran',
address: {
'@type': 'PostalAddress',
streetAddress: 'Valiasr St',
addressLocality: 'Tehran',
addressCountry: 'IR',
},
geo: {
'@type': 'GeoCoordinates',
latitude: 35.6892,
longitude: 51.3890,
},
openingHours: 'Mo-Su 08:00-22:00',
telephone: '+98-21-12345678',
},
},
],
});SSR Notes
The library checks for document before touching the DOM. During server-side rendering, updateSeo() and resetSeo() are safe no-ops.
For best SEO in SSR frameworks (Next.js, Nuxt, Angular SSR), prefer setting meta tags in server-rendered HTML or framework-specific head APIs. Use SEO Manager Pro on the client for SPA route transitions and dynamic pages.
Best Practices
- Call on every route change — SPAs don't reload the page; update SEO when navigation happens.
- Use
resetSeo()on unmount — Avoid stale tags when leaving a page. - Always set
canonicalUrl— Prevents duplicate-content issues with query strings or trailing slashes. - Use absolute URLs — For
image,canonicalUrl, and schema URLs. - Match OG and Twitter — The library auto-fills Twitter from title/description/image; override only when needed.
- Add
hreflangfor multilingual sites — Includex-defaultfor the fallback locale. - Prefer JSON-LD — Google recommends JSON-LD for structured data; this library injects it automatically.
- Validate structured data — Test with Google Rich Results Test.
TypeScript
All types are exported from the package:
import {
SeoManager,
SeoManagerPro,
AeoManager,
AeoPresets,
SeoConfig,
AeoConfig,
SchemaType,
OpenGraphConfig,
TwitterConfig,
PageSummary,
LlmsTxtConfig,
} from 'seo-manager-pro';Includes:
- ✅ Angular Demo
- ✅ React Demo
- ✅ Vanilla JavaScript Demo
License
MIT © MohammadBagher Sharifi
