├── LICENSE ├── README.md ├── assets └── images │ ├── basic-test.png │ ├── bulk-tests.png │ ├── chrometracedata.png │ ├── crux.png │ ├── dryrun.png │ ├── getresponsebody.png │ ├── lighthouse-scores.png │ ├── lighthouse.png │ ├── recipe-banner.png │ ├── screenshot-strip.jpg │ ├── specs.png │ ├── waterfall.png │ ├── webpagetest-chrome-recorder.png │ └── webvitals.png ├── bulk-tests.js ├── connectivity-custom.js ├── dryrun.js ├── getChromeTraceData.js ├── getResponseBody.js ├── lighthouse.js ├── mobile-device.js ├── multistep.js ├── network-and-cpu-throttling.js ├── screenshot-strip.js ├── slow-network.js ├── testspecs.js ├── third-party-domain-blocked.js ├── waterfall-image.js ├── webpagetest-chrome-recorder.js ├── webvitals-crux.js └── webvitals.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 WebPageTest 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Webpagetest Recipes Banner

2 |

3 | WebPageTest API Recipes 4 |

5 |

6 | 👩‍🍳 A collection of useful recipes for the WebPageTest API 7 |

8 |

🍔 What's your favorite recipe?

9 | 10 | ## 📖Table Of Contents 11 | 12 | - [Emulate a slow network](#emulate-a-slow-network) 13 | - [Emulate a slow network and CPU throttling](#emulate-network-&-cputhrottle) 14 | - [Emulate a custom connectivity (Bandwidth, Latency, PacketLossRate)](#emulate-a-custom-connectivity) 15 | - [Emulate a test on mobile device](#Emulate-a-test-on-mobile-device) 16 | - [Retrieve your Core Web Vitals](#retrieve-your-core-web-vitals) 17 | - [Retrieve your Core Web Vitals + CrUX data for the tested URL](#retrieve-your-core-web-vitals-+-crux) 18 | - [Run a test with a third-party domain blocked](#run-a-test-with-a-third-party-domain-blocked) 19 | - [Run a test and get the filmstrip screenshots](#run-a-test-and-get-the-filmstrip-screenshots) 20 | - [Run a test and generate a lighthouse report](#run-a-test-and-generate-a-lighthouse-report) 21 | - [Run a multi-step test with scripting](#run-a-multi-step-test-with-scripting) 22 | - [Run a test and generate a waterfall image](#run-a-test-and-generate-a-waterfall-image) 23 | - [Run tests on multiple URLs](#run-tests-on-multiple-urls) 24 | - [Create a URL endpoint](#create-a-url-endpoint) 25 | - [Run a test and check a budget using testspecs](#run-a-test-and-check-a-budget-using-testspecs) 26 | - [Run a test using webpagetest chrome recorder](#run-a-test-using-webpagetest-chrome-recorder) 27 | - [Retrieving chrome trace data](#retrieving-chrome-trace-data) 28 | - [Retrieving response body](#retrieving-response-body) 29 | 30 |

Emulate a slow network

31 | 32 | ```js 33 | import WebPageTest from "webpagetest"; 34 | 35 | const wptServer = "https://www.webpagetest.org"; 36 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 37 | 38 | let testURL = "https://docs.webpagetest.org/"; //Your URL here 39 | 40 | // Simulated network throttling (Slow 3G) 41 | let options = { 42 | location: "Dulles:Chrome", //mandatory with connectivity 43 | connectivity: "3G", 44 | }; 45 | 46 | // Run the test 47 | wpt.runTest(testURL, options, (err, result) => { 48 | if (result) { 49 | console.log(result); 50 | } else { 51 | console.log(err); 52 | } 53 | }); 54 | 55 | ``` 56 | ![Slow-network](/assets/images/basic-test.png "Emulate a slow network using Webpagetest") 57 | 58 | [Source](slow-network.js) 59 | 60 |

Emulate a slow network and CPU throttling

61 | 62 | ```js 63 | import WebPageTest from "webpagetest"; 64 | 65 | const wptServer = "https://www.webpagetest.org"; 66 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 67 | 68 | let testURL = "https://docs.webpagetest.org/"; //Your URL here 69 | 70 | // Simulated network & cpu throttling 71 | let options = { 72 | location: "Dulles:Chrome", 73 | connectivity: "3G", 74 | throttleCPU: 5, 75 | }; 76 | 77 | // Run the test 78 | wpt.runTest(testURL, options, (err, result) => { 79 | if (result) { 80 | console.log(result); 81 | } else { 82 | console.log(err); 83 | } 84 | }); 85 | 86 | 87 | ``` 88 | 89 | [Source](network-and-cpu-throttling.js) 90 | 91 |

Emulate a custom connectivity (Bandwidth, Latency, PacketLossRate)

92 | 93 | ```js 94 | import WebPageTest from "webpagetest"; 95 | 96 | const wptServer = "https://www.webpagetest.org"; 97 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 98 | 99 | let testURL = "https://docs.webpagetest.org/"; //Your URL here 100 | 101 | // Simulated custom connectivity options (custom) 102 | let options = { 103 | connectivity: "custom", 104 | location: "ec2-us-east-1:Chrome", 105 | label: "custom connectivity", 106 | bandwidthDown: 1000, 107 | bandwidthUp: 1000, 108 | latency: 5, 109 | packetLossRate: 5, 110 | }; 111 | 112 | // Run the test 113 | wpt.runTest(testURL, options, (err, result) => { 114 | if (result) { 115 | console.log(result); 116 | } else { 117 | console.log(err); 118 | } 119 | }); 120 | 121 | ``` 122 | 123 | [Source](connectivity-custom.js) 124 | 125 |

Emulate a test on mobile device

