# @push.rocks/smartsitemap
> πΊοΈ **Modern sitemap generation and management for TypeScript** β Create XML sitemaps from RSS feeds, YAML configs, or programmatically. Perfect for SEO optimization and search engine indexing.
## Install
```bash
# Using pnpm (recommended)
pnpm install @push.rocks/smartsitemap
# Using npm
npm install @push.rocks/smartsitemap
# Using yarn
yarn add @push.rocks/smartsitemap
```
## Features
β¨ **Multiple Sitemap Types**
- π° **News Sitemaps** β Generate Google News-compatible sitemaps from RSS feeds
- π **Website Sitemaps** β Standard XML sitemaps with customizable update frequencies
- π **Dynamic Generation** β Create sitemaps from various sources (RSS, YAML, arrays)
π **Developer-Friendly**
- πͺ **Full TypeScript Support** β Complete type definitions and interfaces
- π― **Simple API** β Intuitive methods for common sitemap operations
- π¦ **Zero Configuration** β Works out of the box with sensible defaults
- π **Sitemap Parsing** β Read and parse existing sitemaps from URLs
π¨ **Flexible Input Sources**
- RSS/Atom feeds (URL or string)
- YAML configuration files
- URL info arrays
- Article objects
## Quick Start
```typescript
import { SmartSitemap } from '@push.rocks/smartsitemap';
const sitemap = new SmartSitemap();
// Generate a news sitemap from RSS feed
const newsSitemap = await sitemap.createSitemapNewsFromFeedUrl(
'https://yoursite.com/rss/'
);
console.log(newsSitemap);
```
## Usage Examples
### π° Creating News Sitemaps
#### From RSS Feed URL
Perfect for blogs, news sites, and content platforms with RSS feeds:
```typescript
import { SmartSitemap } from '@push.rocks/smartsitemap';
const sitemap = new SmartSitemap();
// Fetch RSS feed and generate Google News sitemap
const newsSitemap = await sitemap.createSitemapNewsFromFeedUrl(
'https://coffee.link/rss/'
);
console.log(newsSitemap);
```
**Output:**
```xml
https://coffee.link/article-url/
en
some name
2025-11-18T16:57:15.000Z
Article Title
```
#### From RSS Feed String
When you already have the RSS XML content:
```typescript
import { SmartSitemap } from '@push.rocks/smartsitemap';
const rssFeedXml = `
`;
const sitemap = new SmartSitemap();
const newsSitemap = await sitemap.createSitemapNewsFromAFeedStringArg(rssFeedXml);
console.log(newsSitemap);
```
#### From Article Array
Create news sitemaps programmatically from your CMS or database:
```typescript
import { SmartSitemap } from '@push.rocks/smartsitemap';
import type { IArticle } from '@tsclass/tsclass';
const articles: IArticle[] = [
{
title: 'Breaking News Article',
content: 'Article content here...',
url: 'https://yoursite.com/breaking-news',
// Add other required IArticle properties
},
// More articles...
];
const sitemap = new SmartSitemap();
const newsSitemap = await sitemap.createSitemapNewsFromArticleArray(articles);
console.log(newsSitemap);
```
### π Creating Website Sitemaps
#### From YAML Configuration
Define your sitemap structure in YAML for easy maintenance:
```typescript
import { SmartSitemap } from '@push.rocks/smartsitemap';
const yamlConfig = `
daily:
- https://yoursite.com/
- https://yoursite.com/blog
- https://yoursite.com/products
`;
const sitemap = new SmartSitemap();
const websiteSitemap = await sitemap.createSitemapFromYmlString(yamlConfig);
console.log(websiteSitemap);
```
**Output:**
```xml
https://yoursite.com/
2025-11-19T12:00:00.000Z
daily
```
#### From URL Info Array
Fine-grained control over each URL's properties:
```typescript
import { SmartSitemap, IUrlInfo } from '@push.rocks/smartsitemap';
const urlInfos: IUrlInfo[] = [
{
url: 'https://yoursite.com/',
timestamp: Date.now(),
frequency: 'daily', // How often the page changes
},
{
url: 'https://yoursite.com/about',
timestamp: Date.now() - 86400000, // Yesterday
frequency: 'monthly',
},
{
url: 'https://yoursite.com/blog',
timestamp: Date.now(),
frequency: 'weekly',
},
];
const sitemap = new SmartSitemap();
const websiteSitemap = await sitemap.createSitemapFromUrlInfoArray(urlInfos);
console.log(websiteSitemap);
```
**Available Frequencies:**
- `'never'` β Archived content
- `'daily'` β Updated every day
- `'weekly'` β Updated weekly
- `'monthly'` β Updated monthly
- `'yearly'` β Updated annually
### π Parsing Existing Sitemaps
Read and parse sitemaps from remote URLs:
```typescript
import { SmartSitemap } from '@push.rocks/smartsitemap';
const sitemap = new SmartSitemap();
// Parse a sitemap from URL
const parsedSitemap = await sitemap.parseSitemapUrl(
'https://www.theverge.com/sitemaps/google_news'
);
console.log(parsedSitemap);
// {
// urlset: {
// url: [
// { loc: '...', lastmod: '...', changefreq: '...' },
// // ...
// ]
// }
// }
```
#### Parse Sitemap String
If you already have the sitemap XML:
```typescript
import { SmartSitemap } from '@push.rocks/smartsitemap';
const sitemapXml = `
`;
const sitemap = new SmartSitemap();
const parsed = await sitemap.parseSitemap(sitemapXml);
console.log(parsed);
```
## Advanced Usage
### Working with Lower-Level Classes
For more control, use the individual sitemap classes directly:
#### SitemapWebsite Class
```typescript
import { SitemapWebsite, IUrlInfo } from '@push.rocks/smartsitemap';
const websiteSitemap = new SitemapWebsite();
// Add URLs one by one
websiteSitemap.addUrl({
url: 'https://yoursite.com/page1',
timestamp: Date.now(),
frequency: 'daily',
});
websiteSitemap.addUrl({
url: 'https://yoursite.com/page2',
timestamp: Date.now(),
frequency: 'weekly',
});
// Export to XML
const xml = websiteSitemap.exportSitemapXml();
console.log(xml);
```
#### SitemapNews Class
```typescript
import { SitemapNews } from '@push.rocks/smartsitemap';
const newsSitemap = new SitemapNews({});
// Add from RSS feed URL
await newsSitemap.readAndAddFromRssFeedUrl('https://yoursite.com/rss');
// Or from RSS string
await newsSitemap.readAndAddFromRssFeedString(rssFeedXml);
// Or from articles
await newsSitemap.readAndParseArticles(articles);
// Export to XML
const xml = newsSitemap.exportSitemapXml();
console.log(xml);
```
### Combining Multiple Sources
Create comprehensive sitemaps by combining different data sources:
```typescript
import { SitemapWebsite } from '@push.rocks/smartsitemap';
const sitemap = new SitemapWebsite();
// Add static pages
sitemap.addUrl({
url: 'https://yoursite.com/',
timestamp: Date.now(),
frequency: 'daily',
});
// Add dynamic content from database
const blogPosts = await fetchBlogPostsFromDB();
for (const post of blogPosts) {
sitemap.addUrl({
url: post.url,
timestamp: post.updatedAt,
frequency: 'weekly',
});
}
// Add pages from CMS
const cmsPages = await fetchPagesFromCMS();
for (const page of cmsPages) {
sitemap.addUrl({
url: page.url,
timestamp: page.lastModified,
frequency: page.updateFrequency,
});
}
const xml = sitemap.exportSitemapXml();
```
## TypeScript Types
### IUrlInfo
```typescript
interface IUrlInfo {
url: string;
timestamp: number; // Unix timestamp in milliseconds
frequency?: TUpdateFrequency;
}
type TUpdateFrequency = 'never' | 'daily' | 'weekly' | 'monthly' | 'yearly';
```
### IParsedSiteMap
```typescript
interface IParsedSiteMap {
urlset: {
url:
| { loc: string; lastmod: string; changefreq: string }
| { loc: string; lastmod: string; changefreq: string }[]
| {
loc: string;
'news:news': {
'news:publication': [];
'news:keywords': string;
'news:publication_date': string;
'news:title': string;
};
}[];
};
}
```
### IRssItem
```typescript
interface IRssItem {
[key: string]: any;
link?: string;
guid?: string;
title?: string;
pubDate?: string;
creator?: string;
content?: string;
isoDate?: string;
categories?: string[];
contentSnippet?: string;
enclosure?: any;
}
```
## Real-World Integration Examples
### Express.js Server
```typescript
import express from 'express';
import { SmartSitemap } from '@push.rocks/smartsitemap';
const app = express();
const sitemap = new SmartSitemap();
// Serve sitemap dynamically
app.get('/sitemap.xml', async (req, res) => {
const urlInfos = await getUrlsFromDatabase();
const xml = await sitemap.createSitemapFromUrlInfoArray(urlInfos);
res.header('Content-Type', 'application/xml');
res.send(xml);
});
// News sitemap from RSS
app.get('/news-sitemap.xml', async (req, res) => {
const xml = await sitemap.createSitemapNewsFromFeedUrl(
'https://yoursite.com/rss'
);
res.header('Content-Type', 'application/xml');
res.send(xml);
});
app.listen(3000);
```
### Static Site Generator
```typescript
import { SmartSitemap } from '@push.rocks/smartsitemap';
import { writeFileSync } from 'fs';
async function generateSitemap() {
const sitemap = new SmartSitemap();
// Get all pages from your static site
const pages = [
{ url: 'https://yoursite.com/', frequency: 'daily' as const },
{ url: 'https://yoursite.com/about', frequency: 'monthly' as const },
// ... more pages
];
const urlInfos = pages.map(page => ({
url: page.url,
timestamp: Date.now(),
frequency: page.frequency,
}));
const xml = await sitemap.createSitemapFromUrlInfoArray(urlInfos);
// Write to public directory
writeFileSync('./public/sitemap.xml', xml);
console.log('β
Sitemap generated!');
}
generateSitemap();
```
### Content Management System
```typescript
import { SmartSitemap, IUrlInfo } from '@push.rocks/smartsitemap';
class CMSSitemapGenerator {
private sitemap = new SmartSitemap();
async generateCompleteSitemap(): Promise {
const urlInfos: IUrlInfo[] = [];
// Add all content types
urlInfos.push(...await this.getPageUrls());
urlInfos.push(...await this.getBlogUrls());
urlInfos.push(...await this.getProductUrls());
return this.sitemap.createSitemapFromUrlInfoArray(urlInfos);
}
private async getPageUrls(): Promise {
const pages = await this.cms.getPages();
return pages.map(page => ({
url: page.url,
timestamp: page.updatedAt,
frequency: 'weekly',
}));
}
private async getBlogUrls(): Promise {
const posts = await this.cms.getBlogPosts();
return posts.map(post => ({
url: post.url,
timestamp: post.publishedAt,
frequency: 'monthly',
}));
}
private async getProductUrls(): Promise {
const products = await this.cms.getProducts();
return products.map(product => ({
url: product.url,
timestamp: product.lastModified,
frequency: 'daily',
}));
}
}
```
## Best Practices
### 1. Update Frequencies
Choose appropriate update frequencies for better crawling:
```typescript
// Homepage and main sections: daily
{ url: 'https://yoursite.com/', frequency: 'daily' }
// Blog posts: weekly
{ url: 'https://yoursite.com/blog/post', frequency: 'weekly' }
// Static pages: monthly or yearly
{ url: 'https://yoursite.com/about', frequency: 'monthly' }
// Archived content: never
{ url: 'https://yoursite.com/archive/2020', frequency: 'never' }
```
### 2. Sitemap Size Limits
Google recommends keeping sitemaps under 50,000 URLs and 50MB. Split large sitemaps:
```typescript
import { SitemapWebsite } from '@push.rocks/smartsitemap';
async function generateSitemaps(allUrls: IUrlInfo[]) {
const chunkSize = 50000;
const chunks = [];
for (let i = 0; i < allUrls.length; i += chunkSize) {
chunks.push(allUrls.slice(i, i + chunkSize));
}
const sitemaps = await Promise.all(
chunks.map(async (chunk, index) => {
const sitemap = new SitemapWebsite();
chunk.forEach(url => sitemap.addUrl(url));
const xml = sitemap.exportSitemapXml();
// Save as sitemap-1.xml, sitemap-2.xml, etc.
return { filename: `sitemap-${index + 1}.xml`, content: xml };
})
);
return sitemaps;
}
```
### 3. Cache Generated Sitemaps
Don't regenerate on every request:
```typescript
import { SmartSitemap } from '@push.rocks/smartsitemap';
class SitemapCache {
private cache: string | null = null;
private lastGenerated: number = 0;
private cacheDuration = 3600000; // 1 hour
async getSitemap(): Promise {
const now = Date.now();
if (!this.cache || now - this.lastGenerated > this.cacheDuration) {
const sitemap = new SmartSitemap();
const urls = await this.fetchUrls();
this.cache = await sitemap.createSitemapFromUrlInfoArray(urls);
this.lastGenerated = now;
}
return this.cache;
}
invalidate() {
this.cache = null;
}
private async fetchUrls() {
// Fetch from your data source
return [];
}
}
```
### 4. Submit to Search Engines
After generating your sitemap, submit it to search engines:
```typescript
// In your robots.txt
`
User-agent: *
Allow: /
Sitemap: https://yoursite.com/sitemap.xml
Sitemap: https://yoursite.com/news-sitemap.xml
`
```
Or ping search engines programmatically:
```typescript
async function submitSitemap(sitemapUrl: string) {
const encodedUrl = encodeURIComponent(sitemapUrl);
// Google
await fetch(`https://www.google.com/ping?sitemap=${encodedUrl}`);
// Bing
await fetch(`https://www.bing.com/ping?sitemap=${encodedUrl}`);
}
submitSitemap('https://yoursite.com/sitemap.xml');
```
## API Reference
### SmartSitemap
Main class for sitemap operations.
#### Methods
**`createSitemapNewsFromFeedUrl(feedUrl: string): Promise`**
- Generate a Google News sitemap from an RSS/Atom feed URL
- Returns XML string
**`createSitemapNewsFromAFeedStringArg(feedString: string): Promise`**
- Generate a Google News sitemap from RSS/Atom feed XML string
- Returns XML string
**`createSitemapNewsFromArticleArray(articles: IArticle[]): Promise`**
- Generate a Google News sitemap from an array of article objects
- Returns XML string
**`createSitemapFromYmlString(yamlString: string): Promise`**
- Generate a standard sitemap from YAML configuration
- Returns XML string
**`createSitemapFromUrlInfoArray(urlInfos: IUrlInfo[]): Promise`**
- Generate a standard sitemap from URL info array
- Returns XML string
**`parseSitemapUrl(url: string): Promise`**
- Parse a sitemap from a URL
- Returns parsed sitemap object
**`parseSitemap(sitemapXml: string): Promise`**
- Parse a sitemap from XML string
- Returns parsed sitemap object
### SitemapWebsite
Lower-level class for website sitemaps.
#### Methods
**`addUrl(urlInfo: IUrlInfo): void`**
- Add a URL to the sitemap
**`exportSitemapXml(): string`**
- Export sitemap as XML string
### SitemapNews
Lower-level class for news sitemaps.
#### Methods
**`readAndAddFromRssFeedUrl(url: string): Promise`**
- Add news items from RSS feed URL
**`readAndAddFromRssFeedString(feedString: string): Promise`**
- Add news items from RSS feed string
**`readAndParseArticles(articles: IArticle[]): Promise`**
- Add news items from article array
**`exportSitemapXml(): string`**
- Export news sitemap as XML string
## Why @push.rocks/smartsitemap?
- β
**Simple & Intuitive** β Clean API that just works
- β
**Type-Safe** β Full TypeScript support with complete type definitions
- β
**Flexible** β Multiple input sources and output formats
- β
**Battle-Tested** β Used in production across multiple projects
- β
**Modern** β ESM-first, async/await, latest standards
- β
**SEO-Friendly** β Generates valid XML sitemaps that search engines love
## Related Packages
Part of the `@push.rocks` ecosystem:
- **[@push.rocks/smartfeed](https://www.npmjs.com/package/@push.rocks/smartfeed)** β RSS/Atom feed parsing
- **[@push.rocks/smartxml](https://www.npmjs.com/package/@push.rocks/smartxml)** β XML parsing and generation
- **[@push.rocks/smartyaml](https://www.npmjs.com/package/@push.rocks/smartyaml)** β YAML parsing
## License and Legal Information
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
### Trademarks
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
### Company Information
Task Venture Capital GmbH
Registered at District court Bremen HRB 35230 HB, Germany
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.