Has Google pagespeed v5 removed screenshot support?

Viewed 1742

Google Pagespeed v4 worked using "screenshot" to archive our newspaper website daily, until Wednesday this week. I can find no information if they removed support for 'field=screenshot' but it no longer returns JSON. Is there a new method to capture screenshot, or is it gone?

private function capture_thumbnail(){
        if(false === $data = file_get_contents('https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=' . $this->url . '&filter_third_party_resources=true&screenshot=true&strategy=desktop&fields=screenshot&key=' . $this->google_server_api_key))
            throw new Exception('Could not get url contents');
        $data = json_decode($data, true);
        if(empty($data['screenshot']['data']))
            throw new Exception('Screenshot data empty');
        $image = str_replace(
            array('_', '-'),
            array('/', '+'),
            $data['screenshot']['data']
        );
        $dir = SCREENSHOTS_DIR . date(CAPTURE_DIR_DATE_FORMAT) . '/';
        if(false === file_exists($dir)){
            if(false === mkdir($dir))
                throw new Exception('Could not create screenshot directory');
        }
        if(false === file_put_contents($dir . date('H') . '.jpg', base64_decode($image)))
            throw new Exception('Could not save image');
    }   

}
2 Answers

The screenshots can be accessed in two ways.

Final Screenshot

If you just want the final screenshot it is $data['lighthouseResult']['audits']['final-screenshot'].

I have included the relevant JSON below, you can see it is located within the 'final-screenshot' as ['details']['data'].

"final-screenshot": {
        "id": "final-screenshot",
        "title": "Final Screenshot",
        "description": "The last screenshot captured of the pageload.",
        "score": null,
        "scoreDisplayMode": "informative",
        "details": {
          "timing": 1396,
          "timestamp": 1155417931434,
          "data": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAA...etc...==",
          "type": "screenshot"
        }
      },

Timeline screenshots / filmstrip to show loading progress

If you want the thumbnails to show the loading progress it is $data['lighthouseResult']['audits']['screenshot-thumbnails']

I have yet again included the relevant JSON data so you can see how it is structured, but I will leave that to you to decode that.

"screenshot-thumbnails": {
        "id": "screenshot-thumbnails",
        "title": "Screenshot Thumbnails",
        "description": "This is what the load of your site looked like.",
        "score": null,
        "scoreDisplayMode": "informative",
        "details": {
          "type": "filmstrip",
          "items": [
            {
              "timing": 300,
              "timestamp": 1155416835809,
              "data": "data:image/jpeg;base64,/9j/4AAQSkZJ..etc.."
            },
            {
              "timestamp": 1155417135809,
              "data": "data:image/jpeg;base64,/9j/4AAQSkZJdsAPmRx/xKrPgA...etc...RLP//Z",
              "timing": 600
            },
            {
              "timestamp": 1155417435809,
              "data": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQ...etc...XItzzvtHoujj/iVWfAAMKHA9SOa9GPwoyl8TLbnAqiWf//Z",
              "timing": 900
            },
            {
              "timing": 1200,
              "timestamp": 1155417735809,
              "data": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQA...etc....qiWf//Z"
            },
            {
              "timestamp": 1155418035809,
              "data": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD...etc...sIbgvYpnjchJuJieTvPP41yLc877R6Lo4/4lVnwADChwPUjmvRj8KMpfEy25wKoln//2Q==",
              "timing": 1500
            },
            {
              "timing": 1800,
              "timestamp": 1155418335809,
              "data": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQA...etc....ADChwPUjmvRj8KMpfEy25wKoln//2Q=="
            },
            {
              "timing": 2100,
              "timestamp": 1155418635809,
              "data": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQA...etc...vPP41yLc877R6Lo4/4lVnwADChwPUjmvRj8KMpfEy25wKoln//2Q=="
            },
            {
              "timing": 2400,
              "timestamp": 1155418935809,
              "data": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQA...etc...Ey25wKoln//2Q=="
            },
            {
              "timing": 2700,
              "timestamp": 1155419235809,
              "data": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQA...etc...6Lo4/4lVnwADChwPUjmvRj8KMpfEy25wKoln//2Q=="
            },
            {
              "timing": 3000,
              "timestamp": 1155419535809,
              "data": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAchJ...etc...VnwADChwPUjmvRj8KMpfEy25wKoln//2Q=="
            }
          ],
          "scale": 3000
        }
      },

Hey for anyone who was using this trick on v4 and doesn't want to deal with v5 (ex: screenshot quality is super low), check out thum.io. Took me 10 minutes to rework my script to work with it + is free up to 1000 screenshots a month.

Quick tip: use /noanimate/ in the API url. For reference, here is my script:

function stockDatabasePDF_v2() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName('stock db');
  var date = new Date();
  
  var fid = 'enter-your-fid';
  var folder = DriveApp.getFolderById(fid);
  var apiKey = "where-your-api-key-goes";
  
  //get your data 
  // get lastrow of data in column A
  var lastRow = sheet.getLastRow();
  var data = sheet.getRange(2, 1, lastRow, 1).getValues();
  //var data = sheet.getRange('A2:A').getValues(); //these are your URLs to check
  
  // Get values in Column B to help get restart row
  var data2 = sheet.getRange(2, 4, lastRow, 1).getValues(); //this is where your screenshots are saved
  //var data2 = range.getValues();
  
  // For Timed Trigger
  // There is still time to execute at the start
  var stillTime = true;
  
  // Start time of execution
  var startTime = new Date();
  // loop counter
  var i = 0;
  
  // Main loop
  // Run till you run out of time or rows to process
  while (stillTime && i < data.length) {   
    //for ( var i = 0; i < data2.length; i++ ) {
    //this means if your data (screenshot URLs) are NOT blank
    // and Link to Screenshot is not already created
    if ( data[i][0] !=="" && data2[i][0] == ""   ) { 
      // and Col B is not already populated
      
      var siteUrl = data[i][0];
      var fileName = siteUrl + " - " + date; // You may format the date
      var errorRange = sheet.getRange(i+2,6);
      
      var url = "https://image.thum.io/get/auth/"+apiKey+"/noanimate/"+siteUrl+"";
      
      var serverResponse = fetchlink(url); //note this checks the http response code before running
      
      if ( serverResponse == 200 ) {
        try {
          
          var res = UrlFetchApp.fetch(url);
          var blob = res.getBlob();
          blob.setName(fileName);
          
          var screenshotUrl = folder.createFile(blob).getUrl();
          
          //save that URL back into the sheet
          sheet.getRange(i+2,4).setValue(screenshotUrl); //you add 2 here to account for your header row
          sheet.getRange(i+2,5).setValue(date); //add your date to col E
          Logger.log(i + ":" + screenshotUrl);
          
          if ( errorRange.getValue() == "" ) {}
          else { errorRange.clearContents(); }
          
        }
        
        catch(e) {
          errorRange.setValue(e);  
        }
        
      } // End if #2
      
      else { errorRange.setValue("Skipped - bad server response"); }
      
    } // Ends if #1
    
    // There is still time if elapsed time is less than the set limit
    stillTime = (secondsElapsed(startTime) < TimeLimit);
    // Increment the counter to go to the next row
    i++;
  } // End Loop
  
} // End Function
Related