126 | 127 | ```js 128 | import WebPageTest from "webpagetest"; 129 | 130 | const wptServer = "https://www.webpagetest.org"; 131 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 132 | 133 | let testURL = "https://docs.webpagetest.org/"; //Your URL here 134 | 135 | let options = { 136 | location: "ec2-us-east-1:Chrome", 137 | label: "emulate mobile device", 138 | firstViewOnly: true, 139 | emulateMobile: true, 140 | device: "Nexus5", // optional (default: MotoG4) 141 | }; 142 | 143 | //Supported devices: https://github.com/WPO-Foundation/webpagetest/blob/master/www/settings/mobile_devices.ini 144 | 145 | // Run the test 146 | wpt.runTest(testURL, options, (err, result) => { 147 | if (result) { 148 | console.log(result); 149 | } else { 150 | console.log(err); 151 | } 152 | }); 153 | 154 | ``` 155 | 156 | [Source](mobile-device.js) 157 | 158 |

Retrieve your Core Web Vitals

159 | 160 | ```js 161 | import WebPageTest from "webpagetest"; 162 | 163 | const wptServer = "https://www.webpagetest.org"; 164 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 165 | 166 | let testURL = "https://docs.webpagetest.org/"; //Your URL here 167 | 168 | let options = { 169 | firstViewOnly: true, 170 | location: "Dulles:Chrome", 171 | pollResults: 60, 172 | timeout: 240, 173 | }; 174 | 175 | wpt.runTest(testURL, options, (err, result) => { 176 | if (result) { 177 | console.log({ 178 | CumulativeLayoutShift: result.data.average.firstView["chromeUserTiming.CumulativeLayoutShift"], 179 | LargestContentfulPaint: result.data.average.firstView["chromeUserTiming.LargestContentfulPaint"], 180 | TotalBlockingTime: result.data.average.firstView["TotalBlockingTime"], 181 | }); 182 | } else { 183 | console.log(err); 184 | } 185 | }); 186 | 187 | 188 | ``` 189 | ![Webvitals](/assets/images/webvitals.png "Get your webvitals using webpagetest WPT") 190 | 191 | [Source](webvitals.js) 192 | 193 | 194 |

Retrieve your Core Web Vitals + CrUX data for the tested URL

195 | 196 | ```js 197 | import WebPageTest from "webpagetest"; 198 | 199 | const wptServer = "https://www.webpagetest.org"; 200 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 201 | 202 | let testURL = "https://www.webpagetest.org/"; //Your URL here 203 | 204 | let options = { 205 | firstViewOnly: true, 206 | location: "Dulles:Chrome", 207 | pollResults: 60, 208 | timeout: 240, 209 | }; 210 | 211 | wpt.runTest(testURL, options, (err, result) => { 212 | if (result) { 213 | console.log("<-------------Core Web Vitals------------->"); 214 | console.log({ 215 | CumulativeLayoutShift: result.data.average.firstView["chromeUserTiming.CumulativeLayoutShift"], 216 | LargestContentfulPaint: result.data.average.firstView["chromeUserTiming.LargestContentfulPaint"], 217 | TotalBlockingTime: result.data.average.firstView["TotalBlockingTime"], 218 | }); 219 | 220 | if (result.data.median.firstView.CrUX !== undefined) { 221 | console.log("<----------------Crux Data---------------->"); 222 | console.log(result.data.median.firstView.CrUX); 223 | } else { 224 | console.log("No CrUX Data Found"); 225 | } 226 | } else { 227 | console.log(err); 228 | } 229 | }); 230 | 231 | ``` 232 | 233 | ![Webvitals + CrUX](/assets/images/crux.png "Generate a CrUX report using webpagetest WPT") 234 | 235 | [Source](webvitals-crux.js) 236 | 237 |

Run a test with a third-party domain blocked

238 | 239 | ```js 240 | import WebPageTest from "webpagetest"; 241 | 242 | const wptServer = "https://www.webpagetest.org"; 243 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 244 | 245 | let testURL = "https://theverge.com"; //Your URL here 246 | 247 | // URL's must be seprated by spaces (space-delimited) 248 | let options = { 249 | block: 250 | "https://pagead2.googlesyndication.com https://creativecdn.com https://www.googletagmanager.com https://cdn.krxd.net https://adservice.google.com https://cdn.concert.io https://z.moatads.com https://cdn.permutive.com", 251 | }; 252 | 253 | // Run the test 254 | wpt.runTest(testURL, options, (err, result) => { 255 | if (result) { 256 | console.log(result); 257 | } else { 258 | console.log(err); 259 | } 260 | }); 261 | 262 | ``` 263 | 264 | [Source](third-party-domain-blocked.js) 265 | 266 |

Run a test and get the filmstrip screenshots

267 | 268 | ```js 269 | import WebPageTest from "webpagetest"; 270 | import fs from "fs"; 271 | import axios from "axios"; 272 | 273 | const wptServer = "https://www.webpagetest.org"; 274 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 275 | 276 | let testURL = "https://docs.webpagetest.org/"; //Your URL here 277 | 278 | let options = { 279 | firstViewOnly: true, 280 | location: "Dulles:Chrome", 281 | connectivity: "4G", 282 | pollResults: 60, //keep polling for results after test is scheduled 283 | }; 284 | 285 | wpt.runTest(testURL, options, (err, result) => { 286 | if (result) { 287 | result.data.median.firstView.videoFrames.forEach((item, index) => { 288 | axios({ 289 | method: "get", 290 | url: item.image, 291 | responseType: "stream", 292 | }).then(function (response) { 293 | response.data.pipe(fs.createWriteStream(`screenshot-${index}.png`)); 294 | }); 295 | }); 296 | } else { 297 | console.log(err); 298 | } 299 | }); 300 | 301 | ``` 302 | ![Screenshot strip](/assets/images/screenshot-strip.jpg "Screenshot strip Webpagetest WPT") 303 | 304 | [Source](screenshot-strip.js) 305 | 306 |

