Skip to content

discoverFeeds ​

Discovers and validates feeds from a webpage.

Signature ​

typescript
function discoverFeeds(
  input: DiscoverInput,
  options?: DiscoverOptions<FeedResult, 'platform' | 'html' | 'headers' | 'guess'>,
): Promise<Array<DiscoverResult<FeedResult>>>

Parameters ​

input ​

The URL to discover feeds from. Can be a string or an object:

typescript
// String - URL to fetch and scan
discoverFeeds('https://example.com', options)

// Object - provide existing content/headers
discoverFeeds({
  url: 'https://example.com',
  content: htmlContent,     // Optional HTML content
  headers: responseHeaders, // Optional HTTP headers
}, options)

options ​

All options are optional. When not provided, sensible defaults are used.

PropertyTypeDefaultDescription
methodsDiscoverMethodsConfig['platform', 'html', 'headers', 'guess']Which methods to use
fetchFnFetchFnnative fetchCustom fetch function
extractFnDiscoverExtractFnfeedsmithCustom feed extraction function
resolveUrlFnDiscoverResolveUrlFnresolve relativeCustom URL resolution function
stopOnFirstMethodbooleanfalseStop after the first method that finds a valid result
stopOnFirstResultbooleanfalseStop after first valid feed
concurrencynumber3Max parallel validations
maxUrisnumber50Max total candidate URIs to fetch across all methods
includeInvalidbooleanfalseInclude invalid results
onProgressDiscoverOnProgressFnProgress callback
onStepDiscoverOnStepFnCalled when each stage of discovery starts and ends
onErrorDiscoverOnErrorFnCalled when fetching the input fails. DiscoverOnErrorFn lists everything it reports

Return Value ​

Returns a promise that resolves to an array of results:

typescript
// Valid result
{
  url: 'https://example.com/feed.xml',
  isValid: true,
  format: 'rss',         // 'rss' | 'atom' | 'json' | 'rdf'
  title: 'Example Blog',
  description: 'A blog about examples',
  siteUrl: 'https://example.com/',
  method: 'guess',       // 'platform' | 'html' | 'headers' | 'guess'
}

// Invalid result (when includeInvalid: true)
{
  url: 'https://example.com/not-a-feed',
  isValid: false,
  error: Error, // Only set when the request or the extractor threw
  method: 'guess',
}

Each feed URL appears once. When several candidates lead to the same feed, for example /feed and /rss both redirecting to /feed/, only the first is kept, so the result comes from the earliest method that found it. The same applies to invalid results with includeInvalid.

The method field indicates which discovery method produced the result. Results from the Platform method also include a hint that identifies the type of feed.

Examples ​

Basic Usage ​

typescript
import { discoverFeeds } from 'feedscout'

// Simple usage - all methods enabled by default
const feeds = await discoverFeeds('https://example.com')

// Or specify which methods to use
const feeds = await discoverFeeds('https://example.com', {
  methods: ['html', 'headers', 'guess'],
})

With Custom Options ​

typescript
const feeds = await discoverFeeds('https://example.com', {
  methods: {
    html: {
      anchorLabels: ['rss', 'feed'],
    },
    guess: {
      uris: ['/feed', '/rss.xml'],
    },
  },
  concurrency: 3,
  stopOnFirstResult: true,
})

With Existing Content ​

typescript
const response = await fetch('https://example.com')

const feeds = await discoverFeeds(
  {
    url: 'https://example.com',
    content: await response.text(),
    headers: response.headers,
  },
  { methods: ['html', 'headers'] },
)

With Progress Tracking ​

typescript
const feeds = await discoverFeeds('https://example.com', {
  methods: ['html', 'guess'],
  onProgress: ({ tested, total, found, current }) => {
    console.log(`[${tested}/${total}] ${current} (${found} found)`)
  },
})

With Custom HTTP Client ​

typescript
import type { FetchFn } from 'feedscout'

const myCustomFetch: FetchFn = async (url, options) => {
  const response = await fetch(url, options)

  return {
    headers: response.headers,
    body: await response.text(),
    url: response.url,
    status: response.status,
  }
}

const feeds = await discoverFeeds('https://example.com', {
  methods: ['html', 'guess'],
  fetchFn: myCustomFetch,
})

See Customize Data Fetching for examples with Axios, Got, Ky, and more.