Our MS Word and PDF tokens are a great way to see if anyone is snooping through your documents. One simply places the document in an enticing location and waits. If the document is opened, a notification (containing useful information about the viewer) is sent to you. Both MS Word tokens and PDF tokens work by embedding a link to a resource in the tokened document. When the document is opened an attempt to fetch the resource is made. This is the request which tickles the token-server, which leads to you being notified.
Because so many of us store content on Google Drive we wanted to do something similar with Google Documents and Google Sheets. Using the embedded image approach was possible in Google Sheets, however, due to image caching coupled with weak API support for Google Documents we turned to Google Apps Script.
The Apps Script files can be published in three different ways.
- The script may be bound to a document (this is the approach we followed);
- It may be published as a Chrome extension;
- It may be published to be used by the Google Execution API (the Execution API basically allows you to create ones own API endpoints to be used by a client application).
With the script bound to a document, the Apps Script features most important for our purposes are: Triggers, the UrlFetchApp service, and the Session service. A brief outline of the flow is:
- A user opens the document,
- A trigger is fired which grabs the perpetrator’s email address;
- This is sent via a request notification to the document owner.
A more detailed outline of each feature is given bellow.
Apps Script triggers come in two flavours: simple and installable. The main difference between the two is the number of services they’re allowed to access. Many services require user authorisation before giving the app access to a user’s data. Each flavour also has separate types. For example: “on open”, “on edit”, “on install”, even timed triggers. For our purposes the “on open” installable triggers proved most useful.
This service simply gives one’s script the ability to make HTTP requests. This service was used to send the requests needed to notify the document owner that the token’d document had been opened. Useful information about the document viewer may also be sent as the payload of a POST request.
The Session service provides access to session information, such as the user’s email address and language setting. This was used to see exactly which user opened the document.
Putting it all together
So, what does this all look like? Let’s go ahead and open up a new Google sheet and navigate to the Script editor.
Once in the Script editor create a new function named whatever you like (in our case it is called “notify”). Here a payload object is constructed which contains the email address of the document owner, the email address of the document viewer and the document viewer’s locale. This information is then sent to an endpoint. Here we use hookbin for convenience.
Once the file has been saved and our notify function is solid, we can go ahead and add the “on open” trigger. To do this: open the Edit tab dropdown from the script editor and go to “Current project’s triggers”.
Under the current project’s triggers add an “On open” trigger to the notify function. This trigger will cause the “notify” function to run each time the document is opened.
Because the function is accessing user data (the Session service) as well as connecting to an external service (sending requests to Hookbin) the script will require a set of permissions to be accepted before being run.
Once the permissions have been accepted all that remains is for the document to be shared. You can share the document with specific people or anyone on the internet. The only caveat being that the document needs to be shared with EDIT permissions or else the script will not function correctly.
Every time the document is opened post requests will be sent to the endpoint. Below is an example of the contents of the POST request sent to Hookbin.
We ran into a few limitations while investigating the use of Apps Script for tokens. While copying a document as another Google user would also copy the script bound to the document, it would not copy the triggers if any had been previously installed. Thus, the user with which the document was shared would need to manually add the triggers to the copied document. Another limitation was that anyone viewing the document needed to have EDIT permissions in order for the script to work correctly. This could prove problematic if the person viewing the document decided to delete/edit the script and/or document.We overcame this, through some creativity and elbow grease..
Thanks for reading. The methods described here were used in our new Google Docs/Sheets Canarytokens for our Canary product, you should totally check them out! We hope you found this useful and that you’ll come up with some other cool new ways to use Google Apps Script!