Google Apps Script: WebApp [updated Dec 2021 – With thanks to Greg S]
In this tutorial, we will cover how you can get a unique temporary access key from a user accessing your WebApp that lasts for 30 days.
Temporary access keys allow you to track users as they use your WebApp over time while still providing anonymity to the user by providing only an access key to that user. Rather than, say, use their name or email address.
Why is this important? Well, you might want to limit the number of times a user submits a form on your WebApp. If you can get a user’s access key unique to them then you can store the number of attempts by the user and check it before the data is submitted.
For example, in a previous post, we created a chain story that we might want to limit the number of times our users contribute to our story to once a day.
NOTE! This tutorial is pretty much standalone. However, it will require some basic knowledge of Google Apps Script WebApp and HTML. Don’t worry if some basic setup parts are not covered in this tutorial, I’ll link to how to do these bits if you need some more instruction.
Let’s take a look at what we are going to make:
Table of Contents
The Example
Check out the Google Iframe WebApp below. NOTE! You will be required to sign into your Google Account for this WebApp to run.
In the above iframe of our Google Apps Script WebApp, you can see your unique temporary active user key that will be assigned to you for 30 days.
We’ve stored your key server-side along with the date and time that you first accessed the WebApp. We also make a record of the times you have accessed the WebApp. Either through accessing this tutorial page or directly through the URL. You can see this value changes if you refresh this page, or better yet click this link to the URL below:
https://script.google.com/macros/s/AKfycbxRb8orTieMYTz8X0MVmbsw64dpDwJL-qjQf8uy8JmO/dev
If you bookmark the link and come back to it in a few hours, or tomorrow, you will see that the time valid will change.
Here, take a look at mine. I first accessed the WebApp a little over a day ago:

Let’s take a look at the code.
The Code
Before, I share the code. Let’s quickly go over how it all works.
First of all, this Web App needs to be deployed as:
- Execute the app as: User accessing the web app
- Who has access to the app: anyone

