Skip to Content
DevelopmentAPIExamples

Examples

Complete usage examples for rss.Today.

Table of Contents

Basic Parsing

Parse from URL

import { Parser } from 'rss.today'; async function parseFromURL() { const parser = new Parser(); const feed = await parser.parseURL('https://example.com/feed.xml'); console.log('Feed:', feed.title); console.log('Description:', feed.description); console.log('Items:', feed.items.length); feed.items.forEach(item => { console.log(`- ${item.title}`); console.log(` ${item.link}`); }); } parseFromURL();

Parse from String

import { Parser } from 'rss.today'; async function parseFromString() { const xml = `<?xml version="1.0" encoding="UTF-8"?> <rss version="2.0"> <channel> <title>Example Feed</title> <link>https://example.com</link> <description>An example RSS feed</description> <item> <title>First Item</title> <link>https://example.com/first</link> <description>Description of first item</description> </item> </channel> </rss>`; const parser = new Parser(); const feed = await parser.parseString(xml); console.log(feed.title); console.log(feed.items[0].title); } parseFromString();

Parse from File

import { Parser } from 'rss.today'; import * as fs from 'fs/promises'; async function parseFromFile() { const parser = new Parser(); const feed = await parser.parseFile('./feeds/my-feed.xml'); console.log(`Loaded feed: ${feed.title}`); console.log(`Total items: ${feed.items.length}`); } parseFromFile();

Feed Generation

Basic RSS Feed

import { Feed } from 'rss.today'; const feed = new Feed({ id: 'https://example.com/feed', title: 'My Blog', description: 'A blog about technology', link: 'https://example.com', copyright: '2024 My Blog', language: 'en' }); feed.addItem({ title: 'First Post', link: 'https://example.com/first-post', description: 'This is my first post', date: new Date() }); feed.addItem({ title: 'Second Post', link: 'https://example.com/second-post', description: 'This is my second post', date: new Date() }); const rss = feed.rss2(); console.log(rss);

Generate Multiple Formats

import { Feed } from 'rss.today'; const feed = new Feed({ id: 'https://example.com/feed', title: 'My Blog', link: 'https://example.com', copyright: '2024 My Blog' }); feed.addItem({ title: 'Post Title', link: 'https://example.com/post', description: 'Post description', date: new Date() }); // Generate all formats const rss2 = feed.rss2(); const atom1 = feed.atom1(); const rss1 = feed.rss1(); const rss09 = feed.rss0_9(); const json1 = feed.json1(); console.log('RSS 2.0:', rss2); console.log('Atom 1.0:', atom1); console.log('JSON Feed:', json1);

Blog Feed with Categories and Authors

import { Feed } from 'rss.today'; const feed = new Feed({ id: 'https://blog.example.com/feed', title: 'Tech Blog', description: 'Technology and programming articles', link: 'https://blog.example.com', copyright: '2024 Tech Blog', language: 'en', updated: new Date(), author: { name: 'Blog Author', email: 'author@blog.example.com', link: 'https://blog.example.com/author' } }); // Add categories feed.addCategory('Technology'); feed.addCategory('Programming'); feed.addCategory('Web Development'); // Add contributors feed.addContributor({ name: 'Jane Doe', email: 'jane@example.com' }); feed.addContributor({ name: 'John Smith', email: 'john@example.com' }); // Add posts feed.addItem({ title: 'Introduction to TypeScript', link: 'https://blog.example.com/typescript-intro', description: 'Learn TypeScript basics', content: '<p>TypeScript is a typed superset of JavaScript...</p>', date: new Date('2024-01-15'), author: [{ name: 'Jane Doe', email: 'jane@example.com' }], category: [ { name: 'TypeScript' }, { name: 'JavaScript' } ] }); feed.addItem({ title: 'React Hooks Guide', link: 'https://blog.example.com/react-hooks', description: 'Master React Hooks', content: '<p>React Hooks are functions that let you...</p>', date: new Date('2024-01-20'), author: [{ name: 'John Smith', email: 'john@example.com' }], category: [ { name: 'React' }, { name: 'Frontend' } ] }); const rss = feed.rss2(); console.log(rss);

Podcast Feed

Complete Podcast Feed

