0
# normalize-url
1
2
normalize-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.
3
4
## Package Information
5
6
- **Package Name**: normalize-url
7
- **Package Type**: npm
8
- **Language**: JavaScript (ES Module)
9
- **Installation**: `npm install normalize-url`
10
11
## Core Imports
12
13
```javascript
14
import normalizeUrl from 'normalize-url';
15
```
16
17
For Node.js environments requiring CommonJS compatibility, you'll need to use dynamic imports:
18
19
```javascript
20
const { default: normalizeUrl } = await import('normalize-url');
21
```
22
23
For TypeScript projects:
24
25
```typescript
26
import normalizeUrl, { Options } from 'normalize-url';
27
```
28
29
## Basic Usage
30
31
```javascript
32
import normalizeUrl from 'normalize-url';
33
34
// Basic normalization
35
const url1 = normalizeUrl('sindresorhus.com');
36
// => 'http://sindresorhus.com'
37
38
// Advanced normalization with options
39
const url2 = normalizeUrl('//www.sindresorhus.com:80/../baz?b=bar&a=foo', {
40
stripWWW: true,
41
removeTrailingSlash: true,
42
sortQueryParameters: true
43
});
44
// => 'http://sindresorhus.com/baz?a=foo&b=bar'
45
46
// Custom configuration
47
const url3 = normalizeUrl('https://user:pass@example.com/path/?utm_campaign=test&ref=source', {
48
stripAuthentication: true,
49
removeQueryParameters: [/^utm_\w+/i, 'ref'],
50
forceHttps: true
51
});
52
// => 'https://example.com/path'
53
```
54
55
## Capabilities
56
57
### URL Normalization
58
59
The main function that normalizes URLs according to specified configuration options.
60
61
```typescript { .api }
62
/**
63
* Normalize a URL with comprehensive configuration options
64
* @param url - URL to normalize, including data URLs
65
* @param options - Configuration options for normalization behavior
66
* @returns Normalized URL string
67
*/
68
function normalizeUrl(url: string, options?: Options): string;
69
```
70
71
**Usage Examples:**
72
73
```javascript
74
// Protocol normalization
75
normalizeUrl('sindresorhus.com'); // => 'http://sindresorhus.com'
76
normalizeUrl('//sindresorhus.com'); // => 'http://sindresorhus.com'
77
normalizeUrl('HTTP://EXAMPLE.COM'); // => 'http://example.com'
78
79
// WWW and hostname cleanup
80
normalizeUrl('http://www.example.com'); // => 'http://example.com'
81
normalizeUrl('example.com.'); // => 'http://example.com'
82
83
// Path normalization
84
normalizeUrl('example.com/foo//bar'); // => 'http://example.com/foo/bar'
85
normalizeUrl('example.com/foo/bar/'); // => 'http://example.com/foo/bar'
86
87
// Query parameter handling
88
normalizeUrl('example.com?b=2&a=1'); // => 'http://example.com/?a=1&b=2'
89
normalizeUrl('example.com?utm_campaign=test&foo=bar'); // => 'http://example.com/?foo=bar'
90
```
91
92
### Protocol Options
93
94
Configure how protocols are handled during normalization.
95
96
```typescript { .api }
97
interface ProtocolOptions {
98
/** Default protocol to prepend if missing */
99
defaultProtocol?: 'https' | 'http'; // default: 'http'
100
/** Whether to prepend defaultProtocol to protocol-relative URLs */
101
normalizeProtocol?: boolean; // default: true
102
/** Convert HTTPS URLs to HTTP */
103
forceHttp?: boolean; // default: false
104
/** Convert HTTP URLs to HTTPS (cannot be used with forceHttp) */
105
forceHttps?: boolean; // default: false
106
}
107
```
108
109
**Usage Examples:**
110
111
```javascript
112
// Default protocol
113
normalizeUrl('example.com', { defaultProtocol: 'https' });
114
// => 'https://example.com'
115
116
// Protocol-relative handling
117
normalizeUrl('//example.com', { normalizeProtocol: false });
118
// => '//example.com'
119
120
// Force protocol conversion
121
normalizeUrl('https://example.com', { forceHttp: true });
122
// => 'http://example.com'
123
124
normalizeUrl('http://example.com', { forceHttps: true });
125
// => 'https://example.com'
126
```
127
128
### Authentication and Security Options
129
130
Control how authentication information and protocols are handled.
131
132
```typescript { .api }
133
interface SecurityOptions {
134
/** Remove authentication part of URL */
135
stripAuthentication?: boolean; // default: true
136
/** Remove protocol from URL completely */
137
stripProtocol?: boolean; // default: false
138
}
139
```
140
141
**Usage Examples:**
142
143
```javascript
144
// Authentication stripping (default behavior)
145
normalizeUrl('https://user:password@example.com');
146
// => 'https://example.com'
147
148
// Keep authentication
149
normalizeUrl('https://user:password@example.com', { stripAuthentication: false });
150
// => 'https://user:password@example.com'
151
152
// Remove protocol entirely
153
normalizeUrl('https://example.com', { stripProtocol: true });
154
// => 'example.com'
155
```
156
157
### Hash and Fragment Options
158
159
Configure handling of URL hashes and text fragments.
160
161
```typescript { .api }
162
interface HashOptions {
163
/** Remove hash from URL */
164
stripHash?: boolean; // default: false
165
/** Remove text fragment part of URL hash */
166
stripTextFragment?: boolean; // default: true
167
}
168
```
169
170
**Usage Examples:**
171
172
```javascript
173
// Text fragment removal (default behavior)
174
normalizeUrl('http://example.com/page#:~:text=hello');
175
// => 'http://example.com/page#'
176
177
normalizeUrl('http://example.com/page#section:~:text=hello');
178
// => 'http://example.com/page#section'
179
180
// Keep text fragments
181
normalizeUrl('http://example.com/page#:~:text=hello', { stripTextFragment: false });
182
// => 'http://example.com/page#:~:text=hello'
183
184
// Remove entire hash
185
normalizeUrl('http://example.com/page#section', { stripHash: true });
186
// => 'http://example.com/page'
187
```
188
189
### Hostname and WWW Options
190
191
Control WWW prefix handling and hostname normalization.
192
193
```typescript { .api }
194
interface HostnameOptions {
195
/** Remove www. from hostname */
196
stripWWW?: boolean; // default: true
197
}
198
```
199
200
**Usage Examples:**
201
202
```javascript
203
// WWW removal (default behavior)
204
normalizeUrl('http://www.example.com'); // => 'http://example.com'
205
206
// Keep WWW
207
normalizeUrl('http://www.example.com', { stripWWW: false });
208
// => 'http://www.example.com'
209
```
210
211
### Query Parameter Options
212
213
Comprehensive query parameter filtering, sorting, and management capabilities.
214
215
```typescript { .api }
216
interface QueryOptions {
217
/** Remove query parameters matching strings/regexes or all if true */
218
removeQueryParameters?: ReadonlyArray<RegExp | string> | boolean; // default: [/^utm_\w+/i]
219
/** Keep only query parameters matching strings/regexes (overrides removeQueryParameters) */
220
keepQueryParameters?: ReadonlyArray<RegExp | string>; // default: undefined
221
/** Sort query parameters alphabetically by key */
222
sortQueryParameters?: boolean; // default: true
223
}
224
```
225
226
**Usage Examples:**
227
228
```javascript
229
// Default UTM parameter removal
230
normalizeUrl('example.com?foo=bar&utm_campaign=test');
231
// => 'http://example.com/?foo=bar'
232
233
// Custom parameter removal
234
normalizeUrl('example.com?foo=bar&ref=source&debug=1', {
235
removeQueryParameters: ['ref', /^debug/i]
236
});
237
// => 'http://example.com/?foo=bar'
238
239
// Remove all parameters
240
normalizeUrl('example.com?foo=bar&baz=qux', { removeQueryParameters: true });
241
// => 'http://example.com'
242
243
// Keep only specific parameters
244
normalizeUrl('example.com?foo=bar&utm_source=google&ref=twitter', {
245
keepQueryParameters: ['foo', /^utm_/]
246
});
247
// => 'http://example.com/?foo=bar&utm_source=google'
248
249
// Disable sorting
250
normalizeUrl('example.com?c=3&a=1&b=2', { sortQueryParameters: false });
251
// => 'http://example.com/?c=3&a=1&b=2'
252
```
253
254
### Path Options
255
256
Control trailing slashes, directory indexes, and path normalization.
257
258
```typescript { .api }
259
interface PathOptions {
260
/** Remove trailing slash from path */
261
removeTrailingSlash?: boolean; // default: true
262
/** Remove sole / pathname */
263
removeSingleSlash?: boolean; // default: true
264
/** Remove directory index files matching patterns */
265
removeDirectoryIndex?: boolean | ReadonlyArray<RegExp | string>; // default: false
266
}
267
```
268
269
**Usage Examples:**
270
271
```javascript
272
// Trailing slash removal (default behavior)
273
normalizeUrl('http://example.com/path/'); // => 'http://example.com/path'
274
275
// Keep trailing slashes
276
normalizeUrl('http://example.com/path/', { removeTrailingSlash: false });
277
// => 'http://example.com/path/'
278
279
// Directory index removal
280
normalizeUrl('http://example.com/index.html', { removeDirectoryIndex: true });
281
// => 'http://example.com'
282
283
normalizeUrl('http://example.com/path/index.php', { removeDirectoryIndex: ['index.php'] });
284
// => 'http://example.com/path'
285
286
// Custom directory index patterns
287
normalizeUrl('http://example.com/default.htm', {
288
removeDirectoryIndex: [/^default\.[a-z]+$/]
289
});
290
// => 'http://example.com'
291
```
292
293
### Port Options
294
295
Configure explicit port number handling.
296
297
```typescript { .api }
298
interface PortOptions {
299
/** Remove explicit port numbers */
300
removeExplicitPort?: boolean; // default: false
301
}
302
```
303
304
**Usage Examples:**
305
306
```javascript
307
// Keep explicit ports (default behavior)
308
normalizeUrl('http://example.com:8080'); // => 'http://example.com:8080'
309
310
// Remove explicit ports
311
normalizeUrl('http://example.com:8080', { removeExplicitPort: true });
312
// => 'http://example.com'
313
314
// Standard ports are always removed
315
normalizeUrl('http://example.com:80'); // => 'http://example.com'
316
normalizeUrl('https://example.com:443'); // => 'https://example.com'
317
```
318
319
### Data URL Support
320
321
Comprehensive support for data URL normalization with MIME type and encoding handling.
322
323
```javascript
324
// Data URL normalization
325
normalizeUrl('data:text/plain,hello'); // => 'data:,hello'
326
normalizeUrl('data:;charset=us-ascii,hello'); // => 'data:,hello'
327
normalizeUrl('data:TEXT/HTML,<h1>Hello</h1>'); // => 'data:text/html,<h1>Hello</h1>'
328
normalizeUrl('data:;base64, SGVsbG8='); // => 'data:;base64,SGVsbG8='
329
330
// Data URLs ignore most normalization options
331
normalizeUrl('data:,example.com/path/', {
332
removeTrailingSlash: true,
333
stripWWW: true
334
}); // => 'data:,example.com/path/' (unchanged)
335
```
336
337
### Custom Protocol Support
338
339
URLs with custom protocols are passed through unchanged to preserve their integrity.
340
341
```javascript
342
// Custom protocols are preserved
343
normalizeUrl('tel:+1234567890'); // => 'tel:+1234567890'
344
normalizeUrl('mailto:user@example.com'); // => 'mailto:user@example.com'
345
normalizeUrl('ftp://files.example.com/path/'); // => 'ftp://files.example.com/path/'
346
normalizeUrl('custom://app.local/resource'); // => 'custom://app.local/resource'
347
```
348
349
## Types
350
351
```typescript { .api }
352
interface Options {
353
/** Default protocol to prepend if missing */
354
readonly defaultProtocol?: 'https' | 'http';
355
/** Whether to prepend defaultProtocol to protocol-relative URLs */
356
readonly normalizeProtocol?: boolean;
357
/** Convert HTTPS URLs to HTTP */
358
readonly forceHttp?: boolean;
359
/** Convert HTTP URLs to HTTPS (cannot be used with forceHttp) */
360
readonly forceHttps?: boolean;
361
/** Remove authentication part of URL */
362
readonly stripAuthentication?: boolean;
363
/** Remove hash from URL */
364
readonly stripHash?: boolean;
365
/** Remove protocol from URL completely */
366
readonly stripProtocol?: boolean;
367
/** Remove text fragment part of URL hash */
368
readonly stripTextFragment?: boolean;
369
/** Remove www. from hostname */
370
readonly stripWWW?: boolean;
371
/** Remove query parameters matching strings/regexes or all if true */
372
readonly removeQueryParameters?: ReadonlyArray<RegExp | string> | boolean;
373
/** Keep only query parameters matching strings/regexes */
374
readonly keepQueryParameters?: ReadonlyArray<RegExp | string>;
375
/** Remove trailing slash from path */
376
readonly removeTrailingSlash?: boolean;
377
/** Remove sole / pathname */
378
readonly removeSingleSlash?: boolean;
379
/** Remove directory index files matching patterns */
380
readonly removeDirectoryIndex?: boolean | ReadonlyArray<RegExp | string>;
381
/** Remove explicit port numbers */
382
readonly removeExplicitPort?: boolean;
383
/** Sort query parameters alphabetically by key */
384
readonly sortQueryParameters?: boolean;
385
}
386
```
387
388
## Error Handling
389
390
The function throws errors in the following cases:
391
392
- **Invalid URLs**: Malformed URLs that cannot be parsed
393
- **Conflicting options**: Using `forceHttp` and `forceHttps` together
394
- **Invalid data URLs**: Malformed data URL format
395
396
```javascript
397
// Error examples
398
try {
399
normalizeUrl('http://'); // Throws: Invalid URL
400
} catch (error) {
401
console.error(error.message); // "Invalid URL: http://"
402
}
403
404
try {
405
normalizeUrl('https://example.com', { forceHttp: true, forceHttps: true });
406
} catch (error) {
407
console.error(error.message); // "The `forceHttp` and `forceHttps` options cannot be used together"
408
}
409
```