Two properties of add-ons make them especially easy to share and use:
- Once you get an add-on from the store, you see it in the Add-ons menu for every document you open or create. Collaborators on those documents won't see the add-on except in documents where you actually use it.
- Once you use an add-on in a document, your collaborators also see it in the Add-ons menu, but just for that document (unless they use it themselves).
We hope this sharing model feels natural for users. However, because an add-on
automatically runs its onOpen(e) function to add menu items when a document
opens, the behavior above adds some complexity to Apps Script's authorization
rules. After all, users wouldn't be comfortable with an add-on accessing
personal data every time they open a document. This guide should help you
understand what your code can do and when.
Installed versus enabled
If you see an add-on in the menu, it's in one (or both) of two states: installed and enabled. An add-on is installed for a particular user after he or she chooses the add-on in the store and authorizes it to access their Google data. By contrast, an add-on is enabled in a given document when anyone uses it there. If two people collaborate on a document, and one of them uses an add-on, it is installed for the one user and enabled for the document.
The table below summarizes the two states. Note that when testing a script as an add-on you can choose to run the test in either or both of these states.
| Installed | Enabled | |
|---|---|---|
| Applies to | User | Document |
| Caused by | Getting an add-on from the store | Getting an add-on from the store while using that document Using a previously installed add-on in that document |
| Menu visible to | Only that user, in all documents they open or create | All collaborators on that document |
onOpen(e) runs in |
AuthMode.NONE (unless also enabled, in which case
AuthMode.LIMITED) |
AuthMode.LIMITED |
Authorization modes
An add-on automatically runs its onOpen(e) function to add menu items when a
document opens — but to protect users' data, Apps Script restricts what the
onOpen(e) function can do. If the add-on hasn't been used in the current
document, these restrictions become more severe.
Specifically, the installed and enabled states determine which authorization
mode the onOpen(e) function runs in. Apps Script passes the authorization mode
as the authMode property of the
event parameter, e; the value of
e.authMode corresponds to a constant in the
ScriptApp.AuthMode enum.
If an add-on is installed for a user but not enabled in the current document,
onOpen(e) runs in AuthMode.NONE; if the add-on is enabled in the current
document, onOpen(e) runs in AuthMode.LIMITED. If the add-on is both
installed and enabled, the enabled state takes precedence, since LIMITED
allows access to more Apps Script services.
Note that only published add-ons can be in AuthMode.NONE;
scripts that are bound to a document,
including add-ons in development, always run onOpen(e) in AuthMode.LIMITED.
You can, however, test a script as an add-on
to verify that an add-on under development will behave as intended in either
AuthMode.
The concept of authorization modes applies to all Apps Script executions — such
as running from the script editor, from a menu item, or from a
google.script.run call — although
the e.authMode property can only be inspected if the script runs as the result
of a trigger like onOpen(e),
onEdit(e) or onInstall(e).
Custom functions in Google Sheets use
their own authorization mode, AuthMode.CUSTOM_FUNCTION, which is similar to
LIMITED but has slightly different restrictions. The rest of the time, scripts
run in AuthMode.FULL, as detailed in the table below.
NONE |
LIMITED |
CUSTOM_FUNCTION |
FULL |
|
|---|---|---|---|---|
| Occurs for | onOpen(e) (if the user has installed an add-on but not enabled it in the document) |
onOpen(e) (all other times)onEdit(e) (only in Sheets) |
Custom functions | All other times, including: installable triggers onInstall(e)google.script.run |
| Access to user data | Locale only | Locale only | Locale only | Yes |
| Access to document | No | Yes | Yes — read-only | Yes |
| Access to user interface | Add menu items | Add menu items Show sidebar |
No | Yes |
Access to Properties |
No | Yes | Yes | Yes |
Access to Jdbc, UrlFetch |
No | No | Yes | Yes |
| Other services | LoggerUtilities |
Any services that don’t access user data | Any services that don’t access user data | All services |
The complete lifecycle
If an add-on is either installed for the current user or enabled in the current
document, the add-on is loaded in the document, which causes it to appear in
the Add-ons menu and start listening for the
simple triggers onInstall(e),
onOpen(e), and onEdit(e). If a user clicks one of the add-on’s menu items,
it runs.
Installing
When an add-on is installed from the store, its onInstall(e) function runs in
AuthMode.FULL. This allows the add-on to run a complex setup routine, but it’s
important to also use onInstall(e) to create menu items, since the document is
already open and thus your onOpen(e) function hasn’t run. For convenience, you
can just call onOpen(e) from onInstall(e), as shown in this sample:
function onInstall(e) {
onOpen(e);
// Perform additional setup as needed.
}
Opening
When a document opens, it loads every add-on that the current user has installed
or that any collaborator has enabled in the document, and calls each of their
onOpen(e) functions. The authorization mode that onOpen(e) runs in depends
on whether an add-on is installed or enabled,
as explained above.
If an add-on only creates a basic menu, the mode doesn’t matter. This sample
shows what a simple onOpen(e) might look like:
function onOpen(e) {
SpreadsheetApp.getUi().createAddonMenu() // Or DocumentApp.
.addItem('Insert chart', 'insertChart')
.addItem('Update charts', 'updateCharts')
.addToUi();
}
However, if you want to add dynamic menu items based on stored
properties, read the contents of the current
document, or perform other advanced tasks, you need to detect the authorization
mode and handle it appropriately. This sample shows what an advanced onOpen(e)
function might look like, changing its behavior based on the authorization mode:
function onOpen(e) {
var menu = SpreadsheetApp.getUi().createAddonMenu(); // Or DocumentApp.
if (e && e.authMode == ScriptApp.AuthMode.NONE) {
// Add a normal menu item (works in all authorization modes).
menu.addItem('Start workflow', 'startWorkflow');
} else {
// Add a menu item based on properties (doesn't work in AuthMode.NONE).
var properties = PropertiesService.getDocumentProperties();
var workflowStarted = properties.getProperty('workflowStarted');
if (workflowStarted) {
menu.addItem('Check workflow status', 'checkWorkflow');
} else {
menu.addItem('Start workflow', 'startWorkflow');
}
}
menu.addToUi();
}
An add-on's onOpen(e) function can also open a sidebar if it executes in
AuthMode.LIMITED. However, if any collaborator on the document has not yet
installed the add-on, the sidebar's
google.script.run calls will fail
for that user, since google.script.run executes in AuthMode.FULL and the
user hasn't granted authorization. In this case, you should handle the failure
and direct the user to install your add-on by clicking on a menu item. (Also,
see the UI style guide's restrictions on
automatically showing a sidebar.)
Running
When someone clicks one of an add-on's menu items, Apps Script first checks to
see whether the user has installed the add-on, and prompts them to do so if not.
If the user has authorized the add-on, the script runs the function that
corresponds to the menu item in AuthMode.FULL. The add-on also becomes enabled
in the document if it wasn’t already.