Run a test and generate a lighthouse report

307 | 308 | ```js 309 | import WebPageTest from "webpagetest"; 310 | 311 | const wptServer = "https://www.webpagetest.org"; 312 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 313 | 314 | let testURL = "https://docs.webpagetest.org/"; //Your URL here 315 | 316 | let options = { 317 | pollResults: 60, 318 | timeout: 240, 319 | lighthouse: 1, // This parameter will generate both WPT results and Lighthouse report 320 | }; 321 | 322 | // Run the test 323 | wpt.runTest(testURL, options, (err, result) => { 324 | if (result) { 325 | console.log(`\n 326 | Lighthouse scores: 327 | Performance: ${result.data.lighthouse.categories.performance.score * 100}, 328 | Accessibility: ${result.data.lighthouse.categories.accessibility.score * 100}, 329 | Best Practices: ${result.data.lighthouse.categories['best-practices'].score * 100}, 330 | SEO: ${result.data.lighthouse.categories.seo.score * 100}, 331 | PWA: ${result.data.lighthouse.categories.pwa.score * 100} 332 | 333 | Lighthouse report: https://www.webpagetest.org/lighthouse.php?test=${result.data.id} 334 | Full WebPageTest results: ${result.data.summary} 335 | `); 336 | } else { 337 | console.log(err); 338 | } 339 | }); 340 | 341 | ``` 342 | ![Lighthouse scores by Webpagetest WPT](/assets/images/lighthouse-scores.png "Lighthouse scores") 343 | 344 | ![Lighthouse report by Webpagetest WPT](/assets/images/lighthouse.png "Lighthouse report") 345 | 346 | [Source](lighthouse.js) 347 | 348 |

Run a multi-step test with scripting

