A Node.js CLI tool that measures the total weight of a webpage on initial load. It catalogues every asset the browser fetches — scripts, stylesheets, images, fonts, and more — and presents a formatted breakdown grouped by type and sorted by size.
- Features
- Prerequisites
- Installation
- Usage
- How It Works
- Output
- Page Weight Budgets
- Programmatic API
- Contributing
- License
- Calculates the total transfer size of all assets loaded during a page visit
- Groups assets by type (Script, Stylesheet, Image, Font, Media, Document, and more)
- Sorts each group by size in descending order
- Simulates real user behaviour by scrolling to the bottom of the page, capturing lazy-loaded resources
- Supports configurable viewport width so you can compare asset loads across breakpoints
- Configurable viewport height for non-square viewports
- Multiple output formats: table (default), JSON, CSV
- File output via
--output - Page weight budgets — total, per-type group, and per-asset limits for CI/CD pipelines
- Programmatic API for use as a library
- Node.js v18 or later
- npm (bundled with Node.js)
Puppeteer downloads a compatible version of Chromium automatically during installation, so no separate browser install is required.
Install the package globally to make the pageweight command available everywhere:
npm install -g pageweightClone the repository and install dependencies:
git clone https://github.com/briananders/pageweight.git
cd pageweight
npm installThen run the tool with:
node bin/pageweight.js <url> <viewport-width>Use npx to run the tool directly:
npx pageweight <url> <viewport-width>pageweight <url> <viewport-width> [options]
| Argument | Description |
|---|---|
url |
The full URL of the page to analyze (include https://) |
viewport-width |
The viewport width in pixels — the viewport height defaults to the same value, creating a square viewport |
| Option | Description |
|---|---|
-h, --help |
Show help message |
-v, --version |
Show version number |
-f, --format <type> |
Output format: table (default), json, csv |
-o, --output <file> |
Write output to a file instead of stdout |
-t, --timeout <ms> |
Navigation timeout in milliseconds (default: 60000) |
--height <px> |
Viewport height in pixels (defaults to viewport-width, making the viewport square) |
--no-scroll |
Skip scrolling to the bottom of the page |
All budget sizes accept a number optionally followed by B, KB, MB, or GB (e.g. 1MB, 500KB, 2.5MB). If no unit is specified, bytes are assumed. The tool exits with code 1 if any budget is exceeded.
| Option | Description |
|---|---|
-b, --budget <size> |
Total page weight budget |
--budget-image <size> |
Max total weight for all images combined |
--budget-media <size> |
Max total weight for all media (video/audio) combined |
--budget-script <size> |
Max total weight for all scripts combined |
--budget-stylesheet <size> |
Max total weight for all stylesheets combined |
--budget-font <size> |
Max total weight for all fonts combined |
--budget-document <size> |
Max total weight for all documents combined |
--budget-per-asset <size> |
Max weight for any single asset |
--budget-per-image <size> |
Max weight for any single image |
--budget-per-media <size> |
Max weight for any single media file |
Analyze a page at a desktop viewport width:
pageweight https://briananders.com 1440Analyze a page at a tablet viewport width:
pageweight https://briananders.com 768Analyze a page at a mobile viewport width:
pageweight https://briananders.com 375Export results as JSON:
pageweight https://example.com 1440 --format jsonSave CSV results to a file:
pageweight https://example.com 1440 --format csv --output results.csvSet a page weight budget (CI-friendly — exits with code 1 if exceeded):
pageweight https://example.com 1440 --budget 1MBEnforce image budgets (total and per-file):
pageweight https://example.com 1440 --budget-image 500KB --budget-per-image 200KBEnforce media/video budgets:
pageweight https://example.com 1440 --budget-media 5MB --budget-per-media 2MBCombine multiple budget constraints:
pageweight https://example.com 1440 \
--budget 2MB \
--budget-image 500KB \
--budget-media 5MB \
--budget-script 300KB \
--budget-per-asset 1MBCustom viewport height (non-square):
pageweight https://example.com 1440 --height 900Skip scrolling and use a shorter timeout:
pageweight https://example.com 1440 --no-scroll --timeout 30000- Launches a headless Chromium instance via Puppeteer
- Sets the viewport to the given width and height (defaults to a square)
- Navigates to the target URL and waits until network activity settles
- Scrolls from the top of the page to the bottom at a measured pace, triggering any lazy-loaded assets (unless
--no-scrollis used) - Waits briefly for remaining network requests to complete
- Collects the transfer size and MIME type of every request made by the browser
- Prints results in the chosen format (table, JSON, or CSV)
Different viewport widths can cause different assets to load (responsive images, conditional scripts, etc.), so running the tool at multiple widths gives a more complete picture of your page's weight profile.
The default output is a formatted table printed to stdout. Assets are grouped by type and each group is sorted largest-first. A grand total is displayed at the end.
----------------------------------------------------------------------------------------------------
Image (3 files) — Total: 1.20 MB
----------------------------------------------------------------------------------------------------
800.00 KB https://example.com/hero.webp
350.00 KB https://example.com/photo.jpg
50.00 KB https://example.com/icon.svg
----------------------------------------------------------------------------------------------------
Script (2 files) — Total: 320.00 KB
----------------------------------------------------------------------------------------------------
250.00 KB https://example.com/bundle.js
70.00 KB https://example.com/analytics.js
====================================================================================================
TOTAL PAGE WEIGHT: 1.52 MB (5 requests)
====================================================================================================
Structured JSON with full metadata including per-group totals and a summary:
{
"url": "https://example.com",
"viewport": { "width": 1440, "height": 1440 },
"timestamp": "2026-03-07T12:00:00.000Z",
"summary": {
"totalSize": 524288,
"totalSizeFormatted": "512.00 KB",
"totalRequests": 15
},
"groups": {
"Script": {
"count": 5,
"totalSize": 262144,
"totalSizeFormatted": "256.00 KB",
"assets": [...]
}
}
}Comma-separated values with columns: type, url, size_bytes, size_formatted.
The budget flags are designed for CI/CD pipelines. Set maximum weight constraints and the tool will exit with code 1 if any budget is exceeded, printing all violations.
pageweight https://example.com 1440 --budget 2MBLimit the total weight of all assets within a type:
pageweight https://example.com 1440 --budget-image 500KB --budget-script 300KBLimit the weight of any single asset. Use --budget-per-asset for a universal limit, or --budget-per-image / --budget-per-media for type-specific limits:
pageweight https://example.com 1440 --budget-per-image 200KB --budget-per-media 2MBAll budget flags can be used together. Every constraint is checked independently:
pageweight https://example.com 1440 \
--budget 2MB \
--budget-image 500KB \
--budget-per-image 200KB \
--budget-media 5MB \
--budget-per-media 2MB \
--budget-script 300KBBudget sizes accept: B, KB, MB, GB, or plain numbers (bytes).
You can also use pageweight as a library:
const { analyze, formatTable, formatJSON, formatCSV, checkBudgets, parseSizeString } = require('pageweight');
const result = await analyze({
url: 'https://example.com',
width: 1440,
height: 900, // optional, defaults to width
timeout: 60000, // optional
scroll: true, // optional
});
console.log(result.totalSizeFormatted); // e.g. "1.23 MB"
console.log(result.requestCount); // e.g. 42
// Format as table, JSON, or CSV
console.log(formatTable(result.assets));
console.log(formatJSON(result.assets, { url: result.url, viewport: result.viewport }));
console.log(formatCSV(result.assets));| Option | Type | Default | Description |
|---|---|---|---|
url |
string |
required | URL to analyze |
width |
number |
required | Viewport width in pixels |
height |
number |
width |
Viewport height in pixels |
timeout |
number |
60000 |
Navigation timeout in ms |
scroll |
boolean |
true |
Whether to scroll to bottom |
waitAfterScroll |
number |
2000 |
Time to wait after scrolling (ms) |
| Property | Type | Description |
|---|---|---|
url |
string |
The analyzed URL |
viewport |
{width, height} |
The viewport dimensions used |
assets |
Array |
All loaded assets with url, type, mimeType, statusCode, size |
totalSize |
number |
Total page weight in bytes |
totalSizeFormatted |
string |
Human-readable total size |
requestCount |
number |
Total number of requests |
const { analyze, checkBudgets } = require('pageweight');
const result = await analyze({ url: 'https://example.com', width: 1440 });
const violations = checkBudgets(result.assets, {
total: '2MB',
image: '500KB',
media: '5MB',
perImage: '200KB',
perMedia: '2MB',
script: '300KB',
perAsset: '1MB',
});
if (violations.length > 0) {
for (const v of violations) {
console.error(v.message);
}
}Contributions are welcome. To get started:
- Fork the repository
- Create a feature branch (
git checkout -b my-feature) - Commit your changes (
git commit -m "Add my feature") - Push to the branch (
git push origin my-feature) - Open a pull request
Please open an issue first if you plan a large change so it can be discussed.
This project is licensed under the ISC License.