import { Feed } from 'rss.today'; const feed = new Feed({ id: 'https://podcast.example.com/feed', title: 'Tech Talk Podcast', description: 'Weekly discussions about technology', link: 'https://podcast.example.com', feed: 'https://podcast.example.com/feed.xml', copyright: '2024 Tech Talk', language: 'en', updated: new Date(), podcast: true, category: 'Technology', author: { name: 'Tech Talk Host', email: 'host@podcast.example.com' }, image: 'https://podcast.example.com/podcast-cover.jpg' }); // Add iTunes metadata feed.addExtension({ name: 'itunes', objects: { author: 'Tech Talk Host', subtitle: 'Weekly tech discussions', summary: 'Join us every week for discussions about the latest in technology.', explicit: 'clean', keywords: ['technology', 'programming', 'software'], image: 'https://podcast.example.com/podcast-cover.jpg', owner: { name: 'Tech Talk Host', email: 'host@podcast.example.com' }, categories: [ 'Technology', 'Software How-To' ] } }); // Add episodes feed.addItem({ title: 'Episode 1: Introduction to React', link: 'https://podcast.example.com/episode-1', description: 'Learn the basics of React framework', date: new Date('2024-01-01'), enclosure: { url: 'https://podcast.example.com/episode-1.mp3', type: 'audio/mpeg', length: 15728640 // 15MB } }); feed.addItem({ title: 'Episode 2: TypeScript Deep Dive', link: 'https://podcast.example.com/episode-2', description: 'Advanced TypeScript techniques', date: new Date('2024-01-08'), enclosure: { url: 'https://podcast.example.com/episode-2.mp3', type: 'audio/mpeg', length: 17825792 // 17MB } }); feed.addItem({ title: 'Episode 3: Node.js Best Practices', link: 'https://podcast.example.com/episode-3', description: 'Best practices for Node.js development', date: new Date('2024-01-15'), enclosure: { url: 'https://podcast.example.com/episode-3.mp3', type: 'audio/mpeg', length: 19922944 // 19MB } }); const rss = feed.rss2(); console.log(rss);

Feed Aggregation

Merge Multiple Feeds

