I am trying to automate a google spreadsheet on google script editor. However, when I try to identify the spreadsheet and select as the one that we are working on, it is written in the documentation cited below (openById) that scripts that use this method require authorization with one or more of the following scopes:
--> https://www.googleapis.com/auth/spreadsheets.currentonly
--> https://www.googleapis.com/auth/spreadsheets
When I add these scopes, my function doesn't run. It only runs when those scopes are not added. Either way, I am met with the error msg that reads: "We are sorry, a server error occurred. Please wait a bit and try again."
https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app#openbyidid
I tried various methods include OpenByUrl and getActiveSpreadsheet...
function automatedInvoiceEmailing() {
var people = [];
// selecting the spreadsheet (without the bottom line, the function works just fine)
var ss = SpreadsheetApp.openById("1jdn3S1Iv2zDAqF6Hyy3fybKARZJYmg-LJVdUWJJS3LA");
}
Either way, I am met with the error msg that reads: "We are sorry, a server error occurred. Please wait a bit and try again."
I expected the sheet to have been selected
Edit: hmm, when I copied the google sheets and saved the new code, it runs properly!! :)
Since you are working with a bounded script (bound to the sheet you’re working with), the way to get a reference to the sheet is with var ss = SpreadsheetApp.getActiveSheet();, this will provide a reference to the bound document. You would use openById() to access another file.
As for scopes, they are added automatically when you run the script for the first time, it will ask for your permission to access your data, and when you accept, google adds them to the script project automatically.
Here are some quick-start examples on working with sheets and apps script
Related
I am trying to use the Google Sheets API. The problem is, once I call my script function on the google spreadsheet, I get the following error:
API call to sheets.spreadsheets.values.get failed with error: The request is missing a valid API key. (line 5).
where line 5 in the script looks like this:
var values = Sheets.Spreadsheets.Values.get(spreadsheetId, rangeName).values;
and spreadsheetId and rangeName are defined in the first lines.
I think the problem might be that I did not copy the API key anywhere, but I really do not understand where and how I can do it.
I call the function just using = function().
When you use Sheets API by a custom function like =myFunction() put to a cell, such error occurs. When the custom function is run, ScriptApp.getOAuthToken() returns null. I think that this is the mainly reason of your issue. And unfortunately, I think that this is the specification. In order to avoid this issue, I would like to propose 2 workarounds.
Workaround 1:
A part of Spreadsheet Services can be used at the custom function. So using this, it obtains the same result with var values = Sheets.Spreadsheets.Values.get(spreadsheetId, rangeName).values;. In the case of your script, openById() cannot be used. So the script is as follows.
Sample script:
function customFunc() {
var rangeName = "#####"; // Please set this.
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var values = sheet.getRange(rangeName).getValues();
return values;
}
Workaround 2:
If you want to use Sheets API, the access token is required. But it is required to directly request to the endpoint of Sheets API, because the access token is automatically used in internal at Advanced Google Services. As an issue of this case, there is that when ScriptApp.getOAuthToken() is run in the custom function, null is returned. In order to avoid this, as a method, the access token is directly given to the custom function using PropertiesService. The sample flow is as follows.
When the Spreadsheet is opened, it puts the access token to PropertiesService by the OnOpen trigger.
When you use this, please install the OnOpen trigger to onOpenFunc() in the sample script.
When the custom function is run, the access token retrieved by PropertiesService is used for using Sheets API.
By this, Sheets API can be used in the custom function.
Sample script:
// Please install OnOpen trigger to this function.
function onOpenFunc() {
PropertiesService.getScriptProperties().setProperty("accessToken", ScriptApp.getOAuthToken());
}
function customFunc() {
var spreadsheetId = "#####"; // Please set this.
var rangeName = "#####"; // Please set this.
var accessToken = PropertiesService.getScriptProperties().getProperty("accessToken");
var url = "https://sheets.googleapis.com/v4/spreadsheets/" + spreadsheetId + "/values/" + rangeName;
var res = UrlFetchApp.fetch(url, {headers: {"Authorization": "Bearer " + accessToken}});
var obj = JSON.parse(res.getContentText());
var values = obj.values;
return values;
}
The expilation time of access token is 1 hour. In this sample script, PropertiesService is used. In this case, when 1 hour is spent after the Spreadsheet was opened, the access token cannot be used. If you want to use continuously the access token, you can also update it using the time-driven trigger.
Note:
When you use Sheets API, please enable Sheets API at API console.
References:
Custom Functions in Google Sheets
spreadsheets.values.get
PropertiesService
If these workarounds were not what you want, I apologize.
I want to thank you, #Tanaike, for your response (I don't have enough 'points' to upvote or comment, so my only option is an 'Answer')
I know this thread is several years old, but I thought others might be interested in my personal experience.
First of all: "Workaround 1" worked for me!
The function/method "Sheets.Spreadsheets.Values.get(spreadsheetID, RangeName).values" was giving me an "missing a valid API key" error, so I swapped it for "sheet.getRange(RangeName).getValues()".
Most of the above was set as Global Variables, i.e. outside of any functions.
Weird thing was that this error occured only when running from within the [container] sheet, not from the "embedded" script.
For instance: If I had an active onOpen() function, and I opened/refreshed the Sheet, the script would log a "The request is missing a valid API key." error, and the UI/Menu I had built therein would not load.
I could, however run the onOpen() function from within the script itself, and the menu would appear, and function, within the Sheet. If I disabled/renamed the onOpen() function, and reloaded the Sheet, I would not get the error message.
Makes sense, as the simple loading of the Sheet does not appear to run the script, but when one does access it (the script), i.e. through the onOpen() function, then the initial global variables are read (and the error occurs).
However, when I ran the same function, or others, from within the script itself, they would run ok. This permissions conundrum is what has led me on a wild goose chase all over the Internet, ultimately landing here.
All this after numerous other issues, in the course of whose resolution I built a Google Cloud Project, added APIs (e.g. for Sheets), added scopes to the oauthScopes section of the manifest, and more.
It was only after I made the replacements described above that everything worked, both from the script, and its container spreadsheet! So, THANKS!
Anyway... Sorry for the long post, but I hope others may benefit from your solution, and in which context it helped me.
Cheers,
-Paul
Some quick background - I'm not overly familiar with javascript or the implementation that seems to exist for use with Google Scripts, so please explain any suggested solutions clearly.
Anyway, I'm having an issue where my script cannot find the getSheetByName function. Now, this specifically occurs when I run it from my spreadsheet, but not from the script editor.
The section of code that throws the error is as follows (and no, I'm unable to share the specific sheet due to security policies):
function Refresh_materials() {
//Calls sheets, ranges, and last rows for later use
var ss = SpreadsheetApp.getActiveSpreadsheet();
Logger.log(ss);
var Materials = ss.getSheetByName("Materials");
Logger.log(Materials.getIndex());
When in a spreadsheet, my script errors out at line 5, with the aforementioned issue. However, when I access the log or the execution viewables within the script editor, everything proceeds smoothly, and no error is throw. The log returns in this example:
[17-06-14 08:50:45:848 PDT] Spreadsheet
[17-06-14 08:50:45:952 PDT] 7.0
This is exactly what I would expect, as the sheet "Materials" is located at Index 7.
Seems to work great in the script editor, but consistently fails within the spreadsheet. I read up on an instance where a similar issue was only for a local user, and evidently disappeared given time.
Is there something incorrect with my script, or is there some other issue in play?
Thanks for the feedback.
-KS
I'm trying to write a script that moves a range of data from one spreadsheet to another. I'm running into a permission issue when I try to open the destination spreadsheet, I keep getting the error "You do not have permission to call open." I've tried open(file), openByUrl(url), and openById(id), and all three methods raise that same error.
I am the owner of the destination spreadsheet, so I don't understand why I don't have permission. I am also the owner of the script, and I have read/write access to the source spreadsheet (although I am not the owner).
Thanks for your help.
Here's my code:
function moveData() {
var source = SpreadsheetApp.getActiveSheet();
var destination = SpreadsheetApp.openById("1kfELXf9WxcZGsUO0piCjEXC_-ZR57GvbFzx1UPw89K4");
...
}
Unfortunately this behaviour is prohibited by Google: Following an update to Apps Script rolled out last June, custom functions are permitted to read data only from the current spreadsheet.
Their recommendation is to use the IMPORTRANGE formula instead.
Problem: When I run the script, Google tells me,
You do not have permission to call openById
I had copied a script from another one of my Google spreadsheets and changed the target_ssKey variable's cell reference and created properly-sized Named Ranges in both the Source and Target spreadsheets.
Google Apps Script documentation says nothing about reasons why it might not be working:
https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app#openById%28String%29
Another Google Apps Script documentation says that it should work for me because I invoke it from a custom menu:
https://developers.google.com/apps-script/guides/sheets/functions#using_apps_script_services
The second link above says:
If your custom function throws the error message You do not have
permission to call X service., the service requires user authorization
and thus cannot be used in a custom function.
To use a service other than those listed above, create a custom menu
that runs an Apps Script function instead of writing a custom
function. A function that is triggered from a menu will ask the user
for authorization if necessary and can consequently use all Apps
Script services.
I tried putting the function into a "Custom Functions" project and then into an "Add-on" project, but still got the same error message.
Any ideas on what I am doing wrong and how to make this work?
Here is my exact code:
function exportData_SStoSS() {
// Get the source data.
var source_ss = SpreadsheetApp.getActiveSpreadsheet();
var data = source_ss.getRangeByName("exportData").getValues();
// Identify the target.
var controls_sh = source_ss.getSheetByName("Controls");
var target_ssKey = controls_sh.getRange('C2').getValue();
var target_ss = SpreadsheetApp.openById(target_ssKey);
// Paste the data to the target.
target_ss.getRangeByName("importData").setValues(data);
};
I thought that I would throw in a similar issue that I had which brought me to this question, where I received the error You don't have permission to call by openById.
In my case I was trying to call functions from translate.gs which I copied from this example:
https://developers.google.com/apps-script/quickstart/docs
Note that at the top of translate.gs
/**
* #OnlyCurrentDoc
*
* The above comment directs Apps Script to limit the scope of file
* access for this add-on. It specifies that this add-on will only
* attempt to read or modify the files in which the add-on is used,
* and not all of the user's files. The authorization request message
* presented to users will reflect this limited scope.
*/
The culprit here is the #OnlyCurrentDoc comment. See here for reference:
https://developers.google.com/apps-script/guides/services/authorization
Removing #OnlyCurrentDoc fixed this issue for me
I could resolved this issue with this autorization guide of google developers.
https://developers.google.com/apps-script/concepts/scopes#setting_explicit_scopes
This entry It's necesary in json file.
"oauthScopes": [
"https://www.googleapis.com/auth/spreadsheets.readonly",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/spreadsheets"
],
I found this official note which I believe clears up what caused the issue.
If your function is a custom function, that is one which can be used like a regular spreadsheet function in the sheet itself, then it has limited access to things and cannot open other spreadsheets.
The same script can however open other spreadsheets from a menu button or similar.
Link: Documentation at developers.google.com
The method openById can be called from a "Blank Project" but not a "Custom Functions in Sheets" nor a "Google Sheets Add-on" project.
I thought a "Blank Project" would create a project that was not connected to my spreadsheet, but I was wrong. The Blank Project is connected to my spreadsheet. The other types of projects that I tried to use seem to be limited-scope versions of script projects, not able to carry out some GAS methods.
Had this same issue and came to share my solution. In my case I had two spreadsheets, call them A and B. Both used scripts bound to each respective spreadsheet. Spreadsheet B was able to write data to a tab of spreadsheet A. But Spreadsheet A kept getting the "You do not have permission to call openById" error when trying to read from spreadsheet B. I then tried adding it as a custom menu item but still the same issue.
The solution in my case turned out to be really simple. I created a new unbound script in script.google.com that calls both spreadsheets using openById. The first time running put a smile on my face as it asked for authorization. Thereafter smooth sailing.
When I create an Apps Script library that accesses a spreadsheet and use it in a script then I get a permission error (for setValue in the following example).
If I call the same spreadsheet function in the script once (and then remove it) and then call the library function I will never get the permission error again (It's reproducible).
Have you ever experienced such behavior and if yes how did you solve this problem?
Thanks
The library
function addRecord(ss, sheetName) {
var sheet = ss.getSheetByName(sheetName);
sheet.getRange("A1:A1").setValue("Hello World!");
}
The script
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
MyLib.addRecord(ss, "Sheet1");
}
The error message
"You don’t have the required permission to call setValue"
Your script must have the same authorizations than the libraries need to have : if you know that the library reads/writes a spreadsheet or a calendar (or whatever) you have to authorize the script for these services.
You can do that quite easily with some (even dummy ) function that will tell the system to call the authorization process for the required services. From what you describe I guess the system doesn't check what is inside the library when you save you script so it's kind of a 'surprise' for the script to write to the spreadsheet without authorization. If you include the (dummy) calls I mentioned before the script will know what you are going to do and ask for authorization on the first run attempt.
Hoping I'm clear enough.
To close this - the issue reported by Stefan has been confirmed as an issue. We are looking into this. Permissions to a passed in spreadsheet are not being correctly absorbed by a library.
Stefan - please feel free to create a report on issue tracker if you prefer.