How to Enable Push Notifications for File Changes in Google Drive with Apps Script
How to setup push notifications to monitor changes in your Google Drive files with Google Apps Script
Are you looking for a way to receive notifications in real-time when an important spreadsheet in your Google Drive get modified or is accidently deleted by sometimes? Well, Google Drive offers an API to help you set up a watch on any file in your Google Drive be it a document, presentation or even a PDF file. This means that you can receive instant notifications whenever the content or even permissions of that file changes.
This tutorial explains how you can setup watch notifications on any file in your Google Drive with the help of Google Apps Script.
Setup a File Watch in Google Drive
To get started, type script.new
in the browser to open the Apps Script editor and add the code below to create a watch. You’d need the unique ID of the Google Drive file and the webhook URL where the notifications would be send when the file gets modified.
const API_BASE_URL = 'https://www.googleapis.com/drive/v3';
const SUBSCRIPTION_DURATION_MS = 24 * 60 * 60 * 1000; // 24 hours in milliseconds
/**
* Starts a subscription for receiving notifications about changes to a Google Drive file.
*
* @param {string} fileId - The ID of the file to watch for changes.
* @param {string} webhookUrl - The URL where notifications will be sent.
* @returns {void}
*/
const startSubscription = (fileId, webhookUrl) => {
try {
// Prepare the payload for the channel subscription
const channelPayload = {
id: Utilities.getUuid(), // Generate a unique ID for the channel
address: webhookUrl,
expiration: Date.now() + SUBSCRIPTION_DURATION_MS,
type: 'web_hook',
token: `fileId=${fileId}&source=labnol.org`,
};
// Construct the API endpoint URL for starting the subscription
const endPoint = Utilities.formatString(`${API_BASE_URL}/files/%s/watch?supportsAllDrives=true`, fileId);
// Call the Drive API to start the subscription
const response = UrlFetchApp.fetch(endPoint, {
method: 'POST',
contentType: 'application/json',
headers: {
Authorization: `Bearer ${ScriptApp.getOAuthToken()}`,
},
payload: JSON.stringify(channelPayload), // Convert payload to JSON string
});
// Parse the response to extract subscription information
const { id, resourceId } = JSON.parse(response);
// Store subscription information in script properties
const subscriptions = { id, resourceId, fileId, webhookUrl };
PropertiesService.getScriptProperties().setProperty('subscriptions', JSON.stringify(subscriptions));
} catch (error) {
// Handle errors that might occur during subscription setup
console.error(`Error starting subscription: ${error.message}`);
}
};
Initialize Drive Watch Trigger
By default, a file watch expires in an hour. To extend this duration to 24 hours, we’ll use the SUBSCRIPTION_DURATION_MS variable. Please note that there’s no way to set up an indefinite watch. We’ll thus setup a time-based trigger in Apps Script to automatically renew the watch every 24 hours.
const initializeWatchApp = () => {
const fileId = '<<Drive File Id>>';
const webhookUrl = 'https://<<Webhook URL>>';
startSubscription(fileId, webhookUrl);
ScriptApp.getProjectTriggers().forEach((trigger) => {
ScriptApp.deleteTrigger(trigger);
});
ScriptApp.newTrigger('triggerRenewSubscription').timeBased().everyHours(24).create();
// Used to add the necessary Drive Scope
const file = DriveApp.getFileById(fileId);
console.log(`Push notifications activated for ${file.getName()}`);
};
Renew File Watch Automatically
The trigger functions manages the process of creating and renewing channel subscriptions for receiving notifications about changes to specific files in Google Drive. It leverages UrlFetchApp.fetch method instead of the Drive.Files.watch
service since the latter uses the older version v2 of Google Drive API.
Since we do not want multiple notifications for the same file, we manually stop any existing subscriptions for a file before adding a new watch.
const triggerRenewSubscription = () => {
try {
// Retrieve subscription information from script properties
const data = PropertiesService.getScriptProperties().getProperty('subscriptions');
const subscriptions = JSON.parse(data);
const { resourceId, id, fileId, webhookUrl } = subscriptions;
// Stop the current subscription
UrlFetchApp.fetch(`${API_BASE_URL}/channels/stop`, {
method: 'POST',
contentType: 'application/json',
headers: {
Authorization: `Bearer ${ScriptApp.getOAuthToken()}`,
},
payload: JSON.stringify({ id, resourceId }),
});
// Start a new subscription with the same details
startSubscription(fileId, webhookUrl);
console.log('Channel subscription renewed successfully!');
} catch (error) {
console.error(`Error renewing subscription: ${error.message}`);
}
};
Handline watch notfications
You may use a web service like webhook.site
or requestbin.com
to test webhook notifications for file changes.
It is also possible to publish a Google Script as a web app to handle POST notifications from the Drive API but there’s a limitation - Apps Script cannot read the header of an incoming web require and Drive notifications include the data in the X-Goog-Channel-ID
, X-Goog-Channel-Token
and X-Goog-Resource-State
headers of the request.
Amit Agarwal
Google Developer Expert, Google Cloud Champion
Amit Agarwal is a Google Developer Expert in Google Workspace and Google Apps Script. He holds an engineering degree in Computer Science (I.I.T.) and is the first professional blogger in India.
Amit has developed several popular Google add-ons including Mail Merge for Gmail and Document Studio. Read more on Lifehacker and YourStory