349 | 350 | ```js 351 | import WebPageTest from "webpagetest"; 352 | 353 | const wptServer = "https://www.webpagetest.org"; 354 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 355 | 356 | let options = { 357 | pollResults: 60, 358 | firstViewOnly: true, //Skips the Repeat View test 359 | }; 360 | 361 | const script = wpt.scriptToString([ 362 | { logData: 0 }, 363 | { navigate: "http://foo.com/login" }, 364 | { logData: 1 }, 365 | { setValue: ["name=username", "johndoe"] }, 366 | { setValue: ["name=password", "12345"] }, 367 | { submitForm: "action=http://foo.com/main" }, 368 | "waitForComplete", 369 | ]); 370 | 371 | // Run the test 372 | wpt.runTest(script, options, (err, result) => { 373 | if (result) { 374 | console.log(result); 375 | } else { 376 | console.log(err); 377 | } 378 | }); 379 | 380 | ``` 381 | 382 | Visit [Scripting Docs](https://docs.webpagetest.org/scripting/) for more information 383 | 384 | [Source](multistep.js) 385 | 386 | 387 |

Run a test and generate a waterfall image

388 | 389 | ```js 390 | import WebPageTest from "webpagetest"; 391 | import fs from "fs"; 392 | import axios from "axios"; 393 | 394 | const wptServer = "https://www.webpagetest.org"; 395 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 396 | 397 | let testURL = "https://docs.webpagetest.org/"; //Your URL here 398 | 399 | let options = { 400 | firstViewOnly: true, 401 | location: "Dulles:Chrome", 402 | connectivity: "4G", 403 | pollResults: 60, //keep polling for results after test is scheduled 404 | }; 405 | 406 | wpt.runTest(testURL, options, (err, result) => { 407 | if (result) { 408 | let imgurl = result.data.median.firstView.images.waterfall; 409 | 410 | axios({ 411 | method: "get", 412 | url: imgurl, 413 | responseType: "stream", 414 | }).then(function (response) { 415 | response.data.pipe(fs.createWriteStream("waterfall.png")); 416 | }); 417 | } else { 418 | console.log(err); 419 | } 420 | }); 421 | 422 | ``` 423 | ![Waterfall image by WbePagetest WPT](/assets/images/waterfall.png "Waterfall image") 424 | 425 | [Source](waterfall-image.js) 426 | 427 |

Run tests on multiple URLs

428 | 429 | ```js 430 | import WebPageTest from "webpagetest"; 431 | 432 | const wpt = new WebPageTest("www.webpagetest.org", "YOUR_API_KEY"); 433 | const finalResults = []; 434 | 435 | // Your list of URLs to test 436 | let urls = [ 437 | "https://www.webpagetest.org/", 438 | "https://www.product.webpagetest.org/api", 439 | "https://docs.webpagetest.org/api/", 440 | "https://blog.webpagetest.org/", 441 | "https://www.webpagetest.org/about", 442 | ]; 443 | 444 | let options = { 445 | firstViewOnly: true, 446 | location: "Dulles:Chrome", 447 | connectivity: "4G", 448 | pollResults: 60, 449 | timeout: 240, 450 | }; 451 | 452 | const runTest = (wpt, url, options) => { 453 | return new Promise((resolve, reject) => { 454 | console.log(`Submitting test for ${url}...`); 455 | wpt.runTest(url, options, async (err, result) => { 456 | try { 457 | if (result) { 458 | return resolve(result); 459 | } else { 460 | return reject(err); 461 | } 462 | } catch (e) { 463 | console.info(e); 464 | } 465 | }); 466 | }); 467 | }; 468 | 469 | (async function () { 470 | Promise.all( 471 | urls.map(async (url) => { 472 | try { 473 | await runTest(wpt, url, options).then(async (result) => { 474 | if (result.data) { 475 | let median = result.data.median.firstView; 476 | //Pushing the data into the Array 477 | finalResults.push({ 478 | id: result.data.id, 479 | url: result.data.url, 480 | cls: median["chromeUserTiming.CumulativeLayoutShift"], 481 | lcp: median["chromeUserTiming.LargestContentfulPaint"], 482 | tbt: median["TotalBlockingTime"], 483 | }); 484 | } 485 | }); 486 | } catch (e) { 487 | console.error(e); 488 | } 489 | }) 490 | ).then(() => { 491 | console.info(finalResults); 492 | }); 493 | })(); 494 | 495 | ``` 496 | ![Bulk Tests URLs using WebPageTest WPT](/assets/images/bulk-tests.png "Bulk Tests") 497 | 498 | [Source](bulk-tests.js) 499 | 500 |

Create a URL endpoint

501 | 502 | ```js 503 | import WebPageTest from "webpagetest"; 504 | 505 | const wptServer = "https://www.webpagetest.org"; 506 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 507 | 508 | let options = { 509 | dryRun: true, // outputs the api endpoint 510 | }; 511 | 512 | // multistep script 513 | const script = wpt.scriptToString([ 514 | { navigate: 'https://timkadlec.com/' }, 515 | { execAndWait: 'document.querySelector("#nav > ul > li:nth-child(2) > a").click();' }, 516 | { execAndWait: 'document.querySelector("#nav > ul > li:nth-child(3) > a").click();' }, 517 | { execAndWait: 'document.querySelector("#nav > ul > li:nth-child(4) > a").click();' }, 518 | ]); 519 | 520 | // fire up the runtest function with a script or a url 521 | wpt.runTest(script, options, (err, result) => { 522 | if (result) { 523 | console.log(result); 524 | } else { 525 | console.log(err); 526 | } 527 | }); 528 | 529 | 530 | ``` 531 | ![Generate a url using dryRun option](/assets/images/dryrun.png "DryRun Test") 532 | 533 | [Source](dryrun.js) 534 | 535 |

Run a test and check a budget using testspecs

536 | 537 | ```js 538 | import WebPageTest from "webpagetest"; 539 | 540 | const wptServer = "https://www.webpagetest.org"; 541 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 542 | 543 | let testURL = "https://docs.webpagetest.org/"; //Your URL here 544 | 545 | let options = { 546 | firstViewOnly: true, 547 | location: "Dulles:Chrome", 548 | pollResults: 60, 549 | timeout: 240, 550 | // Set you budget specs here 551 | specs: { 552 | average: { 553 | firstView: { 554 | "chromeUserTiming.CumulativeLayoutShift": 0.1, 555 | "chromeUserTiming.LargestContentfulPaint": 2500, 556 | firstContentfulPaint: 2000, 557 | TotalBlockingTime: 0.1, 558 | }, 559 | }, 560 | }, 561 | }; 562 | 563 | wpt.runTest(testURL, options, (err, result) => { 564 | if (result) { 565 | console.log(`Your results are here for test ID:- ${result.testId}`); 566 | } else { 567 | console.log(err); 568 | } 569 | }); 570 | 571 | ``` 572 | ![Check a budget using testspecs](/assets/images/specs.png "testspecs") 573 | 574 | Check [Testspecs](https://github.com/WebPageTest/webpagetest-api/wiki/Test-Specs) for more details on setting a budget 575 | 576 | [Source](testspecs.js) 577 | 578 |

Run a test using webpagetest chrome recorder

579 | 580 | ```js 581 | import WebPageTest from "webpagetest"; 582 | import { WPTStringifyChromeRecording } from "webpagetest-chrome-recorder"; 583 | 584 | //Recording generated using chrome recorder 585 | const recordingContent = { 586 | title: "Webpagetest Chrome Recorder", 587 | steps: [ 588 | { 589 | type: "setViewport", 590 | width: 1263, 591 | height: 600, 592 | deviceScaleFactor: 1, 593 | isMobile: false, 594 | hasTouch: false, 595 | isLandscape: false, 596 | }, 597 | { 598 | type: "navigate", 599 | url: "https://blog.webpagetest.org/", 600 | assertedEvents: [ 601 | { 602 | type: "navigation", 603 | url: "https://blog.webpagetest.org/", 604 | title: "WebPageTest Blog", 605 | }, 606 | ], 607 | }, 608 | { 609 | type: "click", 610 | target: "main", 611 | selectors: [["header li:nth-of-type(2) > a"]], 612 | offsetY: 27.802078247070312, 613 | offsetX: 26.427078247070312, 614 | assertedEvents: [ 615 | { 616 | type: "navigation", 617 | url: "https://blog.webpagetest.org/categories/webpagetest-news/", 618 | title: "", 619 | }, 620 | ], 621 | }, 622 | ], 623 | }; 624 | 625 | //Converting json recording to webpagetest script 626 | const script = await WPTStringifyChromeRecording(recordingContent); 627 | console.log("Stringified Webpagetest Recorder Script: \n\n" + script + "\n"); 628 | 629 | // Initializing webpagetest 630 | const wptServer = "https://www.webpagetest.org"; 631 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 632 | 633 | let options = { 634 | firstViewOnly: true, 635 | label: recordingContent.title, 636 | }; 637 | 638 | console.log("Webpagetest Custom Script Test Result: \n"); 639 | 640 | // Run the test using webpagetest script 641 | wpt.runTest(script, options, (err, result) => { 642 | if (result) { 643 | console.log(result); 644 | } else { 645 | console.log(err); 646 | } 647 | }); 648 | 649 | ``` 650 | ![Run a test using webpagetest chrome recorder](/assets/images/webpagetest-chrome-recorder.png "webpagetest chrome recorder") 651 | 652 | Check [Webpagetest Chrome Recorder](https://github.com/WebPageTest/Recorder-To-WPT-Script) for more details 653 | 654 | [Source](webpagetest-chrome-recorder.js) 655 | 656 |

Retrieving chrome trace data

657 | 658 | ```js 659 | import WebPageTest from "webpagetest"; 660 | 661 | const wptServer = "https://www.webpagetest.org"; 662 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 663 | 664 | let testId = "YOUR_TEST_ID"; //Your URL here 665 | 666 | // Retrieving Chrome Trace Data 667 | wpt.getChromeTraceData(testId, (err, result) => { 668 | if (result) { 669 | console.log(result); 670 | } else { 671 | console.log(err); 672 | } 673 | }); 674 | 675 | ``` 676 | ![Retrieving chrome trace data](/assets/images/chrometracedata.png "chrome trace") 677 | 678 | [Source](getChromeTraceData.js) 679 | 680 |

Retrieving Response Body

681 | 682 | ```js 683 | import WebPageTest from "webpagetest"; 684 | 685 | const wptServer = "https://www.webpagetest.org"; 686 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 687 | 688 | let testID = "YOUR_TEST_ID"; 689 | 690 | let options = { 691 | run: 1, // the run from which you'd want to fetch the response body 692 | request: 2, // the request number same as waterfall 693 | cached: 0, // check for the repeat view 694 | }; 695 | 696 | // Retrieving response body (Make sure you've enabled the save response body on this test) 697 | wpt.getResponseBody(testID, options, (err, result) => { 698 | if (result) { 699 | console.log(result); 700 | } else { 701 | console.log(err); 702 | } 703 | }); 704 | 705 | ``` 706 | ![Retrieving Response Body](/assets/images/getresponsebody.png "Response Body") 707 | 708 | [Source](getResponseBody.js) -------------------------------------------------------------------------------- /assets/images/basic-test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catchpoint/WebPageTest.api-recipes/8fe8160fbadbf316427f9891a4f9a896edbc2dda/assets/images/basic-test.png -------------------------------------------------------------------------------- /assets/images/bulk-tests.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catchpoint/WebPageTest.api-recipes/8fe8160fbadbf316427f9891a4f9a896edbc2dda/assets/images/bulk-tests.png -------------------------------------------------------------------------------- /assets/images/chrometracedata.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catchpoint/WebPageTest.api-recipes/8fe8160fbadbf316427f9891a4f9a896edbc2dda/assets/images/chrometracedata.png -------------------------------------------------------------------------------- /assets/images/crux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catchpoint/WebPageTest.api-recipes/8fe8160fbadbf316427f9891a4f9a896edbc2dda/assets/images/crux.png -------------------------------------------------------------------------------- /assets/images/dryrun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catchpoint/WebPageTest.api-recipes/8fe8160fbadbf316427f9891a4f9a896edbc2dda/assets/images/dryrun.png -------------------------------------------------------------------------------- /assets/images/getresponsebody.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catchpoint/WebPageTest.api-recipes/8fe8160fbadbf316427f9891a4f9a896edbc2dda/assets/images/getresponsebody.png -------------------------------------------------------------------------------- /assets/images/lighthouse-scores.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catchpoint/WebPageTest.api-recipes/8fe8160fbadbf316427f9891a4f9a896edbc2dda/assets/images/lighthouse-scores.png -------------------------------------------------------------------------------- /assets/images/lighthouse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catchpoint/WebPageTest.api-recipes/8fe8160fbadbf316427f9891a4f9a896edbc2dda/assets/images/lighthouse.png -------------------------------------------------------------------------------- /assets/images/recipe-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catchpoint/WebPageTest.api-recipes/8fe8160fbadbf316427f9891a4f9a896edbc2dda/assets/images/recipe-banner.png -------------------------------------------------------------------------------- /assets/images/screenshot-strip.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catchpoint/WebPageTest.api-recipes/8fe8160fbadbf316427f9891a4f9a896edbc2dda/assets/images/screenshot-strip.jpg -------------------------------------------------------------------------------- /assets/images/specs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catchpoint/WebPageTest.api-recipes/8fe8160fbadbf316427f9891a4f9a896edbc2dda/assets/images/specs.png -------------------------------------------------------------------------------- /assets/images/waterfall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catchpoint/WebPageTest.api-recipes/8fe8160fbadbf316427f9891a4f9a896edbc2dda/assets/images/waterfall.png -------------------------------------------------------------------------------- /assets/images/webpagetest-chrome-recorder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catchpoint/WebPageTest.api-recipes/8fe8160fbadbf316427f9891a4f9a896edbc2dda/assets/images/webpagetest-chrome-recorder.png -------------------------------------------------------------------------------- /assets/images/webvitals.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catchpoint/WebPageTest.api-recipes/8fe8160fbadbf316427f9891a4f9a896edbc2dda/assets/images/webvitals.png -------------------------------------------------------------------------------- /bulk-tests.js: -------------------------------------------------------------------------------- 1 | import WebPageTest from "webpagetest"; 2 | 3 | const wptServer = "https://www.webpagetest.org"; 4 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 5 | 6 | const finalResults = []; 7 | 8 | // Your list of URLs to test 9 | let urls = [ 10 | "https://www.webpagetest.org/", 11 | "https://www.product.webpagetest.org/api", 12 | "https://docs.webpagetest.org/api/", 13 | "https://blog.webpagetest.org/", 14 | "https://www.webpagetest.org/about", 15 | ]; 16 | 17 | let options = { 18 | firstViewOnly: true, 19 | location: "Dulles:Chrome", 20 | connectivity: "4G", 21 | pollResults: 5, 22 | timeout: 240, 23 | }; 24 | 25 | const runTest = (wpt, url, options) => { 26 | return new Promise((resolve, reject) => { 27 | console.log(`Submitting test for ${url}...`); 28 | wpt.runTest(url, options, async (err, result) => { 29 | try { 30 | if (result) { 31 | return resolve(result); 32 | } else { 33 | return reject(err); 34 | } 35 | } catch (e) { 36 | console.info(e); 37 | } 38 | }); 39 | }); 40 | }; 41 | 42 | (async function () { 43 | Promise.all( 44 | urls.map(async (url) => { 45 | try { 46 | await runTest(wpt, url, options).then(async (result) => { 47 | if (result.data) { 48 | let median = result.data.median.firstView; 49 | //Pushing the data into the Array 50 | finalResults.push({ 51 | id: result.data.id, 52 | url: result.data.url, 53 | cls: median["chromeUserTiming.CumulativeLayoutShift"], 54 | lcp: median["chromeUserTiming.LargestContentfulPaint"], 55 | tbt: median["TotalBlockingTime"], 56 | }); 57 | } 58 | }); 59 | } catch (e) { 60 | console.error(e); 61 | } 62 | }) 63 | ).then(() => { 64 | console.info(finalResults); 65 | }); 66 | })(); 67 | -------------------------------------------------------------------------------- /connectivity-custom.js: -------------------------------------------------------------------------------- 1 | import WebPageTest from "webpagetest"; 2 | 3 | const wptServer = "https://www.webpagetest.org"; 4 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 5 | 6 | let testURL = "https://docs.webpagetest.org/"; //Your URL here 7 | 8 | // Simulated custom connectivity options (custom) 9 | let options = { 10 | connectivity: "custom", 11 | location: "ec2-us-east-1:Chrome", 12 | label: "custom connectivity", 13 | bandwidthDown: 1000, 14 | bandwidthUp: 1000, 15 | latency: 5, 16 | packetLossRate: 5, 17 | }; 18 | 19 | // Run the test 20 | wpt.runTest(testURL, options, (err, result) => { 21 | if (result) { 22 | console.log(result); 23 | } else { 24 | console.log(err); 25 | } 26 | }); 27 | -------------------------------------------------------------------------------- /dryrun.js: -------------------------------------------------------------------------------- 1 | import WebPageTest from "webpagetest"; 2 | 3 | const wptServer = "https://www.webpagetest.org"; 4 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 5 | 6 | let options = { 7 | dryRun: true, // outputs the api endpoint 8 | }; 9 | 10 | // multistep script 11 | const script = wpt.scriptToString([ 12 | { navigate: "https://timkadlec.com/" }, 13 | { execAndWait: 'document.querySelector("#nav > ul > li:nth-child(2) > a").click();' }, 14 | { execAndWait: 'document.querySelector("#nav > ul > li:nth-child(3) > a").click();' }, 15 | { execAndWait: 'document.querySelector("#nav > ul > li:nth-child(4) > a").click();' }, 16 | ]); 17 | 18 | // fire up the runtest function with a script or a url 19 | wpt.runTest(script, options, (err, result) => { 20 | if (result) { 21 | console.log(result); 22 | } else { 23 | console.log(err); 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /getChromeTraceData.js: -------------------------------------------------------------------------------- 1 | import WebPageTest from "webpagetest"; 2 | 3 | const wptServer = "https://www.webpagetest.org"; 4 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 5 | 6 | let testId = "YOUR_TEST_ID"; //Your URL here 7 | 8 | // Retrieving Chrome Trace Data 9 | wpt.getChromeTraceData(testId, (err, result) => { 10 | if (result) { 11 | console.log(result); 12 | } else { 13 | console.log(err); 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /getResponseBody.js: -------------------------------------------------------------------------------- 1 | import WebPageTest from "webpagetest"; 2 | 3 | const wptServer = "https://www.webpagetest.org"; 4 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 5 | 6 | let testID = "YOUR_TEST_ID"; 7 | 8 | let options = { 9 | run: 1, // the run from which you'd want to fetch the response body 10 | request: 2, // the request number same as waterfall 11 | cached: 1, // check for the repeat view 12 | }; 13 | 14 | // Retrieving response body (Make sure you've enabled the save response body on this test) 15 | wpt.getResponseBody(testID, options, (err, result) => { 16 | if (result) { 17 | console.log(result); 18 | } else { 19 | console.log(err); 20 | } 21 | }); 22 | -------------------------------------------------------------------------------- /lighthouse.js: -------------------------------------------------------------------------------- 1 | import WebPageTest from "webpagetest"; 2 | 3 | const wptServer = "https://www.webpagetest.org"; 4 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 5 | 6 | let testURL = "https://docs.webpagetest.org/"; //Your URL here 7 | 8 | let options = { 9 | pollResults: 5, 10 | timeout: 240, 11 | lighthouse: 1, // This parameter will generate both WPT results and Lighthouse report 12 | }; 13 | 14 | // Run the test 15 | wpt.runTest(testURL, options, (err, result) => { 16 | if (result) { 17 | console.log(`\n 18 | Lighthouse scores: 19 | Performance: ${result.data.lighthouse.categories.performance.score * 100}, 20 | Accessibility: ${result.data.lighthouse.categories.accessibility.score * 100}, 21 | Best Practices: ${result.data.lighthouse.categories["best-practices"].score * 100}, 22 | SEO: ${result.data.lighthouse.categories.seo.score * 100}, 23 | PWA: ${result.data.lighthouse.categories.pwa.score * 100} 24 | 25 | Lighthouse report: https://www.webpagetest.org/lighthouse.php?test=${result.data.id} 26 | Full WebPageTest results: ${result.data.summary} 27 | `); 28 | } else { 29 | console.log(err); 30 | } 31 | }); 32 | -------------------------------------------------------------------------------- /mobile-device.js: -------------------------------------------------------------------------------- 1 | import WebPageTest from "webpagetest"; 2 | 3 | const wptServer = "https://www.webpagetest.org"; 4 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 5 | 6 | let testURL = "https://docs.webpagetest.org/"; //Your URL here 7 | 8 | let options = { 9 | location: "ec2-us-east-1:Chrome", 10 | label: "emulate mobile device", 11 | firstViewOnly: true, 12 | emulateMobile: true, 13 | device: "Nexus5", // optional (default: MotoG4) 14 | }; 15 | 16 | //List of support devices https://github.com/WPO-Foundation/webpagetest/blob/master/www/settings/mobile_devices.ini 17 | 18 | // Run the test 19 | wpt.runTest(testURL, options, (err, result) => { 20 | if (result) { 21 | console.log(result); 22 | } else { 23 | console.log(err); 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /multistep.js: -------------------------------------------------------------------------------- 1 | import WebPageTest from "webpagetest"; 2 | 3 | const wptServer = "https://www.webpagetest.org"; 4 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 5 | 6 | let options = { 7 | pollResults: 5, 8 | firstViewOnly: true, //Skips the Repeat View test 9 | }; 10 | 11 | const script = wpt.scriptToString([ 12 | { logData: 0 }, 13 | { navigate: "http://foo.com/login" }, 14 | { logData: 1 }, 15 | { setValue: ["name=username", "johndoe"] }, 16 | { setValue: ["name=password", "12345"] }, 17 | { submitForm: "action=http://foo.com/main" }, 18 | "waitForComplete", 19 | ]); 20 | 21 | // Run the test 22 | wpt.runTest(script, options, (err, result) => { 23 | if (result) { 24 | console.log(result); 25 | } else { 26 | console.log(err); 27 | } 28 | }); 29 | -------------------------------------------------------------------------------- /network-and-cpu-throttling.js: -------------------------------------------------------------------------------- 1 | import WebPageTest from "webpagetest"; 2 | 3 | const wptServer = "https://www.webpagetest.org"; 4 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 5 | 6 | let testURL = "https://docs.webpagetest.org/"; //Your URL here 7 | 8 | // Simulated network & cpu throttling 9 | let options = { 10 | location: "Dulles:Chrome", 11 | connectivity: "3G", 12 | throttleCPU: 5, 13 | }; 14 | 15 | // Run the test 16 | wpt.runTest(testURL, options, (err, result) => { 17 | if (result) { 18 | console.log(result); 19 | } else { 20 | console.log(err); 21 | } 22 | }); 23 | -------------------------------------------------------------------------------- /screenshot-strip.js: -------------------------------------------------------------------------------- 1 | import WebPageTest from "webpagetest"; 2 | import fs from "fs"; 3 | import axios from "axios"; 4 | 5 | const wptServer = "https://www.webpagetest.org"; 6 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 7 | 8 | let testURL = "https://docs.webpagetest.org/"; //Your URL here 9 | 10 | let options = { 11 | firstViewOnly: true, 12 | location: "Dulles:Chrome", 13 | connectivity: "4G", 14 | pollResults: 5, //keep polling for results after test is scheduled 15 | }; 16 | 17 | wpt.runTest(testURL, options, (err, result) => { 18 | if (result) { 19 | result.data.median.firstView.videoFrames.forEach((item, index) => { 20 | axios({ 21 | method: "get", 22 | url: item.image, 23 | responseType: "stream", 24 | }).then(function (response) { 25 | response.data.pipe(fs.createWriteStream(`screenshot-${index}.png`)); 26 | }); 27 | }); 28 | } else { 29 | console.log(err); 30 | } 31 | }); 32 | -------------------------------------------------------------------------------- /slow-network.js: -------------------------------------------------------------------------------- 1 | import WebPageTest from "webpagetest"; 2 | 3 | const wptServer = "https://www.webpagetest.org"; 4 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 5 | 6 | let testURL = "https://docs.webpagetest.org/"; //Your URL here 7 | 8 | // Simulated network throttling (Slow 3G) 9 | let options = { 10 | location: "Dulles:Chrome", //mandatory with connectivity 11 | connectivity: "3G", 12 | }; 13 | 14 | // Run the test 15 | wpt.runTest(testURL, options, (err, result) => { 16 | if (result) { 17 | console.log(result); 18 | } else { 19 | console.log(err); 20 | } 21 | }); 22 | -------------------------------------------------------------------------------- /testspecs.js: -------------------------------------------------------------------------------- 1 | import WebPageTest from "webpagetest"; 2 | 3 | const wptServer = "https://www.webpagetest.org"; 4 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 5 | 6 | let testURL = "https://docs.webpagetest.org/"; //Your URL here 7 | 8 | let options = { 9 | firstViewOnly: true, 10 | location: "Dulles:Chrome", 11 | pollResults: 5, 12 | timeout: 240, 13 | // Set you budget specs here 14 | specs: { 15 | average: { 16 | firstView: { 17 | "chromeUserTiming.CumulativeLayoutShift": 0.1, 18 | "chromeUserTiming.LargestContentfulPaint": 2500, 19 | firstContentfulPaint: 2000, 20 | TotalBlockingTime: 0.1, 21 | }, 22 | }, 23 | }, 24 | }; 25 | 26 | wpt.runTest(testURL, options, (err, result) => { 27 | if (result) { 28 | console.log(`Your results are here for test ID:- ${result.testId}`); 29 | } else { 30 | console.log(err); 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /third-party-domain-blocked.js: -------------------------------------------------------------------------------- 1 | import WebPageTest from "webpagetest"; 2 | 3 | const wptServer = "https://www.webpagetest.org"; 4 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 5 | 6 | let testURL = "https://theverge.com"; //Your URL here 7 | 8 | // URL's must be seprated by spaces (space-delimited) 9 | let options = { 10 | block: 11 | "https://pagead2.googlesyndication.com https://creativecdn.com https://www.googletagmanager.com https://cdn.krxd.net https://adservice.google.com https://cdn.concert.io https://z.moatads.com https://cdn.permutive.com", 12 | }; 13 | 14 | // Run the test 15 | wpt.runTest(testURL, options, (err, result) => { 16 | if (result) { 17 | console.log(result); 18 | } else { 19 | console.log(err); 20 | } 21 | }); 22 | -------------------------------------------------------------------------------- /waterfall-image.js: -------------------------------------------------------------------------------- 1 | import WebPageTest from "webpagetest"; 2 | import fs from "fs"; 3 | import axios from "axios"; 4 | 5 | const wptServer = "https://www.webpagetest.org"; 6 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 7 | 8 | let testURL = "https://docs.webpagetest.org/"; //Your URL here 9 | 10 | let options = { 11 | firstViewOnly: true, 12 | location: "Dulles:Chrome", 13 | connectivity: "4G", 14 | pollResults: 5, //keep polling for results after test is scheduled 15 | }; 16 | 17 | wpt.runTest(testURL, options, (err, result) => { 18 | if (result) { 19 | let imgurl = result.data.median.firstView.images.waterfall; 20 | 21 | axios({ 22 | method: "get", 23 | url: imgurl, 24 | responseType: "stream", 25 | }).then(function (response) { 26 | response.data.pipe(fs.createWriteStream("waterfall.png")); 27 | }); 28 | } else { 29 | console.log(err); 30 | } 31 | }); 32 | -------------------------------------------------------------------------------- /webpagetest-chrome-recorder.js: -------------------------------------------------------------------------------- 1 | import WebPageTest from "webpagetest"; 2 | import { WPTStringifyChromeRecording } from "webpagetest-chrome-recorder"; 3 | 4 | //Recording generated using chrome recorder 5 | const recordingContent = { 6 | title: "Webpagetest Chrome Recorder", 7 | steps: [ 8 | { 9 | type: "setViewport", 10 | width: 1263, 11 | height: 600, 12 | deviceScaleFactor: 1, 13 | isMobile: false, 14 | hasTouch: false, 15 | isLandscape: false, 16 | }, 17 | { 18 | type: "navigate", 19 | url: "https://blog.webpagetest.org/", 20 | assertedEvents: [ 21 | { 22 | type: "navigation", 23 | url: "https://blog.webpagetest.org/", 24 | title: "WebPageTest Blog", 25 | }, 26 | ], 27 | }, 28 | { 29 | type: "click", 30 | target: "main", 31 | selectors: [["header li:nth-of-type(2) > a"]], 32 | offsetY: 27.802078247070312, 33 | offsetX: 26.427078247070312, 34 | assertedEvents: [ 35 | { 36 | type: "navigation", 37 | url: "https://blog.webpagetest.org/categories/webpagetest-news/", 38 | title: "", 39 | }, 40 | ], 41 | }, 42 | ], 43 | }; 44 | 45 | //Converting json recording to webpagetest script 46 | const script = await WPTStringifyChromeRecording(recordingContent); 47 | console.log("Stringified Webpagetest Recorder Script: \n\n" + script + "\n"); 48 | 49 | // Initializing webpagetest 50 | const wptServer = "https://www.webpagetest.org"; 51 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 52 | 53 | let options = { 54 | firstViewOnly: true, 55 | label: recordingContent.title, 56 | }; 57 | 58 | console.log("Webpagetest Custom Script Test Result: \n"); 59 | 60 | // Run the test using webpagetest script 61 | wpt.runTest(script, options, (err, result) => { 62 | if (result) { 63 | console.log(result); 64 | } else { 65 | console.log(err); 66 | } 67 | }); 68 | -------------------------------------------------------------------------------- /webvitals-crux.js: -------------------------------------------------------------------------------- 1 | import WebPageTest from "webpagetest"; 2 | 3 | const wptServer = "https://www.webpagetest.org"; 4 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 5 | 6 | let testURL = "https://www.webpagetest.org/"; //Your URL here 7 | 8 | let options = { 9 | firstViewOnly: true, 10 | location: "Dulles:Chrome", 11 | pollResults: 5, 12 | timeout: 240, 13 | }; 14 | 15 | wpt.runTest(testURL, options, (err, result) => { 16 | if (result) { 17 | console.log("<-------------Core Web Vitals------------->"); 18 | console.log({ 19 | CumulativeLayoutShift: 20 | result.data.average.firstView["chromeUserTiming.CumulativeLayoutShift"], 21 | LargestContentfulPaint: 22 | result.data.average.firstView["chromeUserTiming.LargestContentfulPaint"], 23 | TotalBlockingTime: result.data.average.firstView["TotalBlockingTime"], 24 | }); 25 | 26 | if (result.data.median.firstView.CrUX !== undefined) { 27 | console.log("<----------------Crux Data---------------->"); 28 | console.log(result.data.median.firstView.CrUX); 29 | } else { 30 | console.log("No CrUX Data Found"); 31 | } 32 | } else { 33 | console.log(err); 34 | } 35 | }); 36 | -------------------------------------------------------------------------------- /webvitals.js: -------------------------------------------------------------------------------- 1 | import WebPageTest from "webpagetest"; 2 | 3 | const wptServer = "https://www.webpagetest.org"; 4 | const wpt = new WebPageTest(wptServer, "YOUR_API_KEY"); 5 | 6 | let testURL = "https://docs.webpagetest.org/"; //Your URL here 7 | 8 | let options = { 9 | firstViewOnly: true, 10 | location: "Dulles:Chrome", 11 | pollResults: 5, 12 | timeout: 240, 13 | }; 14 | 15 | wpt.runTest(testURL, options, (err, result) => { 16 | if (result) { 17 | console.log({ 18 | CumulativeLayoutShift: 19 | result.data.average.firstView["chromeUserTiming.CumulativeLayoutShift"], 20 | LargestContentfulPaint: 21 | result.data.average.firstView["chromeUserTiming.LargestContentfulPaint"], 22 | TotalBlockingTime: result.data.average.firstView["TotalBlockingTime"], 23 | }); 24 | } else { 25 | console.log(err); 26 | } 27 | }); 28 | --------------------------------------------------------------------------------