This will allow the user to run the script as themself rather than as me so the script doesn’t dig into my quota limit. More on Google Apps Script Web App permissions here.
When the users open the WebApp, either directly or via an embedded iframe, code is activated server-side (Google Apps Script-side). A unique user key is retrieved.
The user key is then searched for inside Google Apps Script’s Properties Service. Each key is assigned an object of the following keys:
1 2 3 4 5 |
{ date: , timesAccessed: , currentDate: } |
If the key exists, then the access frequency is increased by one and the current date-time is modified to the present. If the user does not exist, then we add the user as a property of the Properties Service, adding the date of the first time that they accessed this WebApp, set the frequency to one and the current date-time to the same as the first time it was accessed.
Next, we use this data to generate HTML that displays the unique ID, the number of times the user accessed the web app and use the start date to work out the remaining days until this current user key expires.
On a daily time-trigger set to a separate function the user can’t access, we check through each user key property each day. If the user’s key has a start date plus 30 days that is less than the current date, then that user will be removed from the Properties Service.
Index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
<!DOCTYPE html> <html> <head> <base target="_top"> <style> #theResult{ max-width: 400px; background-color: #f1f1f1; word-wrap: break-word; border-radius: 5px; padding: 4px; } </style> </head> <body> <div id="theResult"></div> <script> /** Displays error if there is an error on the call to server-side. * run from withFailureHandler. * * @param {string} error - Error warninig. */ function onFailure(error){ let errorTxt = `<em style="color:red">The following error occurred: ${error}</em>` ; document.querySelector("#theResult").innerHTML = errorTxt; }; /** Display returned HTML from server-side. * run from withSuccessHandler. * * @param {string} uniqueID - HTML containing details of unique user key. */ function result(uniqueID){ document.querySelector("#theResult").innerHTML = uniqueID; }; /** Runs on load. *First tests if GAS code is successful, * attempts to run GAS-side function. * on failure sends to onFailure function with nature of error. * on success sends to result function with returned result. */ google.script.run.withFailureHandler(onFailure) .withSuccessHandler(result) .getID(); </script> </body> </html> |
Code.gs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
/**##################################### * Sets up server-side HTML environment */ function doGet(){ return HtmlService.createHtmlOutputFromFile('Index') .addMetaTag('viewport', 'width=device-width, initial-scale=1') .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL); }; /**##################################### * Is initiated when Index.html first loads. * * Checks for stored records of the users. Then collects their user records * HTML containing their unique key the number of time that they have accessed the * web app and how many days and hours are remaning for them before their token * expires. * * @return {string} HTML data. */ function getID(){ const UserProp = createUserProperty(); let key = Object.keys(UserProp)[0]; let prop = UserProp[key]; let timeRemaining = getDaysAndHoursRemaining(prop.date, prop.currentDate, 30); let days = (timeRemaining.days === 1) ? `${timeRemaining.days} day` : `${timeRemaining.days} day`; let hours = (timeRemaining.hrs === 1) ? `${timeRemaining.hrs} hour` : `${timeRemaining.hrs} hours`; const freqText = (prop.timesAccessed === 1) ? `This is the first time you have accessed this webApp` : `You have accessed this webApp ${prop.timesAccessed} times.` //Create text const textOutput = `<p>You have been assigned the unique token: </p> <em>"${key}"</em> <p> ${freqText}</p> <p> Your unique token will stay valid for ${days} ${hours}. <p> <p><em> No other personal data was taken besides an anonymous temporary active user key</em></p>` return textOutput; }; /**##################################### * Collects a unique session key from the current users and * first compares it with current prop service list of keys. * If already exists it updates the current key:value pair. * If it is new, it adds it to the prop service along with the * initial startdate, adds times accessed to 1 and current date * last access. * * @return {object} object of user details. * @return {object.date} Start date of first time key was activated. * @return {object.timesAccessed} Count of times accessed. * @return {object.currentDate} Current date of last accessed. */ function createUserProperty(){ const userSession = Session.getTemporaryActiveUserKey(); let userProperty = {}; //Check if current ID exists: let props = PropertiesService.getScriptProperties(); if(props.getKeys().includes(userSession)){ const currentVals = JSON.parse(props.getProperty(userSession)); userProperty = { date: currentVals.date, timesAccessed: parseInt(currentVals.timesAccessed) +1, currentDate: new Date() }; }else{ userProperty = { date: new Date(), timesAccessed: 1, currentDate: new Date() }; }; let userPropToString = JSON.stringify(userProperty); props.setProperty(userSession, userPropToString); return {[userSession]:userProperty}; }; /**##################################### * The total days and hours remianing of unique user access key. * * @param {date} startDate - the date the key was first given. * @param {date} currentDate - the current date of this access of the WebApp. * @param {number} expiryDays - Number of days unit the unique user key expires. * * @return {object} containing remaining days and hours. * @return {object.days} days remaning. * @return {object.hrs} hours remaining. */ function getDaysAndHoursRemaining(startDate, currentDate, expiryDays){ let start = new Date(startDate); let current = new Date(currentDate); let dateDifference = start.setDate(start.getDate() + expiryDays) - current; let millisecondsPerHour = (60 * 60 * 1000); let millisecondsPerDay = (24 * 60 * 60 * 1000); let daysRemaining = Math.floor(dateDifference/millisecondsPerDay); let millisecondsRemaining = dateDifference % millisecondsPerDay; let hoursRemaining = Math.floor(millisecondsRemaining/millisecondsPerHour); return {days: daysRemaining, hrs: hoursRemaining}; }; |
Admin.gs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
//#################################################################### // THIS CODE IS NOT ACCESSIBLE BY WEBAPP USER IT IS FOR ADMIN ONLY. //#################################################################### /********************************************************************* * Clears all tokens that have reached their 30 day or expirey from * the Properties Service. * * It compares the initial start date plus 30days against the current date. * * This is set to a daily time trigger to review the Properties Serivce * object for any changes. */ function clearExpiredTokens(){ let propServe = PropertiesService.getScriptProperties() let object = propServe.getProperties(); for (const property in object) { let startDate = new Date(JSON.parse(object[property]).date); let expiryDate = new Date(startDate.setDate(startDate.getDate() + 30)); let currentDate = new Date(); if(expiryDate < currentDate){ console.log("Property deleted:", property, object[property]); propServe.deleteProperty(property); }; }; }; /********************************************************************* * Reviews and logs the properties or all user keys in the Properties * Service. */ function checkProperties(){ console.log(PropertiesService.getScriptProperties().getProperties()); }; /********************************************************************* * Deletes all properties in the Properties Service. */ function clearPropService(){ PropertiesService.getScriptProperties().deleteAllProperties() }; |
Code Breakdown
Index.html
The HTML file is pretty basic. There is a little bit of styling you can see at the top of the file just to make the space a little different from the white background. We then have a DIV we’ve cleverly labelled theResult
.
In the code portion of our index file, we have two functions that are run depending on the outcome of our attempt to make a call and run our script server-side.
When the webpage opens, we want to immediately make a call to our getID
function in our Code.gs file server-side. This is done with the google.script.run class. First, we will test for errors with withFailureHander and if there is an error the onFailure()
function is called and an error is reported. If the code works, we run onSuccessHandler, which will call the server-side getID
function and return the results to the Index.html result
function. This, in turn, adds the data from getID
into the DIV of the Index.html.
For a more detailed explanation of this process, check out this post:
Create a basic interactive Web App: Connecting with the server-side…safely.
Code.gs
doget()
1 2 3 4 5 6 7 8 |
/**##################################### * Sets up server-side HTML environment */ function doGet(){ return HtmlService.createHtmlOutputFromFile('Index') .addMetaTag('viewport', 'width=device-width, initial-scale=1') .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL); }; |
A doGet
or postGet
function is a mandatory requirement to run a Google Apps Script web app. Inside this function we call on the HtmlService class to generate and deliver our Index.html file.
getID()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
/**##################################### * Is initiated when Index.html first loads. * * Checks for stored records of the users. Then collects their user records * HTML containing their unique key the number of time that they have accessed the * web app and how many days and hours are remaning for them before their token * expires. * * @return {string} HTML data. */ function getID(){ const UserProp = createUserProperty(); let key = Object.keys(UserProp)[0]; let prop = UserProp[key]; let timeRemaining = getDaysAndHoursRemaining(prop.date, prop.currentDate, 30); let days = (timeRemaining.days === 1) ? `${timeRemaining.days} day` : `${timeRemaining.days} day`; let hours = (timeRemaining.hrs === 1) ? `${timeRemaining.hrs} hour` : `${timeRemaining.hrs} hours`; const freqText = (prop.timesAccessed === 1) ? `This is the first time you have accessed this webApp` : `You have accessed this webApp ${prop.timesAccessed} times.` //Create text const textOutput = `<p>You have been assigned the unique token: </p> <em>"${key}"</em> <p> ${freqText}</p> <p> Your unique token will stay valid for ${days} ${hours}. <p> <p><em> No other personal data was taken besides an anonymous temporary active user key</em></p>` return textOutput; }; |
The getID()
is called from the Index.html client-side when the webpage is first loaded. This is essentially our main working function that will call all our other task functions and finally return back our results client-side.
Get the users key and store it server-side
Our first task is to get our unique user key and save it to our Properties Service. We’ve put this process in a separate function called createUserProperty()
(Line 12). This will return an object with the unique user key as our um…key and then a nested object containing the date of the first time the user accessed the web app with this unique key, how many times they have accessed the app and the date of the last time they accessed the app. It should look a little like this:
1 2 3 4 5 6 7 |
UserProp = { uniqueuserkey: { date: //<<Date time stamp of first time on web app>>, timesAccessed: //<<count of the times accessed>>, currentDate: //<<Date time stamp of current access of web app>> } } |
Next, we want to display the users long alphanumeric key. We can do this by accessing the zeroeth key in the object with the JavaScript Object.keys() method. Line 14
We will also need to get alls the properties of the key so we can do some calculations before sending them back to Index.html to be displayed. We’ll store this in the prop
variable. Line 15
Get the number of days and hours remaining
Our next task is to get the number of days and hours remianing before our user’s current unique key expires. To do this we have created another function getDaysAndHoursRemianing()
which takes 3 arguments:
- The initial date: prop.date
- The current date: prop.currentDate
- The number of days before the key expires: 30 days.
This will then return an object containing the number of days and hours (hrs) remaning. Line 17
Getting our text set up.
Once we have our days and hours we want to put that in a statement. We’ll use two ternary operators to determine if there is a single day or hour we will use the singluar, ‘day’ and ‘hour’, or if there is more than one day or hour, we will add the plural, ‘s’. Lines 18-19
Next, we will grab our times accessed property and check how many times the user has accessed the text. If they have this is their first time, we’ll let them know. Otherwise, we will give them their current count. Line 21
Now that we have our plural and singluar conditions out of the way, we can put all our html text together into our textOutput string. We’ll use the template literal back ticks(
) so that we can easitly add in our variables (
${variable}
). Lines 25-29
Finally, we return the textOutput
client-side to be displayed in the browser.
createUserProperty()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
/**##################################### * Collects a unique session key from the current users and * first compares it with current prop service list of keys. * If already exists it updates the current key:value pair. * If it is new, it adds it to the prop service along with the * initial startdate, adds times accessed to 1 and current date * last access. * * @return {object} object of user details. * @return {object.date} Start date of first time key was activated. * @return {object.timesAccessed} Count of times accessed. * @return {object.currentDate} Current date of last accessed. */ function createUserProperty(){ const userSession = Session.getTemporaryActiveUserKey(); let userProperty = {}; //Check if current ID exists: let props = PropertiesService.getScriptProperties(); if(props.getKeys().includes(userSession)){ const currentVals = JSON.parse(props.getProperty(userSession)); userProperty = { date: currentVals.date, timesAccessed: parseInt(currentVals.timesAccessed) +1, currentDate: new Date() }; }else{ userProperty = { date: new Date(), timesAccessed: 1, currentDate: new Date() }; }; let userPropToString = JSON.stringify(userProperty); props.setProperty(userSession, userPropToString); return {[userSession]:userProperty}; }; |
This function is the main event of this tutorial.
Creating a unique temporary user key
The createUserProperty()
function first grabs a unique temporary user key. It does this by Google Apps Script’s Session class which provides access to the current session information, like the user’s email, the timezone the user is in and their language settings. But the important one for us is that we can get a temporary key for the user that won’t change each time the user logs into their Gmail account and then accesses this webapp.
The getTemporaryActiveUserKey()
method gets a key for the currently active user without reveailing their identity. This key then lasts for this web app for 30 days before it expires. Line 15
For us, this allows us to store user data that we can collect later, say through a time trigger.
If a user already has acquired a key from running the code earlier, then that key will be returned and stored in the userSession
variable.
Storing a record of our user
We need to be able to store our users records somewhere. We can do this with the Properties Service class. This class allows us to store simple key-value object pairs. You can choose how you want your properties service to be scoped:
- To the Script: all properties are specifically accessible by the users of the script.
- To the User: These are specifically to both the script being used, but also exclusive to the current user of the script.
- To the Document: Were the document contains an active add-on. All users of the document can access the properties of this script.
Because we want to keep a record of all of our users in the script we will apply the getScriptProperties()
method. Line 20
You can add, remove and view all or specific properties in your properties service.
A quick headsup – Some limitations
Properties Service is not designed to store large amounts of object data, although it’s not too bad. The current limitations on Properties Service is:
- The value of each property must be less than 9 kilobytes. For reference, our data is barely a handful of bytes.
- The total storage for each property store is 500 kilobytes. This means for this project script properties, we can’t have more than 500kb of property data stored. For another project, thats another 500kb.
- For your enire account, there is a limit of 50,000 reads and writes per day. If you are getting traffic like this, you probably shouldn’t be using Google Apps Script. Have a look a Firebase or something.
Checking if we already have a record of the user
Next, we want to check if we already have a record of the user among our properties.
We titled each of our keys as the unique temporary user key of each user to help make this process easier. First, we call the Google Apps Script getKeys() method to get a list of keys in our Properties Service.
Then, we use the JavaScript includes method on our list of keys. The includes method takes a text item as a parameter. It iterates through each item in the array and checks if the item exists. If it does, then it will return the boolean, True. Otherwise, it will return false.
For us, we want to see if the current userSession
exists in our list of keys. Line 21.
if
(
props
.
getKeys
(
)
.
includes
(
userSession
)
)
{
If the user’s key already exists, then we want to update the current key’s child keys of timesAccessed
and currentDate
. All data stored in a Properties Service value is a text. Specifically, for us, this is a JSON stringified text.
We need to return the values back into an object containing our date
, timesAccessed
and currentDate
. We do this with the JSON.parse() method. The argument for this method is the value of our selected user’s property. We get this value with the getProperty
method which takes a key as an argument. For us, this is the userSession
. Line 22
const
currentVals
=
JSON
.
parse
(
props
.
getProperty
(
userSession
)
)
;
Next, we set up our new inner object in the userPropery
variable we created earlier (Line 23). We reenter the date with the stored date variable (Line 24). Then we add one to the preivous timeAccessed
to keep the count (Line 25). Finally, we update the current date (Line 26).
Adding a new user
If the user doesn’t exists, then we need to add them. We’ll update our userProperty
again. First, we use the new Date() constructor to both the date
and currentDate
keys. Then we set the timeAccessed
to one.
Creating and updating a property
Creating and updating a property is the same thing. If a property with the same key already exists, it will simply overwrite it. So this means that we can use the same method to update and add a property.
Before we add our property we need to convert it to a string. We do this with JSON stringify. Then we apply the setProperty() method to add it to our script properties. Lines 36-37
Finally, we return our updated or new property back to the getID()
function. Line 39
getDaysAndHoursRemaining()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/**##################################### * The total days and hours remianing of unique user access key. * * @param {date} startDate - the date the key was first given. * @param {date} currentDate - the current date of this access of the WebApp. * @param {number} expiryDays - Number of days unit the unique user key expires. * * @return {object} containing remaining days and hours. * @return {object.days} days remaning. * @return {object.hrs} hours remaining. */ function getDaysAndHoursRemaining(startDate, currentDate, expiryDays){ let start = new Date(startDate); let current = new Date(currentDate); let dateDifference = start.setDate(start.getDate() + expiryDays) - current; let millisecondsPerHour = (60 * 60 * 1000); let millisecondsPerDay = (24 * 60 * 60 * 1000); let daysRemaining = Math.floor(dateDifference/millisecondsPerDay); let millisecondsRemaining = dateDifference % millisecondsPerDay; let hoursRemaining = Math.floor(millisecondsRemaining/millisecondsPerHour); return {days: daysRemaining, hrs: hoursRemaining}; }; |
This function determines the number of days and hours remaining until the users unique key expires. It returns an object containing the days and hours remining:
1 2 3 4 |
{ days: hrs: }; |
The getDaysAndHoursRemaining()
function has three parameters:
startDate
: the date when the users first accessed the web app. This is stored in thedate
key of the user’s Properties Service property.currendDate
: The date that the script is currently being accessed.expiryDays
: The number of days that a user’s key will expire. For us, this is set to 30 days to match Google Apps Script max number of days the key will be available for.
First, we need to ensure the start and current dates are readable dates. We do this with the new Date() constructor. Lines 13-14
One line 16, we calculate our remaining days. Using the setDate method to set the day of the startDate
object we want to add our expiryDays
to our current date. Then we subtract this value from our current date. This will return a larger number set or remaining milliseconds.
Next, we work out the number of milliseconds in an hour and in a day and store them both in separate variables. Lines 18-19
Then we determine the number of days rounded down (Math.floor) by dividing the dateDifference
by millisecondsPerDay
. Line 21
We then want to get the leftover milliseconds to calculate the hours remaining. Line 23
Using the remaining milliseconds we use our millisedondsPerDay valuable to calculate the remaining hours, rounded down. Line 24
Finally, we put our days and hours remaining results into our object to be returned back to the getID()
function.
Admin.gs
Perhaps unusually, we have added an Admin.gs Google Apps Script file. The scripts in this folder will not be used by the user or when the Index.html file loads. These will be independent functions.
I’m using this to highlight that you can use your own admin file or section of code to run independent processes and collect the properties data to use in these processes.
We will be using these functions to maintain and get data from our Properties Service.
clearExpiredTokens()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
//#################################################################### // THIS CODE IS NOT ACCESSIBLE BY WEBAPP USER IT IS FOR ADMIN ONLY. //#################################################################### /********************************************************************* * Clears all tokens that have reached their 30 day or expirey from * the Properties Service. * * It compares the initial start date plus 30days against the current date. * * This is set to a daily time trigger to review the Properties Serivce * object for any changes. */ function clearExpiredTokens(){ let propServe = PropertiesService.getScriptProperties() let object = propServe.getProperties(); for (const property in object) { let startDate = new Date(JSON.parse(object[property]).date); let expiryDate = new Date(startDate.setDate(startDate.getDate() + 30)); let currentDate = new Date(); if(expiryDate < currentDate){ console.log("Property deleted:", property, object[property]); propServe.deleteProperty(property); }; }; }; |
One of our main administrative aims for this project is to clear out any user whose unique key tokens has expired from our Properties Service.
The clearExpiredTokens()
function iterates through each stored properties and checks the assigned start date plus 30 days. If this date is less than the current date, the user’s property will be deleted.
First, we call our PropertiesService. Specifically our script properties. Next, we want to grab all the properties that have been stored by our users accessing our WebApp. We do this with the getProperties method. Lines 15-16
We need to loop through all of our object properties to check if they have expired. This is done with our object-specific for-in loop. Line 18
We need to get the start date from each of our properties. Remember that in Properties Service all properties even if they are nested objects, must be strings. We used JSON.stringify on these to turn them into strings when they were added. So to make them objects again, we can use JSON.parse. Once we have the inner objects we can get the value in the date
key. Line 19
Next, we want to create our expiry date we use the new Date constructor again and set the date plus thirty days. Line 20
Then, we get the current date and assign it to our currentDate
variable.
Finally, we check to see if the expiry date is less than the current date. If it is, we record the property in our console for us to check later and then use the deleteProperty method to remove the property completely. Lines 25-29
Setting a trigger to our clearExpiredTokens() function
We don’t want to have to go in each day to run a check of the expired key tokens. Fortunately, we can assign a time trigger to our function. Here is one quick approach to do this:
Our other two little functions
We have two more functions the first one simply gets a list of all of the users who have accessed the WebApp and have tokens. It then logs them in the console for us to review. checkProperties()
The other function clears out all the properties in the script properties with the deleteAllProperties method. This is useful for preparing or updating our code or if we want to reset our list. Just keep in mind that it won’t reset the users key so their expiry count may be a little off. clearPropService()
Conclusion
Storing unique user keys from users accessing a WebApp with Google Apps Script can be a helpful tool for you to collect data on your users to use at another time. This could be used to collect statistics on your users or temporarily store their input for them to call on and edit later in your WebApp.
You might also store form data this way and then run a time trigger to later submit it to your Google Sheets. This way you don’t have to worry about sharing your Google Sheet’s edit permissions publically.
What do you think you would use this approach for? I really like to hear how people implement these tutorials in their own projects. So feel free to share in the comments below. If you like this tutorial give it a like so I know that I should be creating more of these types of tutorials and if you want to get regular updates when my posts come out, why not subscribe (top right sidebar)?
Got a more specific problem you need help with, but donβt have the time to develop the skills? Make an enquiry on my βHire me!β page. I occasionally pick up projects. If I'm unable to right now, I can still help you find a great trusted freelancer.
The code in the common failure function had back leaning single quotes around it???? I switched them to regular single quotes.
result.innerHTML = ‘The following error occurred: ${error}‘
Yes, these are called backticks. They are used in modern Javascript and recently in Google Apps Script V8 runtime to create Template Literals.
This allows us to add a variable reference like,
${error}
. Where that error will read the ‘error’ message generated. Inside, single quotations,${error}
, will not be recognised as a variable.https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
“Execute the app as: User accessing the web app
This will allow us to access the current userβs user key rather than our own if we had executed as the owner.”
it is getEffectiveUser() that is determined by Execute as. getTemporaryActiveUserKey() will return the current userβs user key.
https://developers.google.com/apps-script/reference/base/session?hl=en#geteffectiveuser
Hi Greg,
Yes, fair point and good find. I know better.
The relevant seciton is updated.
~Yagi