import { Parser, mergeFeeds, sortByDate, limitFeed } from 'rss.today'; async function aggregateFeeds(feedUrls: string[], limit: number = 20) { const parser = new Parser(); console.log('Fetching feeds...'); // Fetch all feeds const feeds = await Promise.all( feedUrls.map(async (url) => { try { return await parser.parseURL(url); } catch (error) { console.error(`Failed to fetch ${url}:`, error.message); return null; } }) ); // Filter out failed requests const validFeeds = feeds.filter((feed): feed is NonNullable<typeof feed> => feed !== null); console.log(`Successfully fetched ${validFeeds.length} feeds`); // Merge feeds const merged = mergeFeeds(validFeeds); console.log(`Merged ${merged.items.length} items`); // Sort by date (newest first) const sorted = sortByDate(merged, 'desc'); // Limit results const final = limitFeed(sorted, limit); console.log(`\n=== Aggregated Feed ===`); console.log(`Total items: ${final.items.length}\n`); final.items.forEach((item, index) => { console.log(`${index + 1}. ${item.title}`); console.log(` ${item.link}`); if (item.pubDate) { console.log(` ${item.pubDate}`); } console.log(); }); return final; } aggregateFeeds([ 'https://techcrunch.com/feed/', 'https://arstechnica.com/feed/', 'https://www.theverge.com/rss/index.xml' ], 10);

Feed Monitoring

Detect Feed Changes

import { Parser, diffFeeds } from 'rss.today'; import * as fs from 'fs/promises'; async function monitorFeed(url: string) { const parser = new Parser(); // Load previous state let oldFeed = null; try { const saved = await fs.readFile('./feed-state.json', 'utf-8'); oldFeed = JSON.parse(saved); } catch { console.log('No previous state found, starting fresh'); } // Fetch current feed console.log(`Fetching: ${url}`); const newFeed = await parser.parseURL(url); if (oldFeed) { console.log(`\nOld feed: ${oldFeed.items.length} items`); console.log(`New feed: ${newFeed.items.length} items\n`); // Compare feeds const diff = diffFeeds(oldFeed, newFeed); if (diff.added.length > 0) { console.log(`✨ New items (${diff.added.length}):`); diff.added.forEach(item => { console.log(` + ${item.title}`); }); console.log(); } if (diff.removed.length > 0) { console.log(`🗑️ Removed items (${diff.removed.length}):`); diff.removed.forEach(item => { console.log(` - ${item.title}`); }); console.log(); } if (diff.modified.length > 0) { console.log(`✏️ Modified items (${diff.modified.length}):`); diff.modified.forEach(item => { console.log(` ~ ${item.title}`); }); console.log(); } } else { console.log(`\nInitial feed: ${newFeed.items.length} items\n`); newFeed.items.slice(0, 5).forEach(item => { console.log(` ${item.title}`); }); } // Save current state await fs.writeFile('./feed-state.json', JSON.stringify(newFeed, null, 2)); console.log('State saved'); } monitorFeed('https://example.com/feed.xml');

Format Conversion

Convert Between Formats

import { Parser, convertToRSS2, convertToAtom, convertToJSON } from 'rss.today'; import * as fs from 'fs/promises'; async function convertFeedFormats(sourceUrl: string, outputDir: string) { const parser = new Parser(); console.log(`Fetching: ${sourceUrl}`); const feed = await parser.parseURL(sourceUrl); console.log(`Title: ${feed.title}`); console.log(`Items: ${feed.items.length}\n`); // Convert to all formats console.log('Converting to RSS 2.0...'); const rss2 = convertToRSS2(feed); await fs.writeFile(`${outputDir}/feed.rss.xml`, rss2); console.log('Converting to Atom 1.0...'); const atom = convertToAtom(feed); await fs.writeFile(`${outputDir}/feed.atom.xml`, atom); console.log('Converting to JSON Feed...'); const json = convertToJSON(feed); await fs.writeFile(`${outputDir}/feed.json`, json); console.log('\nAll formats converted successfully!'); console.log(` - RSS 2.0: ${outputDir}/feed.rss.xml`); console.log(` - Atom 1.0: ${outputDir}/feed.atom.xml`); console.log(` - JSON Feed: ${outputDir}/feed.json`); } convertFeedFormats('https://example.com/feed.xml', './output');

OPML Operations

Parse OPML and Import Feeds

import { OPMLParser, Parser } from 'rss.today'; import * as fs from 'fs/promises'; async function importFromOPML(opmlPath: string) { // Parse OPML file const xml = await fs.readFile(opmlPath, 'utf-8'); const opmlParser = new OPMLParser(); const opml = await opmlParser.parseOPML(xml); console.log(`=== ${opml.title} ===`); console.log(`Total feeds: ${countFeeds(opml.outlines)}\n`); // Parse each feed const feedParser = new Parser(); let successCount = 0; let failCount = 0; for (const outline of opml.outlines) { if (outline.type === 'rss' && outline.xmlUrl) { try { const feed = await feedParser.parseURL(outline.xmlUrl); console.log(`✓ ${outline.text}`); console.log(` ${feed.title}`); console.log(` Items: ${feed.items.length}\n`); successCount++; } catch (error: any) { console.log(`✗ ${outline.text}`); console.log(` Error: ${error.message}\n`); failCount++; } } else if (outline.outlines) { for (const feed of outline.outlines) { if (feed.type === 'rss' && feed.xmlUrl) { try { const parsed = await feedParser.parseURL(feed.xmlUrl); console.log(`✓ ${feed.text}`); console.log(` ${parsed.title}\n`); successCount++; } catch (error: any) { console.log(`✗ ${feed.text}`); console.log(` Error: ${error.message}\n`); failCount++; } } } } } console.log(`\nSummary: ${successCount} succeeded, ${failCount} failed`); } function countFeeds(outlines: any[]): number { let count = 0; for (const outline of outlines) { if (outline.type === 'rss') { count++; } else if (outline.outlines) { count += countFeeds(outline.outlines); } } return count; } importFromOPML('./subscriptions.opml');

Export Feeds to OPML

import { Parser, OPMLGenerator, type OPMLDocument } from 'rss.today'; import * as fs from 'fs/promises'; async function exportToOPML(feedUrls: string[], outputPath: string) { const parser = new Parser(); const outlines = []; console.log('Fetching feeds...\n'); for (const url of feedUrls) { try { const feed = await parser.parseURL(url); outlines.push({ text: feed.title || url, type: 'rss', xmlUrl: url, htmlUrl: feed.link, description: feed.description }); console.log(`✓ ${feed.title}`); } catch (error: any) { console.log(`✗ ${url}`); console.log(` Error: ${error.message}`); } } const opml: OPMLDocument = { title: 'Exported Subscriptions', dateCreated: new Date(), dateModified: new Date(), ownerName: 'Your Name', ownerEmail: 'your@example.com', outlines }; const generator = new OPMLGenerator(); const opmlXml = generator.generateOPML(opml); await fs.writeFile(outputPath, opmlXml); console.log(`\nExported ${outlines.length} feeds to ${outputPath}`); } exportToOPML( [ 'https://techcrunch.com/feed/', 'https://arstechnica.com/feed/', 'https://www.theverge.com/rss/index.xml' ], './exports/subscriptions.opml' );

Feed Filtering

Filter by Category

import { Parser, filterByCategory } from 'rss.today'; async function getTechPosts(url: string) { const parser = new Parser(); const feed = await parser.parseURL(url); const techFeed = filterByCategory(feed, 'technology'); console.log(`Found ${techFeed.items.length} technology posts`); techFeed.items.forEach(item => { console.log(`- ${item.title}`); }); } getTechPosts('https://example.com/feed.xml');

Filter by Date Range

import { Parser, filterByDateRange, sortByDate, limitFeed } from 'rss.today'; async function getRecentPosts(url: string, days: number = 7) { const parser = new Parser(); const feed = await parser.parseURL(url); // Filter by date range const startDate = new Date(); startDate.setDate(startDate.getDate() - days); const recentFeed = filterByDateRange(feed, startDate); // Sort by date const sorted = sortByDate(recentFeed, 'desc'); // Limit results const results = limitFeed(sorted, 10); console.log(`Posts from last ${days} days:`); results.items.forEach(item => { console.log(`- ${item.title}`); console.log(` ${item.pubDate}`); }); } getRecentPosts('https://example.com/feed.xml', 7);

Validation

Validate RSS 2.0 Feed

import { Parser, validateRSS2 } from 'rss.today'; async function validateRSSFeed(url: string) { const parser = new Parser(); console.log(`Validating: ${url}\n`); const feed = await parser.parseURL(url); const result = validateRSS2(feed); if (result.valid) { console.log('✅ Feed is valid RSS 2.0'); } else { console.log('❌ Feed has errors:'); result.errors.forEach(error => console.log(` - ${error}`)); } if (result.warnings.length > 0) { console.log('\n⚠️ Warnings:'); result.warnings.forEach(warning => console.log(` - ${warning}`)); } return result.valid; } validateRSSFeed('https://example.com/feed.xml');

Validate Before Processing

import { Parser, validateRSS2, validateAtom } from 'rss.today'; async function safeParse(url: string) { const parser = new Parser(); const feed = await parser.parseURL(url); // Try RSS 2.0 validation const rss2Result = validateRSS2(feed); if (rss2Result.valid) { console.log('Valid RSS 2.0 feed'); return feed; } // Try Atom validation const atomResult = validateAtom(feed); if (atomResult.valid) { console.log('Valid Atom feed'); return feed; } console.log('Feed validation failed'); console.log('RSS 2.0 errors:', rss2Result.errors); console.log('Atom errors:', atomResult.errors); } safeParse('https://example.com/feed.xml');

Error Handling

Comprehensive Error Handling

import { Parser } from 'rss.today'; async function robustParse(url: string) { const parser = new Parser({ timeout: 30000, maxRedirects: 5 }); try { const feed = await parser.parseURL(url); if (!feed || !feed.items) { console.log('Empty or invalid feed'); return null; } console.log(`Success: ${feed.title}`); console.log(`Items: ${feed.items.length}`); return feed; } catch (error: any) { if (error.message.includes('Feed not recognized')) { console.error('❌ Unsupported feed format'); } else if (error.message.includes('Status code')) { console.error(`❌ HTTP error: ${error.message}`); } else if (error.message.includes('File not found')) { console.error('❌ File does not exist'); } else if (error.message.includes('Unable to parse XML')) { console.error('❌ Malformed XML'); } else if (error.message.includes('timeout')) { console.error('❌ Request timeout'); } else { console.error('❌ Unknown error:', error.message); } return null; } } robustParse('https://example.com/feed.xml');

Retry Logic

import { Parser } from 'rss.today'; async function parseWithRetry(url: string, maxRetries: number = 3) { const parser = new Parser(); let lastError: Error | null = null; for (let attempt = 1; attempt <= maxRetries; attempt++) { try { console.log(`Attempt ${attempt}/${maxRetries}...`); const feed = await parser.parseURL(url); console.log('Success!'); return feed; } catch (error: any) { lastError = error; console.log(`Failed: ${error.message}`); if (attempt < maxRetries) { const delay = Math.pow(2, attempt) * 1000; // Exponential backoff console.log(`Waiting ${delay}ms before retry...`); await new Promise(resolve => setTimeout(resolve, delay)); } } } console.error(`Failed after ${maxRetries} attempts`); throw lastError; } parseWithRetry('https://example.com/feed.xml');
Last updated on