Normalize a URL with comprehensive configuration options for protocol, authentication, query parameters, and path handling
npx @tessl/cli install tessl/npm-normalize-url@8.0.0normalize-url is a comprehensive URL normalization library that standardizes URLs for display, storage, deduplication, sorting, and comparison purposes. It provides extensive configuration options for protocol handling, query parameter management, path cleanup, authentication stripping, and special URL format support including data URLs.
npm install normalize-urlimport normalizeUrl from 'normalize-url';For Node.js environments requiring CommonJS compatibility, you'll need to use dynamic imports:
const { default: normalizeUrl } = await import('normalize-url');For TypeScript projects:
import normalizeUrl, { Options } from 'normalize-url';import normalizeUrl from 'normalize-url';
// Basic normalization
const url1 = normalizeUrl('sindresorhus.com');
// => 'http://sindresorhus.com'
// Advanced normalization with options
const url2 = normalizeUrl('//www.sindresorhus.com:80/../baz?b=bar&a=foo', {
stripWWW: true,
removeTrailingSlash: true,
sortQueryParameters: true
});
// => 'http://sindresorhus.com/baz?a=foo&b=bar'
// Custom configuration
const url3 = normalizeUrl('https://user:pass@example.com/path/?utm_campaign=test&ref=source', {
stripAuthentication: true,
removeQueryParameters: [/^utm_\w+/i, 'ref'],
forceHttps: true
});
// => 'https://example.com/path'The main function that normalizes URLs according to specified configuration options.
/**
* Normalize a URL with comprehensive configuration options
* @param url - URL to normalize, including data URLs
* @param options - Configuration options for normalization behavior
* @returns Normalized URL string
*/
function normalizeUrl(url: string, options?: Options): string;Usage Examples:
// Protocol normalization
normalizeUrl('sindresorhus.com'); // => 'http://sindresorhus.com'
normalizeUrl('//sindresorhus.com'); // => 'http://sindresorhus.com'
normalizeUrl('HTTP://EXAMPLE.COM'); // => 'http://example.com'
// WWW and hostname cleanup
normalizeUrl('http://www.example.com'); // => 'http://example.com'
normalizeUrl('example.com.'); // => 'http://example.com'
// Path normalization
normalizeUrl('example.com/foo//bar'); // => 'http://example.com/foo/bar'
normalizeUrl('example.com/foo/bar/'); // => 'http://example.com/foo/bar'
// Query parameter handling
normalizeUrl('example.com?b=2&a=1'); // => 'http://example.com/?a=1&b=2'
normalizeUrl('example.com?utm_campaign=test&foo=bar'); // => 'http://example.com/?foo=bar'Configure how protocols are handled during normalization.
interface ProtocolOptions {
/** Default protocol to prepend if missing */
defaultProtocol?: 'https' | 'http'; // default: 'http'
/** Whether to prepend defaultProtocol to protocol-relative URLs */
normalizeProtocol?: boolean; // default: true
/** Convert HTTPS URLs to HTTP */
forceHttp?: boolean; // default: false
/** Convert HTTP URLs to HTTPS (cannot be used with forceHttp) */
forceHttps?: boolean; // default: false
}Usage Examples:
// Default protocol
normalizeUrl('example.com', { defaultProtocol: 'https' });
// => 'https://example.com'
// Protocol-relative handling
normalizeUrl('//example.com', { normalizeProtocol: false });
// => '//example.com'
// Force protocol conversion
normalizeUrl('https://example.com', { forceHttp: true });
// => 'http://example.com'
normalizeUrl('http://example.com', { forceHttps: true });
// => 'https://example.com'Control how authentication information and protocols are handled.
interface SecurityOptions {
/** Remove authentication part of URL */
stripAuthentication?: boolean; // default: true
/** Remove protocol from URL completely */
stripProtocol?: boolean; // default: false
}Usage Examples:
// Authentication stripping (default behavior)
normalizeUrl('https://user:password@example.com');
// => 'https://example.com'
// Keep authentication
normalizeUrl('https://user:password@example.com', { stripAuthentication: false });
// => 'https://user:password@example.com'
// Remove protocol entirely
normalizeUrl('https://example.com', { stripProtocol: true });
// => 'example.com'Configure handling of URL hashes and text fragments.
interface HashOptions {
/** Remove hash from URL */
stripHash?: boolean; // default: false
/** Remove text fragment part of URL hash */
stripTextFragment?: boolean; // default: true
}Usage Examples:
// Text fragment removal (default behavior)
normalizeUrl('http://example.com/page#:~:text=hello');
// => 'http://example.com/page#'
normalizeUrl('http://example.com/page#section:~:text=hello');
// => 'http://example.com/page#section'
// Keep text fragments
normalizeUrl('http://example.com/page#:~:text=hello', { stripTextFragment: false });
// => 'http://example.com/page#:~:text=hello'
// Remove entire hash
normalizeUrl('http://example.com/page#section', { stripHash: true });
// => 'http://example.com/page'Control WWW prefix handling and hostname normalization.
interface HostnameOptions {
/** Remove www. from hostname */
stripWWW?: boolean; // default: true
}Usage Examples:
// WWW removal (default behavior)
normalizeUrl('http://www.example.com'); // => 'http://example.com'
// Keep WWW
normalizeUrl('http://www.example.com', { stripWWW: false });
// => 'http://www.example.com'Comprehensive query parameter filtering, sorting, and management capabilities.
interface QueryOptions {
/** Remove query parameters matching strings/regexes or all if true */
removeQueryParameters?: ReadonlyArray<RegExp | string> | boolean; // default: [/^utm_\w+/i]
/** Keep only query parameters matching strings/regexes (overrides removeQueryParameters) */
keepQueryParameters?: ReadonlyArray<RegExp | string>; // default: undefined
/** Sort query parameters alphabetically by key */
sortQueryParameters?: boolean; // default: true
}Usage Examples:
// Default UTM parameter removal
normalizeUrl('example.com?foo=bar&utm_campaign=test');
// => 'http://example.com/?foo=bar'
// Custom parameter removal
normalizeUrl('example.com?foo=bar&ref=source&debug=1', {
removeQueryParameters: ['ref', /^debug/i]
});
// => 'http://example.com/?foo=bar'
// Remove all parameters
normalizeUrl('example.com?foo=bar&baz=qux', { removeQueryParameters: true });
// => 'http://example.com'
// Keep only specific parameters
normalizeUrl('example.com?foo=bar&utm_source=google&ref=twitter', {
keepQueryParameters: ['foo', /^utm_/]
});
// => 'http://example.com/?foo=bar&utm_source=google'
// Disable sorting
normalizeUrl('example.com?c=3&a=1&b=2', { sortQueryParameters: false });
// => 'http://example.com/?c=3&a=1&b=2'Control trailing slashes, directory indexes, and path normalization.
interface PathOptions {
/** Remove trailing slash from path */
removeTrailingSlash?: boolean; // default: true
/** Remove sole / pathname */
removeSingleSlash?: boolean; // default: true
/** Remove directory index files matching patterns */
removeDirectoryIndex?: boolean | ReadonlyArray<RegExp | string>; // default: false
}Usage Examples:
// Trailing slash removal (default behavior)
normalizeUrl('http://example.com/path/'); // => 'http://example.com/path'
// Keep trailing slashes
normalizeUrl('http://example.com/path/', { removeTrailingSlash: false });
// => 'http://example.com/path/'
// Directory index removal
normalizeUrl('http://example.com/index.html', { removeDirectoryIndex: true });
// => 'http://example.com'
normalizeUrl('http://example.com/path/index.php', { removeDirectoryIndex: ['index.php'] });
// => 'http://example.com/path'
// Custom directory index patterns
normalizeUrl('http://example.com/default.htm', {
removeDirectoryIndex: [/^default\.[a-z]+$/]
});
// => 'http://example.com'Configure explicit port number handling.
interface PortOptions {
/** Remove explicit port numbers */
removeExplicitPort?: boolean; // default: false
}Usage Examples:
// Keep explicit ports (default behavior)
normalizeUrl('http://example.com:8080'); // => 'http://example.com:8080'
// Remove explicit ports
normalizeUrl('http://example.com:8080', { removeExplicitPort: true });
// => 'http://example.com'
// Standard ports are always removed
normalizeUrl('http://example.com:80'); // => 'http://example.com'
normalizeUrl('https://example.com:443'); // => 'https://example.com'Comprehensive support for data URL normalization with MIME type and encoding handling.
// Data URL normalization
normalizeUrl('data:text/plain,hello'); // => 'data:,hello'
normalizeUrl('data:;charset=us-ascii,hello'); // => 'data:,hello'
normalizeUrl('data:TEXT/HTML,<h1>Hello</h1>'); // => 'data:text/html,<h1>Hello</h1>'
normalizeUrl('data:;base64, SGVsbG8='); // => 'data:;base64,SGVsbG8='
// Data URLs ignore most normalization options
normalizeUrl('data:,example.com/path/', {
removeTrailingSlash: true,
stripWWW: true
}); // => 'data:,example.com/path/' (unchanged)URLs with custom protocols are passed through unchanged to preserve their integrity.
// Custom protocols are preserved
normalizeUrl('tel:+1234567890'); // => 'tel:+1234567890'
normalizeUrl('mailto:user@example.com'); // => 'mailto:user@example.com'
normalizeUrl('ftp://files.example.com/path/'); // => 'ftp://files.example.com/path/'
normalizeUrl('custom://app.local/resource'); // => 'custom://app.local/resource'interface Options {
/** Default protocol to prepend if missing */
readonly defaultProtocol?: 'https' | 'http';
/** Whether to prepend defaultProtocol to protocol-relative URLs */
readonly normalizeProtocol?: boolean;
/** Convert HTTPS URLs to HTTP */
readonly forceHttp?: boolean;
/** Convert HTTP URLs to HTTPS (cannot be used with forceHttp) */
readonly forceHttps?: boolean;
/** Remove authentication part of URL */
readonly stripAuthentication?: boolean;
/** Remove hash from URL */
readonly stripHash?: boolean;
/** Remove protocol from URL completely */
readonly stripProtocol?: boolean;
/** Remove text fragment part of URL hash */
readonly stripTextFragment?: boolean;
/** Remove www. from hostname */
readonly stripWWW?: boolean;
/** Remove query parameters matching strings/regexes or all if true */
readonly removeQueryParameters?: ReadonlyArray<RegExp | string> | boolean;
/** Keep only query parameters matching strings/regexes */
readonly keepQueryParameters?: ReadonlyArray<RegExp | string>;
/** Remove trailing slash from path */
readonly removeTrailingSlash?: boolean;
/** Remove sole / pathname */
readonly removeSingleSlash?: boolean;
/** Remove directory index files matching patterns */
readonly removeDirectoryIndex?: boolean | ReadonlyArray<RegExp | string>;
/** Remove explicit port numbers */
readonly removeExplicitPort?: boolean;
/** Sort query parameters alphabetically by key */
readonly sortQueryParameters?: boolean;
}The function throws errors in the following cases:
forceHttp and forceHttps together// Error examples
try {
normalizeUrl('http://'); // Throws: Invalid URL
} catch (error) {
console.error(error.message); // "Invalid URL: http://"
}
try {
normalizeUrl('https://example.com', { forceHttp: true, forceHttps: true });
} catch (error) {
console.error(error.message); // "The `forceHttp` and `forceHttps` options cannot be used together"
}