Monitor Website Uptime with Google Apps Script

You don't need a paid uptime monitoring service for simple projects. With Apps Script and a time-based trigger, you can check your site every few minutes and get alerted the moment it goes down.

Basic uptime check

function checkUptime() { const url = 'https://yourwebsite.com'; try { const response = UrlFetchApp.fetch(url, { muteHttpExceptions: true }); const statusCode = response.getResponseCode(); if (statusCode >= 200 && statusCode < 300) { Logger.log(`${url} is UP (${statusCode})`); } else { Logger.log(`${url} returned status ${statusCode}`); sendDownAlert(url, statusCode); } } catch (e) { Logger.log(`${url} is unreachable: ${e.message}`); sendDownAlert(url, 'Unreachable'); } } function sendDownAlert(url, status) { GmailApp.sendEmail( '[email protected]', `⚠️ Site Down: ${url}`, `Your site ${url} appears to be down.\nStatus: ${status}\nTime: ${new Date()}` ); }

Log response times to a Google Sheet

function checkUptimeAndLog() { const sites = [ 'https://yourwebsite.com', 'https://api.yourwebsite.com/health', ]; const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); // Add header row if sheet is empty if (sheet.getLastRow() === 0) { sheet.appendRow(['Timestamp', 'URL', 'Status Code', 'Response Time (ms)', 'Status']); } sites.forEach(url => { const start = Date.now(); let statusCode = 'Error'; let status = 'DOWN'; try { const response = UrlFetchApp.fetch(url, { muteHttpExceptions: true }); statusCode = response.getResponseCode(); status = statusCode >= 200 && statusCode < 300 ? 'UP' : 'DOWN'; } catch (e) { statusCode = e.message; } const responseTime = Date.now() - start; sheet.appendRow([new Date(), url, statusCode, responseTime, status]); if (status === 'DOWN') { sendDownAlert(url, statusCode); } }); }

Avoid alert spam with cooldown tracking

Without a cooldown, you'll get an email every 5 minutes while your site is down. Use PropertiesService to track when the last alert was sent:

function checkWithCooldown() { const url = 'https://yourwebsite.com'; const cooldownMinutes = 30; const lastAlertKey = 'LAST_ALERT_TIME'; let statusCode; try { const response = UrlFetchApp.fetch(url, { muteHttpExceptions: true }); statusCode = response.getResponseCode(); } catch (e) { statusCode = 0; } const isDown = statusCode < 200 || statusCode >= 300; if (isDown) { const props = PropertiesService.getScriptProperties(); const lastAlert = props.getProperty(lastAlertKey); const now = Date.now(); if (!lastAlert || (now - parseInt(lastAlert)) > cooldownMinutes * 60 * 1000) { GmailApp.sendEmail( '[email protected]', `⚠️ Site Down: ${url}`, `Status: ${statusCode || 'Unreachable'}\nTime: ${new Date()}` ); props.setProperty(lastAlertKey, String(now)); Logger.log('Alert sent.'); } else { Logger.log('Site down, but within cooldown period. No alert sent.'); } } else { // Reset cooldown when site is back up PropertiesService.getScriptProperties().deleteProperty(lastAlertKey); Logger.log(`${url} is UP (${statusCode})`); } }

Set up a 5-minute check trigger

function createUptimeTrigger() { ScriptApp.newTrigger('checkWithCooldown') .timeBased() .everyMinutes(5) .create(); }

Tips

  • Apps Script triggers have a minimum interval of 1 minute — you can't check more frequently than that.
  • UrlFetchApp.fetch() has a timeout of around 60 seconds. If your site is just slow, it may still count as "up".
  • Log to a Sheet and use conditional formatting (red for DOWN, green for UP) for a simple dashboard.
  • Check /health or /ping endpoints rather than the homepage — they're faster and less likely to trigger unintended side effects.