• 18-19 College Green, Dublin 2
  • 01 685 9088
  • info@cunninghamwebsolutions.com
  • cunninghamwebsolutions
    Cunningham Web Solutions
    • HomeHome
    • About UsAbout Us
    • Our ServicesOur Services
      • Web Design
      • Digital Marketing
      • SEO Services
      • E-commerce Websites
      • Website Redevelopment
      • Social Media Services
    • Digital MarketingDigital Marketing
      • Adwords
      • Social Media Services
      • Email Marketing
      • Display Advertising
      • Remarketing
    • PortfolioPortfolio
    • FAQ’sFAQ’s
    • BlogBlog
    • Contact UsContact Us
    MENU CLOSE back  
    • Home
    • About Us
    • Our Services
      • back
      • Web Design
      • Digital Marketing
      • SEO Services
      • E-commerce Websites
      • Website Redevelopment
      • Social Media Services
    • Digital Marketing
      • back
      • Adwords
      • Social Media Services
      • Email Marketing
      • Display Advertising
      • Remarketing
    • Portfolio
    • FAQ’s
    • Blog
    • Contact Us

    An Introduction To Running Lighthouse Programmatically

    You are here:
    1. Home
    2. Web Design
    3. An Introduction To Running Lighthouse Programmatically
    Thumbnail for 25588

    Lighthouse is Google’s suite of website quality analysis tools. It allows you to assess your site’s performance, accessibility, SEO, and more. It is also highly configurable, making it flexible enough to be useful for all sites, from the simplest to the highly complex. This flexibility includes several different ways of running the tests, allowing you to choose the method that works best for your site or application.

    One of the simplest ways to run Lighthouse is through Chrome’s DevTools Lighthouse panel. If you open your site in Chrome and then open Chrome’s DevTools, you should see a “Lighthouse” tab. From there, if you click “Generate Report”, you should get a full report of your site’s quality metrics.

    What I am focusing on in this article, however, is at the other end of the spectrum. Running Lighthouse programmatically with JavaScript allows us to configure custom runs, picking and choosing the features we want to test, collecting and analyzing results, and specifying configuration options unique to our sites and applications.

    For example, perhaps you work on a site that is accessible through multiple URLs — each with its own data and styling and perhaps even markup that you want to be able to analyze. Or maybe you want to gather the data from each test run and compile or analyze it in different ways. Having the ability to choose how you want to run a Lighthouse analysis based on what works best for your site or application makes it easier to monitor site quality and pinpoint where there are issues with your site before they pile up or cause too many problems for your site’s users.

    Running Lighthouse programmatically is not the best choice for every site and I encourage you to explore all the different methods the Lighthouse team has built for using the tool. If you decide to use Lighthouse programmatically, however, the information and tutorial below should hopefully get you started.

    Customizing Lighthouse Options

    The advantage of running Lighthouse programmatically isn’t only the ability to configure Lighthouse itself, but rather all the things you might want or need to do around the Lighthouse tests. Lighthouse has some great documentation to get you started. To get the most out of running it programmatically, however, there are two main places where you will need to dig in and learn more about how Lighthouse works: configuring your test runs and reporting your test results.

    Lighthouse Test Run Configuration

    Configuring a Lighthouse test run is one of those tasks that can be as simple or as complex as you like.

    When running Lighthouse programmatically, there are three places where you can provide custom options: the URL you will be testing, Chrome options, and the Lighthouse configuration object. You can see all three of these are parameters in the function for running Lighthouse from the Lighthouse documentation:

    function launchChromeAndRunLighthouse(url, opts, config = null) {
      return chromeLauncher.launch({chromeFlags: opts.chromeFlags}).then(chrome => {
        opts.port = chrome.port;
        return lighthouse(url, opts, config).then(results => {
          return chrome.kill().then(() => results.lhr)
        });
      });
    }

    You can use whatever code you need in order to create these parameters. For example, say you have a site with multiple pages or URLs you would like to test. Maybe you want to run that test in a CI environment as part of your CI tasks, checking all necessary pages each time the task runs. Using this setup, you can use JavaScript to create your URLs and create a loop that will run Lighthouse for each one.

    Any Chrome options you might need can be specified in an object that gets passed to chrome-launcher. In the example from the documentation, the opts object contains an array we’re calling chromeFlags that you can pass to chrome-launcher and a port where you can save the port being used by chrome-launcher and then pass it to Lighthouse.

    Finally, the Lighthouse configuration object allows you to add any Lighthouse-specific options. The Lighthouse package provides a default configuration object that can be used as-is or extended and modified. You can use this object to do a multitude of things, including specifying which Lighthouse test categories you want to test.

    You can use the emulatedFormFactor to specify whether you want the test to run in a mobile or desktop emulator. You can use extraHeaders to add any cookies you might need to use in the browser. For example, a test running only the accessibility category on a desktop emulator that outputs the results as HTML might have a configuration object that looks like this:

    const lighthouseOptions = {
      extends: 'lighthouse:default',
      settings: {
        onlyCategories: ['accessibility'],
        emulatedFormFactor:'desktop',
        output: ['html'],
      },
    }

    This example represents a minimal configuration. There is a lot more you can do. The Lighthouse configuration docs have much more information. They also have a set of sample configuration objects for some more complex implementations.

    Custom Results Reporting

    When running Lighthouse programmatically, you can have the results returned in one or more of three formatted options and — and this is the most exciting piece in my opinion — you can have access to the raw Lighthouse Result (LHR) object.

    HTML, JSON, CSV

    Lighthouse will automatically format the results in three different ways: HTML, JSON, or CSV. These are all pre-configured results based on the basic Lighthouse reporting template, which is what you see if you run a Lighthouse test inside of Chrome DevTools, for example. In the lighthouseOptions configuration object from the previous section, you can see a key for output that contains an array with a single string: html. This specifies that I only want the results returned formatted as HTML. If I wanted the results both as HTML and JSON, that array would look like ['html', 'json'].

    Once Lighthouse has run, it will return a results object that will contain two keys: report and lhr. We’ll talk about the contents of the lhr key in the next section, but the report key contains an array with the results formatted as you have requested. So, for example, if we have requested ['html', 'json'], then results.report[0] will contain our results formatted as HTML and results.report[1] will contain our results formatted as JSON.

    The LHR Object

    Running Lighthouse programmatically also gives you access to a much more flexible results object: the LHR object. This object contains the raw results and some metadata from your Lighthouse run. More complete documentation can be found on the Lighthouse Github repository.

    You can use these results in any number of ways, including creating custom reports and collecting data from multiple runs for analysis.

    Example: Running An Accessibility Test For Mobile And Desktop

    Let’s say that I have a site that loads different components depending on whether the user is using a smaller screen or a larger one, meaning that the HTML for each version of the site will be slightly different. I want to make sure that both versions of the site get a score of 95 on the Lighthouse accessibility tests and that no code gets committed to our main branch that doesn’t meet that standard.

    Note: If you want to see a working example of the code below analyzing the Sparkbox homepage, you can find the repository here.

    I can configure Lighthouse to run the accessibility category twice, providing different configuration objects for each one — one setting the emulatedFormFactor to desktop and one setting it to mobile. An easy way to do this is to create an array with both objects, shown below.

    const lighthouseOptionsArray = [
      {
        extends: 'lighthouse:default',
        settings: {
          onlyCategories: ['accessibility'],
          emulatedFormFactor:'desktop',
          output: ['html', 'json'],
        },
      },
      {
        extends: 'lighthouse:default',
        settings: {
          onlyCategories: ['accessibility'],
          emulatedFormFactor:'mobile',
          output: ['html', 'json'],
        },
      },
    ]

    Then, I can create a function that will loop through this array and run a Lighthouse test for each object found inside the array.

    One thing to note is that it is necessary to introduce a delay between each run, otherwise Chromium can get confused and the runs will error out. In order to do this, I’ve added a wait function that returns a promise when the setTimeout interval has completed.

    function wait(val) {
      return new Promise(resolve => setTimeout(resolve, val));
    }
    
    function launchLighthouse(optionSet, opts, results) {
      return chromeLauncher
        .launch({ chromeFlags: opts.chromeFlags })
        .then(async chrome => {
          opts.port = chrome.port;
          try {
            results = await lighthouse(url, opts, optionSet);
          } catch (e) {
            console.error("lighthouse", e);
          }
          if (results) reportResults(results, runEnvironment, optionSet, chrome);
          await wait(500);
          chrome.kill();
        });
    }
    
    async function runLighthouseAnalysis() {
      let results;
      const opts = {
        chromeFlags: ["--no-sandbox", "--headless"]
      };
      for (const optionSet of lighthouseOptionsArray) {
        console.log("** Starting Lighthouse analysis **");
        await launchLighthouse(optionSet, opts, results);
      }
    }

    In this case, I am sending the results to a reportResults function. From there, I save the results to local files, print results to the console, and send the results to a function that will determine if the tests pass or fail our accessibility threshold.

    async function reportResults(results, runEnvironment, optionSet, chrome) {
      if (results.lhr.runtimeError) {
        return console.error(results.lhr.runtimeError.message);
      }
      await writeLocalFile(results, runEnvironment, optionSet);
      printResultsToTerminal(results.lhr, optionSet);
      return passOrFailA11y(results.lhr, optionSet, chrome);
    }

    For this project, I want to be able to save the JSON results in a specified directory for our CI test runs and the HTML file in a specified directory for our local test runs. The way Lighthouse returns these different types of results is in an array in the order in which they were requested.

    So, in this example, in our lighthouseOptions object, our array asks for HTML first, then JSON. So the report array will contain the HTML-formatted results first and the JSON-formatted results second. The writeToLocalFile function then saves the correct version of the results in a file with a customized name.

    function createFileName(optionSet, fileType) {
      const { emulatedFormFactor } = optionSet.settings;
      const currentTime = new Date().toISOString().slice(0, 16);
      const fileExtension = fileType === 'json' ? 'json' : 'html';
      return ${currentTime}-${emulatedFormFactor}.${fileExtension};
    }
    
    function writeLocalFile(results, runEnvironment, optionSet) {
      if (results.report) {
        const fileType = runEnvironment === 'ci' ? 'json' : 'html';
        const fileName = createFileName(optionSet, fileType);
        fs.mkdirSync('reports/accessibility/', { recursive: true }, error => {
          if (error) console.error('error creating directory', error);
        });
        const printResults = fileType === 'json' ? results.report[1] : results.report[0];
        return write(printResults, fileType, reports/accessibility/${fileName}).catch(error => console.error(error));
      }
      return null;
    }

    I also want to print the results to the terminal as the test runs finish. This provides a quick and easy way to view the results without having to open a file.

    function printResultsToTerminal(results, optionSet) {
      const title = results.categories.accessibility.title;
      const score = results.categories.accessibility.score * 100;
      console.log('n**n');
      console.log(Options: ${optionSet.settings.emulatedFormFactor}n);
      console.log(${title}: ${score});
      console.log('n**');
    }

    And finally, I want to be able to fail my test runs if the accessibility scores do not meet my threshold score of 95.

    function passOrFailA11y(results, optionSet, chrome) {
      const targetA11yScore =  95;
      const { windowSize } = optionSet;
      const accessibilityScore = results.categories.accessibility.score * 100;
      if (accessibilityScore) {
        if (windowSize === 'desktop') {
          if (accessibilityScore < targetA11yScore) {
            console.error(Target accessibility score: ${targetA11yScore}, current accessibility score ${accessibilityScore});
            chrome.kill();
            process.exitCode = 1;
          }
        }
        if (windowSize === 'mobile') {
          if (accessibilityScore < targetA11yScore) {
            console.error(Target accessibility score: ${targetA11yScore}, current accessibility score ${accessibilityScore});
            chrome.kill();
            process.exitCode = 1;
          }
        }
      }
    }

    I invite you all to play around with it and explore all the different ways Lighthouse can help monitor your site quality.

    Final Notes

    While I intentionally kept the example above relatively simple, I hope it gave you a good overview of what can be accomplished when running Lighthouse programmatically. And I hope it inspires you to find new ways to use this flexible, powerful tool.

    As Peter Drucker said:

    “If you can’t measure it, you can’t improve it.”

    Being able to not only measure but monitor our website quality, especially for complex sites, will go a long way towards helping us build a better web.

    Further Reading on SmashingMag:

    • A/B Testing For Mobile-First Experiences
    • How To Test A Design Concept For Effectiveness
    • The Importance Of Manual Accessibility Testing
    • Machine Learning For Front-End Developers With Tensorflow.js
    • Get Started With UI Design With These Tips To Speed Up Your Workflow

    From our sponsors: An Introduction To Running Lighthouse Programmatically

    Posted on 11th September 2020Web Design
    FacebookshareTwittertweetGoogle+share

    Related posts

    Archived
    22nd March 2023
    Archived
    18th March 2023
    Archived
    20th January 2023
    Thumbnail for 25788
    Handling Continuous Integration And Delivery With GitHub Actions
    19th October 2020
    Thumbnail for 25778
    A Monthly Update With New Guides And Community Resources
    19th October 2020
    Thumbnail for 25781
    Supercharge Testing React Applications With Wallaby.js
    19th October 2020
    Latest News
    • Archived
      22nd March 2023
    • Archived
      18th March 2023
    • Archived
      20th January 2023
    • 20201019 ML Brief
      19th October 2020
    • Thumbnail for 25788
      Handling Continuous Integration And Delivery With GitHub Actions
      19th October 2020
    • Thumbnail for 25786
      The Future of CX with Larry Ellison
      19th October 2020
    News Categories
    • Digital Marketing
    • Web Design

    Our services

    Website Design
    Digital Marketing
    SEO
    E-commerce
    Social Media Services
    Website Design
    Website Design

    A website is an important part of any business. Professional website development is an essential element of a successful online business.

    We provide website design services for every type of website imaginable. We supply brochure websites, E-commerce websites, bespoke website design, custom website development and a range of website applications. We love developing websites, come and talk to us about your project and we will tailor make a solution to match your requirements.

    You can contact us by phone, email or send us a request through our online form and we can give you a call back.

    More Information

    Digital Marketing
    Digital Marketing

    Our digital marketeers have years of experience in developing and excuting digital marketing strategies. We can help you promote your business online with the most effective methods to achieve the greatest return for your marketing budget. We offer a full service with includes the following:

    1. Social Media Marketing

    2. Email & Newsletter Advertising

    3. PPC - Pay Per Click

    4. A range of other methods are available

    More Information

    SEO
    SEO Services

    SEO is an essential part of owning an online property. The higher up the search engines that your website appears, the more visitors you will have and therefore the greater the potential for more business and increased profits.

    We offer a range of SEO services and packages. Our packages are very popular due to the expanse of on-page and off-page SEO services that they cover. Contact us to discuss your website and the SEO services that would best suit to increase your websites ranking.

    More Information

    E-commerce
    E-commerce Websites

    E-commerce is a rapidly growing area with sales online increasing year on year. A professional E-commerce store online is essential to increase sales and is a reflection of your business to potential customers. We provide professional E-commerce websites custom built to meet our clients requirements.

    Starting to sell online can be a daunting task and we are here to make that journey as smooth as possible. When you work with Cunningham Web Solutions on your E-commerce website, you will benefit from the experience of our team and every detail from the website design to stock management is carefully planned and designed with you in mind.

    More Information

    Social Media Services
    Social Media Services

    Social Media is becoming an increasingly effective method of marketing online. The opportunities that social media marketing can offer are endless and when managed correctly can bring great benefits to every business.

    Social Media Marketing is a low cost form of advertising that continues to bring a very good ROI for our clients. In conjuction with excellent website development and SEO, social media marketing should be an essential part of every digital marketing strategy.

    We offer Social Media Management packages and we also offer Social Media Training to individuals and to companies. Contact us to find out more.

    More Information

    Cunningham Web Solutions
    © Copyright 2025 | Cunningham Web Solutions
    • Home
    • Our Services
    • FAQ's
    • Account Services
    • Privacy Policy
    • Contact Us