Page Summary
-
Universal actions are menu items that provide consistent access to specific functions like opening web pages, displaying UI cards, or running Apps Script functions, appearing on every card within a Google Workspace add-on.
-
These actions are defined in the add-on's manifest file and can be configured to either open a link directly or execute a specified Apps Script function when selected.
-
When a universal action triggers a function, it can build and display UI cards, open a URL, or perform background tasks without altering the user interface.
-
Universal actions are beneficial for providing users with essential functionalities, like settings, help, or initiating workflows, regardless of their current location within the add-on.
Universal actions are menu items that let you open a web page, display UI cards, or run an Apps Script function. They're similar to card actions , but universal actions appear on every card in the add-on, regardless of context.
Use universal actions to ensure that users always have access to certain functionality. Example uses for universal actions include:
- Open a settings web page or display a settings card.
- Show help information.
- Start a new workflow, such as 'Add new customer'.
- Display a card to send feedback about the add-on.
If an action doesn't depend on the current context, consider making it a universal action.
Use universal actions
Configure universal actions in the add-on's manifest . After you configure a universal action, it's always available to users. If a user views a card, the universal actions appear in the card menu ( ) after any card actions . Universal actions appear in the menu in the order they're defined in the manifest.
Configure universal actions
Configure universal actions in the add-on's manifest. See Manifests .
For each action, specify the text that appears in the menu. You can specify an openLink
field to open a web page in a new tab. Alternatively, specify a runFunction
field to call an Apps Script callback function
when the user selects the action.
When you use runFunction
, the callback function usually does one of the
following:
- Builds UI cards to display immediately by returning a
UniversalActionResponseobject. - Opens a URL, perhaps after other tasks, by returning a
UniversalActionResponseobject. - Conducts background tasks that don't switch cards or open a URL. In this case, the callback function returns nothing.
The application passes the callback function an event object with information about the open card and add-on context.
Example
The following snippet shows an example manifest excerpt for an add-on that uses universal actions while extending Gmail. The code sets a metadata scope so that the add-on can determine who sent the open message.
"oauthScopes"
:
[
"https://www.googleapis.com/auth/gmail.addons.current.message.metadata"
],
"addOns"
:
{
"common"
:
{
"name"
:
"Universal Actions Only Addon"
,
"logoUrl"
:
"https://www.example.com/hosted/images/2x/my-icon.png"
,
"openLinkUrlPrefixes"
:
[
"https://www.google.com"
,
"https://www.example.com/urlbase"
],
"universalActions"
:
[{
"label"
:
"Open google.com"
,
"openLink"
:
"https://www.google.com"
},
{
"label"
:
"Open contact URL"
,
"runFunction"
:
"openContactURL"
},
{
"label"
:
"Open settings"
,
"runFunction"
:
"createSettingsResponse"
},
{
"label"
:
"Run background sync"
,
"runFunction"
:
"runBackgroundSync"
}],
...
},
"gmail"
:
{
"contextualTriggers"
:
[
{
"unconditional"
:
{},
"onTriggerFunction"
:
"getContextualAddOn"
}
]
},
...
},
...
The universal actions in the example do the following:
- Open google.comopens google.com in a new tab.
- Open contact URLruns a function that determines which URL to open and
opens it in a new tab using an
OpenLinkobject. The code builds the URL using the sender's email address. - Open settingsruns the
createSettingsCardsfunction. This function returns aUniversalActionResponsewith cards for settings and other information. The UI displays the list of cards. See Return multiple cards . - Run background syncruns the
runBackgroundSyncfunction. This function doesn't build cards; instead, it performs background tasks. Because the function doesn't return aUniversalActionResponse, the UI doesn't display a new card. Instead, the UI displays a loading indicator while the function runs.
Here is an example of how you might construct the openContactURL
, createSettingsResponse
, and runBackgroundSync
functions:
/**
* Open a contact URL.
* @param {Object} e an event object
* @return {UniversalActionResponse}
*/
function
openContactURL
(
e
)
{
// Activate temporary Gmail scopes, in this case so that the
// open message metadata can be read.
var
accessToken
=
e
.
gmail
.
accessToken
;
GmailApp
.
setCurrentMessageAccessToken
(
accessToken
);
// Build URL to open based on a base URL and the sender's email.
// This URL must be included in the openLinkUrlPrefixes whitelist.
var
messageId
=
e
.
gmail
.
messageId
;
var
message
=
GmailApp
.
getMessageById
(
messageId
);
var
sender
=
message
.
getFrom
();
var
url
=
"https://www.example.com/urlbase/"
+
sender
;
return
CardService
.
newUniversalActionResponseBuilder
()
.
setOpenLink
(
CardService
.
newOpenLink
()
.
setUrl
(
url
))
.
build
();
}
/**
* Create a collection of cards to control the add-on
* settings and present other information. These cards are displayed in a list
* when the user selects the associated "Open settings" universal action.
*
* @param {Object} e an event object
* @return {UniversalActionResponse}
*/
function
createSettingsResponse
(
e
)
{
return
CardService
.
newUniversalActionResponseBuilder
()
.
displayAddOnCards
(
[
createSettingCard
(),
createAboutCard
()])
.
build
();
}
/**
* Create and return a built settings card.
* @return {Card}
*/
function
createSettingCard
()
{
return
CardService
.
newCardBuilder
()
.
setHeader
(
CardService
.
newCardHeader
().
setTitle
(
'Settings'
))
.
addSection
(
CardService
.
newCardSection
()
.
addWidget
(
CardService
.
newSelectionInput
()
.
setType
(
CardService
.
SelectionInputType
.
CHECK_BOX
)
.
addItem
(
"Ask before deleting contact"
,
"contact"
,
false
)
.
addItem
(
"Ask before deleting cache"
,
"cache"
,
false
)
.
addItem
(
"Preserve contact ID after deletion"
,
"contactId"
,
false
))
// ... continue adding widgets or other sections here ...
).
build
();
// Don't forget to build the card!
}
/**
* Create and return a built 'About' informational card.
* @return {Card}
*/
function
createAboutCard
()
{
return
CardService
.
newCardBuilder
()
.
setHeader
(
CardService
.
newCardHeader
().
setTitle
(
'About'
))
.
addSection
(
CardService
.
newCardSection
()
.
addWidget
(
CardService
.
newTextParagraph
()
.
setText
(
'This add-on manages contact information. For more '
+
'details see the <a href="https://www.example.com/help">help page</a>.'
))
// ... add other information widgets or sections here ...
).
build
();
// Don't forget to build the card!
}
/**
* Run background tasks, none of which should alter the UI.
* Also records the time of sync in the script properties.
*
* @param {Object} e an event object
*/
function
runBackgroundSync
(
e
)
{
var
props
=
PropertiesService
.
getUserProperties
();
props
.
setProperty
(
"syncTime"
,
new
Date
().
toString
());
syncWithContacts
();
// Not shown.
updateCache
();
// Not shown.
validate
();
// Not shown.
// no return value tells the UI to keep showing the current card.
}

