Customize URL Resolution
Feedscout resolves discovered URLs before validation to ensure consistent results. You can provide a custom resolution function to change this behavior.
Default Behavior
By default, Feedscout resolves relative URLs against the base URL:
// Base URL: https://example.com/blog/
// Discovered: /feed.xml
// Resolved: https://example.com/feed.xml
// Base URL: https://example.com/blog/
// Discovered: ../rss
// Resolved: https://example.com/rssIt also repairs URLs a page often gets wrong:
// HTML entities are decoded
// Discovered: /feed?format=rss&lang=en
// Resolved: https://example.com/feed?format=rss&lang=en
// Feed and podcast schemes become https
// Discovered: feed://example.com/rss.xml
// Resolved: https://example.com/rss.xml
// Malformed http protocols are fixed
// Discovered: htp://example.com/feed.xml
// Resolved: http://example.com/feed.xmlAn entity is decoded only with its trailing semicolon, so a query such as ?id=1©=2 stays as it is. A URL the default cannot parse is kept as discovered and reported to onError.
Custom Resolution
Provide a resolveUrlFn to customize URL resolution:
import type { DiscoverResolveUrlFn } from 'feedscout'
const customResolve: DiscoverResolveUrlFn = (url, baseUrl) => {
// Resolve relative URLs
const resolved = new URL(url, baseUrl).href
// Remove tracking parameters
const parsed = new URL(resolved)
parsed.searchParams.delete('utm_source')
parsed.searchParams.delete('utm_medium')
parsed.searchParams.delete('utm_campaign')
return parsed.href
}
const feeds = await discoverFeeds(url, {
methods: ['html', 'guess'],
resolveUrlFn: customResolve,
})
// Also works with discoverHubs
const hubs = await discoverHubs(url, {
resolveUrlFn: customResolve,
})Interface
type DiscoverResolveUrlFn = (url: string, baseUrl: string | undefined) => string | undefinedReturn undefined when the URL cannot be resolved. Feedscout then keeps the URL as discovered. The same happens when the function throws, and the error is reported to onError, so a malformed href on a page does not stop discovery.
A resolved URL with a scheme other than http or https, such as a javascript: or mailto: link, is dropped, since it cannot be fetched. The Guess method finds nothing on a page without an http origin, such as a saved file: page, since the URLs it builds start from that origin.
Use Cases
Removing Query Parameters
Strip unnecessary query parameters:
const resolveUrl: DiscoverResolveUrlFn = (url, baseUrl) => {
const resolved = new URL(url, baseUrl)
// Keep only essential parameters
const essentialParams = ['format', 'type']
const params = new URLSearchParams()
for (const key of essentialParams) {
const value = resolved.searchParams.get(key)
if (value) params.set(key, value)
}
resolved.search = params.toString()
return resolved.href
}Forcing HTTPS
Upgrade HTTP URLs to HTTPS:
const resolveUrl: DiscoverResolveUrlFn = (url, baseUrl) => {
const resolved = new URL(url, baseUrl)
resolved.protocol = 'https:'
return resolved.href
}Removing Trailing Slashes
Remove trailing slashes from paths:
const resolveUrl: DiscoverResolveUrlFn = (url, baseUrl) => {
const resolved = new URL(url, baseUrl)
resolved.pathname = resolved.pathname.replace(/\/+$/, '')
return resolved.href
}Custom Domain Handling
Rewrite URLs for specific domains:
const resolveUrl: DiscoverResolveUrlFn = (url, baseUrl) => {
const resolved = new URL(url, baseUrl)
// Use feeds subdomain for specific sites
if (resolved.hostname === 'example.com') {
resolved.hostname = 'feeds.example.com'
}
return resolved.href
}Combining with Other Options
URL resolution works with discoverFeeds, discoverBlogrolls, discoverFavicons, and discoverHubs:
const feeds = await discoverFeeds(url, {
methods: ['html', 'guess'],
resolveUrlFn: customResolve,
extractFn: customExtractor,
concurrency: 3,
})
const hubs = await discoverHubs(url, {
methods: ['headers', 'html'],
resolveUrlFn: customResolve,
})