I'm using the PageSpeed API to pull data using Google Script into Google Sheets.
However, when I execute the script and fetch data from the PageSpeed URL, the time-to-first-byte numeric value is substantially higher than when I run it in my regular browser window.
For example, when I fetch the URL within Google Sheets with the code below, my average Time-to-first-byte is 500-510ms. While if I use the exact same URL in chrome on my desktop, it's generally 60-70ms.
This is the code I use to pull in the data:
function callPageSpeed(strategy) {
var pageSpeedUrl = 'https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=' + pageSpeedMonitorUrl + '&key=' + pageSpeedApiKey + '&strategy=' + strategy;
var response = UrlFetchApp.fetch(pageSpeedUrl);
var json = response.getContentText();
return JSON.parse(json);}
I then push it into my sheet using:
function monitor() {
var desktop = callPageSpeed('desktop');
var mobile = callPageSpeed('mobile');
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spreadsheet.getSheetByName('results');
sheet.appendRow([
Utilities.formatDate(new Date(), 'GMT+1', 'yyyy-MM-dd'),
desktop['lighthouseResult']['audits']['time-to-first-byte']['numericValue'].toFixed(0) + " ms"
//some other metrics go here
]);
Does anybody know what might cause this, and how I can overcome it?
The difference in the time average between your direct Browser execution call and the one in your Apps Script execution is due to Apps Script code runs in Google's servers and not in your local machine as the Docs say:
There's nothing to install—we give you a code editor right in your
browser, and your scripts run on Google's servers.
Take that into consideration when calling external APIs because it can have other side effects, besides time average differences like having an IP address that you can't assign.
Related
I have a google sheets workbook that builds a report based on user input, which is run by clicking a "button" (a square shape on the sheet itself). I want to share this workbook with my team, who need to create a copy of the workbook so they can generate multiple reports for themselves.
However, I also want to be able to make changes to the code at a later date, and avoid having them re-download the latest version, so I'm trying to decentralise the Apps Script file by putting it into my company's shared Google Drive, and then the workbook script replaced by a function that loads that file in the drive.
So far I have:
function getApp(){
var folderId = "<folder_id>";
var fileName = "<file_name>";
var scriptId = "<script_id>";
var folder = DriveApp.getFolderById(folderId);
var files = folder.getFilesByName(fileName);
var url = "https://script.google.com/feeds/download/export?id=" +
scriptId + "&format=json"
var options = {
"method": "GET",
"headers": {
"Authorization": "Bearer " + ScriptApp.getOAuthToken()
},
"muteHttpExceptions": true
};
var response = UrlFetchApp.fetch(url, options);
dataContentAsString = response.getContentText();
fileContents = JSON.parse(dataContentAsString);
var codeFile = fileContents.files[1];
if (codeFile){
var code = codeFile.source;
eval(code);
buildReport();
}
}
Which takes the "file" at index 1 (an object containing all functions in the script) and runs the buildReport function. When I do Logger.log(fileContents) I can see the entire script, so I know the retrieval from google drive is working.
buildReport() is the "main" function, which then calls other functions, however when running it, I get the error below, which indicates an Oauth issue:
Exception: You do not have permission to call
SpreadsheetApp.getActive. Required permissions:
(https://www.googleapis.com/auth/spreadsheets.currentonly ||
https://www.googleapis.com/auth/spreadsheets)
Does this mean that despite being able to access the file, the file itself doesn't have access to the sheets (that contain templates which the script manipulates based on the users initial inputs prior to clicking the button) where the macro is being run from?
Is this the best way to achieve what I want?
Update
I added a trigger to the workbook, which runs buildReport just fine when the spreadsheet is opened (not the desired behaviour, but still at least it's working in some way), however when clicking the "Build Report" button it shows the error still.
Why would the local script (i.e. local to the google sheet) be able to successfully import from google drive and run buildReport() when using a trigger, but not when clicking a button to do the same thing?
If you have an standalone script that will "modify" the user current Spreadsheet (or slides, or...) but the script bounded to the Spreadsheet only "calls" the external script, you can add a dummy/commented line to the bound script, so that when the user runs the bound script, permissions for the standalone script will also be asked. Sorry, for my english :D
Adding this line, anywhere, will do the trick:
//SpreadsheetApp.getActive()
BTW, I found very useful your way to share scripts!
Does Google App Scripts provide an API to determine when a script was executed the last time?
I'm executing a script periodically and I only like to process data which is new since the last execution, thus I'd like to know when my script was executed the last time. But since I execute it not every x min its hard to hardcode this value.
Thanks in advance, I really appreciate your help and expertise.
I believe your goal as follows.
You want to retrieve the last executed time of the functions of Google Apps Script.
You want to achieve this using Google Apps Script.
In this case, I thought that the method of "Method: processes.list" of Google Apps Script API might be able to be used. In order to use this API, please do the following flow.
Usage:
1. Linking Google Cloud Platform Project to Google Apps Script Project.
In this case, at first, it is required to link Google Cloud Platform Project to Google Apps Script Project. For this, you can see the detail flow at this repository
2. Prepare sample script.
Please copy and paste the following script to the script editor of the Google Apps Script project linking to Google Cloud Platform Project.
function myFunction() {
const scriptId = "###"; // Please set the Google Apps Script project.
const url = "https://script.googleapis.com/v1/processes?pageSize=1&userProcessFilter.scriptId=" + scriptId;
const res = UrlFetchApp.fetch(url, {headers: {authorization: "Bearer " + ScriptApp.getOAuthToken()}});
const obj = JSON.parse(res.getContentText());
const lastExecutedProcess = obj.processes[0];
console.log(lastExecutedProcess)
}
In this sample script, the last executed process of the specific Google Apps Script project can be retrieved. For example, you can also retrieve the last executed process of the specific function of the the specific Google Apps Script project.
When an error occurs, please check https://github.com/tanaikech/Linking-Google-Cloud-Platform-Project-to-Google-Apps-Script-Project-for-New-IDE#sample-1. You can see the method for avoiding the error using Apps Script API.
Note:
For example, if you want to retrieve the last executed process of all functions of all Google Apps Script project in your Google Drive, you can also use the following script.
function myFunction2() {
const url = "https://script.googleapis.com/v1/processes?pageSize=1";
const res = UrlFetchApp.fetch(url, {headers: {authorization: "Bearer " + ScriptApp.getOAuthToken()}});
const obj = JSON.parse(res.getContentText());
const lastExecutedProcess = obj.processes[0];
console.log(lastExecutedProcess)
}
In this API, you can also use from outside of Google. So, you can also achieve above using other languages except for Google Apps Script.
References:
Method: processes.list
Linking Google Cloud Platform Project to Google Apps Script Project for New IDE
I think it is more reliable to use the exact time up to which point you processed your data than the script execution time because there could a small but meaningful difference which may result in either not accounting for some time period or double process some time period.
What you should do instead is to store the exact time up to which you processed the data and store that and then read that value again next time your script runs.
There is an Apps Script service to do that called Properties Service. It is a key/value service to store some basic information in different scopes. What you need is the Script properties so that you can share information between two executions. Something like this:
const propService = PropertiesService.getScriptProperties();
const lastExecutionTime = propService.getProperty('last_execution');
if (lastExecutionTime) {
// Script was executed before.
} else {
// Script has never been executed.
}
const currentTime = Date.now();
// Do your work
propService.setProperty('last_execution', currentTime);
may 2022
if you're not using Google Cloud Platform, the easiest solution might be to add this line of code to all scripts
SpreadsheetApp.openById('id of a log file').getSheets()[0].appendRow([arguments.callee.name,new Date()])
you will find in the log not only the last execution time, but all the use of the script concerned
There is a nice GAS script to print a Google sheet in google app script print button
As discussed on the Google Cloud Connect (https://www.cloudconnect.goog/message/77627), we are trying to identify a way to control the margins.
There is also a similar question over on the Google Product Forums at https://productforums.google.com/forum/#!topic/docs/DQxnJwoDn0c
You might find this script useful.
I think that it might answer your question on the margins plus it has a few other helpful settings that you can play with.
function printPdf() {
SpreadsheetApp.flush();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var gid = sheet.getSheetId();
var pdfOpts = '&size=A3&fzr=true&portrait=false&fitw=true&gridlines=false&printtitle=true&sheetnames=true&pagenumbers=true&attachment=false&gid='+gid;
var url = ss.getUrl().replace(/edit$/, '') + 'export?format=pdf' + pdfOpts
var app = UiApp.createApplication().setWidth(300).setHeight(100);
app.setTitle('Your Print Preview is Ready');
var link = app.createAnchor('Open Print Preview', url).setTarget('_new');
app.add(link);
ss.show(app);
}
See also: Printing a sheet to PDF
This was also reported in this thread. I suggest to file a feature request for this.
Your first link uses the UiApp which has been depricated but I think I'd look in the following if you still wish to use it.
var pdfOpts = '&size=A4&fzr=false&portrait=false&fitw=true&gridlines=false&printtitle=false&shee tnames=false&pagenum=UNDEFINED&attachment=false&gid='+gid;
it is (currently) neither possible through App Script API ...nor the Macro Recorder
therefore, I'd suggest to utilize some Chrome extension, alike Automation.
the key-codes to open the page setup dialog and enter the desired values and then proceed to hit the Next button, should be about alike this: <Alt> + F, P, (select margins, then select custom numbers, then select the top margin entry field, that can be reached by <Tab>, <Cursor Down> and <Space>)... and then 0.25", <Tab>, 0.25", <Tab>, 0.25", <Tab>, 0.25" ... <Tab>, <Tab>, <Enter>.
from within a spreadsheet (and not even from within client-side JavaScript), without any browser extension, which can send key-codes, there is no access to these properties - because otherwise scripts could easily mess up custom local printer settings.
I am trying to automate data entry while roaming offline using my Chromebook.
I know that google drive is enabled offline and a standalone script in GAS should in theory do the trick but im not sure how to put the pieces together. So far I have the below code which works perfectly online (gets stuck in "running" offline) and I've got the GAS app installed. Any guidance would be greatly appreciated!
function onOpen() {
var ui = SpreadsheetApp.getUi();
// Or DocumentApp or FormApp.
ui.createMenu('Invoice/Receipt System')
// creates a menu item "Submit Order"
.addItem('Record Invoice', 'menuItem1')
.addToUi();
}
function menuItem1() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var is = ss.getSpreadsheetByName("Template_Invoice");
var lastID = is.getRange("j6");
var nextID = is.getRange("j7");
var lastIDValue = lastID.getValue();
var source = ss.getSpreadsheetByName("Key_Invoice");
// sets the 'Key_DailyInput' Sheet as source
var target = ss.geSpreadsheetByName("DataBase_Invoice");
// sets 'Key_DailyInput' sheet as the target for copying data to.
var sourceData = source.getSheetValues(5,1,source.getLastRow(),15);
// sets range to gather source 'Key_DailyInput' data by finding last row, and Line 5 to Column 15
target.getRange(target.getLastRow()+1, 1, sourceData.length,15).setValues(sourceData);
// finds last row of target 'Orders' and writes to +1 row past last row up to column 15 using setValues of sourceData
// Following simply clears DailyInput so new data can be entered
is.getRange('C5:c8').clearContent();
is.getRange('G7:G8').clearContent();
is.getRange('B12:h28').clearContent();
is.getRange('b31:b34').clearContent();
// increases value by +1 so next Sales Order ID is incremented by 1
var cell = is.getRange("j6");
var cellValue = cell.getValue();
cell.setValue(cellValue + 1);
nextID.setValue(lastIDValue + 1);
}
As stated in other responses, the answer appears to be 'No'. However, while researching I did find the Command Line Interface for Apps Script (clasp) to manage and edit your projects offline. I'll post it here hoping it will be helpful to Apps Script developers.
CLASP Features
Develop Locally. clasp lets you write code on your own computer and upload it to Apps Script via command line when you're done. You can also download existing Apps Script projects and then edit them locally. Once the code is local, you can use your favorite development tools like git to work on Apps Script projects.
* Manage Deployment Versions.
* Create, update, and view multiple deployments of your project.
* Structure Code. clasp automatically converts your flat project on script.google.com into folders.
You can find more information on clasp at https://developers.google.com/apps-script/guides/clasp. However, you'll also need to activate the Linux(beta) on your Chromebook utilizing these instructions.
Short answer
Google Apps Script can't be ran offline because they run on the server-side.
Explanation
From https://developers.google.com/apps-script/overview
Google Apps Script is a scripting language based on JavaScript that
lets you do new and cool things with Google Apps like Docs, Sheets,
and Forms. There's nothing to install — we give you a code editor
right in your browser, and your scripts run on Google's servers.
I am trying to write a very basic custom function for my google docs spreadsheet. I have a column in the spreadsheet that lists every day of the year. It's a simple function that should scroll to 'today' in the date column.
However, when I try to run the query, I get an error "google is not defined".
function gotoToday() {
var now = new Date();
var now = Utilities.formatDate(now, "EST", "M/d/yyyy");
var file = SpreadsheetApp.getActiveSpreadsheet();
var sheet = file.getActiveSheet();
var query = new google.visualization.Query(sheet);
query.setQuery('select A WHERE A= '&now);
query.send(handleQueryResponse);
function handleQueryResponse(response) {
Browser.msgBox(response);
var row = day+4;
file.setActiveCell(sheet.getRange(row,1));
}
};
It's dying at the new google.visualization.Query line, saying gooogle isn't defined.
Shouldn't I get those objects for free? Since it is being run in Google Docs, I can't load the jsapi via a script tag. I thought it should just be there. All the other code samples use this same method and the docs don't say anything about other scripts needing to be loaded.
Any ideas would be appreciated!
Thanks,
D
In addition to standard Javascript objects, APIs for many of google's offerings are provided as Services. You don't need to load other scripts to access the Script Services.
The visualization library is represented in Google Apps Script via the Charts Service. The GMail Stats tutorial is one of several that introduces use of the service.
All the other code samples use this same method...
Client-side Javascript samples can do that. No Google Apps Script example does.