Customize URL Tiers
Feedcanon applies URL normalization tiers to generate candidates, ordered from cleanest to least clean. The first candidate serving the same content wins.
Default tiers:
- Tier 1: Strip query, www, and trailing slash
- Tier 2: Strip www and trailing slash, keep query
- Tier 3: Keep www, strip trailing slash, keep query
- Tier 4: Keep www and trailing slash, keep query
INFO
In addition to the structural tiers, you can plug extra cleaning into the cleanUrlFn option in FindCanonicalOptions: strip tracking params, unwrap redirect wrappers, or apply any custom rewrite. It runs on every response URL before candidates are generated, so the cleanup stays consistent across all tiers. The urlpurify package provides ready-made functions for this.
Normalization Options
Each tier accepts all NormalizeOptions except stripQueryParams. Tier options are not merged with any defaults: an option left out of a tier is off. The middle column shows the value the default Tier 2 uses, as a reference point:
| Option | Default Tier 2 | Description |
|---|---|---|
stripProtocol | false | Remove protocol (not recommended for feed URLs) |
stripAuthentication | false | Remove user:pass@ |
stripWww | true | Remove www. prefix |
stripTrailingSlash | true | Remove trailing / from paths |
stripRootSlash | true | Remove / from root paths |
collapseSlashes | true | /// → / |
stripHash | true | Remove #fragment |
sortQueryParams | true | Sort params alphabetically |
stripQuery | false | Remove entire query string |
stripEmptyQuery | true | Remove empty ? |
lowercaseQuery | false | Lowercase query param names and values |
normalizeEncoding | true | Normalize %XX encoding |
normalizeUnicode | true | NFC normalization |
Examples
Minimal Tiers
Use a single tier with minimal normalization:
import { findCanonical } from 'feedcanon'
const url = await findCanonical('https://example.com/feed', {
tiers: [{}], // No URL transformations beyond sorting the query
})Aggressive Tiers
Strip the query, www, trailing slash and hash with a single tier:
import { findCanonical } from 'feedcanon'
const url = await findCanonical('https://example.com/feed', {
tiers: [
{
stripWww: true,
stripTrailingSlash: true,
stripRootSlash: true,
collapseSlashes: true,
stripHash: true,
stripQuery: true,
normalizeEncoding: true,
normalizeUnicode: true,
},
],
})Strip Tracking Params
Clean tracking params before candidate generation (at the top level, not per-tier):
import { findCanonical } from 'feedcanon'
import { stripTrackingParams } from 'urlpurify'
const url = await findCanonical('https://example.com/feed', {
cleanUrlFn: stripTrackingParams,
tiers: [
{ stripWww: true, stripTrailingSlash: true },
{ stripTrailingSlash: true },
],
})A cleanUrlFn that only edits the query is trusted: Feedcanon uses its result without fetching it, so it should remove only params that do not change which feed the URL serves. A result with a different host or path, such as an unwrapped redirect link, is a URL nobody fetched yet. Feedcanon uses it only when existsFn already knows it or when it serves the same feed, which costs one extra request. Otherwise it keeps the URL the response came from.
Preserve Query Params
Keep all query parameters (no stripping):
const url = await findCanonical('https://example.com/feed', {
tiers: [
{ stripWww: true, stripTrailingSlash: true },
],
})