Checks every site listed in a spreadsheet on a schedule and alerts you in Slack or by email when one goes down or recovers.
Uses
Gmail
Google Sheets
Slack
Watch your websites for downtime
Every 15 minutes, the workflow reads the sites listed on the 'Sites' tab of your spreadsheet, requests each one and decides whether it is up. A successful answer counts as up; a server error, a timeout or a name that no longer resolves counts as down. When a site changes state you are told in Slack, by email, or both.
Alerts go out on the change, not the state. When a site first stops answering you get one message saying what went wrong; while it stays down you hear nothing more; when it answers again you get a single all-clear saying how long it had been down. Every change is written to a 'Status log' tab in the same spreadsheet, created on the first run, which is both its memory and your record of what happened and when. One unreachable site never stops the others being checked.
Before the first run you need a spreadsheet with a 'Sites' tab that has a column headed 'URL', one site per row, and a Slack channel or email address to alert.
sitesSheetUrl to blank.Set sitesSheetUrl to blank.sitesTabName to Sites.Set sitesTabName to Sites.statusTabName to Status log.Set statusTabName to Status log.alertSlackChannelId to blank.Set alertSlackChannelId to blank.alertEmailAddress to blank.Set alertEmailAddress to blank.maxSites to 25.Set maxSites to 25.checkedAt.Get the current date and time and save it as checkedAt.siteRows to an empty list.Set siteRows to an empty list.siteListErrorIf a step below fails, save the error as siteListErrorsitesSheetUrl. Save it as siteList.Read the rows of sitesSheetUrl. Save it as siteList.siteRows to siteList.rows.Change siteRows to siteList.rows.siteListError.message).Stop and report a problem: Could not read the site list, so nothing was checked. Check that the spreadsheet in 'sitesSheetUrl' has a tab named as in 'sitesTabName'. (siteListError.message).logRows to an empty list.Set logRows to an empty list.logHasHeader to false.Set logHasHeader to false.logReadErrorIf a step below fails, save the error as logReadErrorsitesSheetUrl. Save it as storedLog.Read the rows of sitesSheetUrl. Save it as storedLog.logRows to storedLog.rows.Change logRows to storedLog.rows.logHasHeader to the length of storedLog.headers is greater than 0.Change logHasHeader to the length of storedLog.headers is greater than 0.logReadError.message).Show in the output: There is no status log yet, so this run creates it and records what it finds as the starting point. (logReadError.message).createTabErrorIf a step below fails, save the error as createTabErrorstatusTabName in sitesSheetUrl.Create the tab statusTabName in sitesSheetUrl.createTabError.message).Show in the output: Could not create the status log tab; carrying on in case it already exists. (createTabError.message).logHasHeader is noIf logHasHeader is noheaderErrorIf a step below fails, save the error as headerErrorstatusTabName in sitesSheetUrl.Add a row to statusTabName in sitesSheetUrl.headerError.message).Show in the output: Could not write the status log header row. (headerError.message).sitesChecked to 0.Set sitesChecked to 0.sitesDown to 0.Set sitesDown to 0.site in siteRows:For each site in siteRows:siteUrl to blank.Set siteUrl to blank.urlErrorIf a step below fails, save the error as urlErrorsite.URL and save it as siteUrl.Trim site.URL and save it as siteUrl.A row in the site list has no 'URL' column, so it was skipped. Check that the first row of the sites tab has a column headed URL..Show in the output: A row in the site list has no 'URL' column, so it was skipped. Check that the first row of the sites tab has a column headed URL..siteUrl is emptyIf siteUrl is emptysitesChecked.Add 1 to sitesChecked.isUp to false.Set isUp to false.detail to blank.Set detail to blank.checkErrorIf a step below fails, save the error as checkErrorsiteUrl and save it as response.Fetch siteUrl and save it as response.isUp to response.ok.Change isUp to response.ok.detail to Answered with HTTP response.status as text.Change detail to Answered with HTTP response.status as text.isUp to false.Change isUp to false.detail to Could not be reached. checkError.message.Change detail to Could not be reached. checkError.message.currentStatus to Down.Set currentStatus to Down.isUp is yesIf isUp is yescurrentStatus to Up.Change currentStatus to Up.sitesDown.Add 1 to sitesDown.lastStatus to blank.Set lastStatus to blank.lastChangedAt to blank.Set lastChangedAt to blank.entry in logRows:For each entry in logRows:logRowErrorIf a step below fails, save the error as logRowErrorentry.URL and save it as entryUrl.Trim entry.URL and save it as entryUrl.entry.Status and save it as entryStatus.Trim entry.Status and save it as entryStatus.entry.Time and save it as entryTime.Trim entry.Time and save it as entryTime.entryUrl is siteUrlIf entryUrl is siteUrllastStatus to entryStatus.Change lastStatus to entryStatus.lastChangedAt to entryTime.Change lastChangedAt to entryTime.logRowError.message).Show in the output: Ignored a status log row that is missing a column. (logRowError.message).currentStatus is not lastStatusIf currentStatus is not lastStatuslogWriteErrorIf a step below fails, save the error as logWriteErrorstatusTabName in sitesSheetUrl.Add a row to statusTabName in sitesSheetUrl.siteUrl in the status log. (logWriteError.message).Show in the output: Could not record the change for siteUrl in the status log. (logWriteError.message).alertSubject to blank.Set alertSubject to blank.alertBody to blank.Set alertBody to blank.currentStatus is DownIf currentStatus is DownalertSubject to Site down: siteUrl.Change alertSubject to Site down: siteUrl.alertBody to siteUrl did not answer as expected.Change alertBody to siteUrl did not answer as expected.
detail
First seen at checkedAt.alertSubject to Site back up: siteUrl.Change alertSubject to Site back up: siteUrl.alertBody to siteUrl is answering again.Change alertBody to siteUrl is answering again.
detail
It had been down since lastChangedAt.alertSubject isn't emptyIf alertSubject isn't emptyalertSlackChannelId isn't emptyIf alertSlackChannelId isn't emptyslackErrorIf a step below fails, save the error as slackErroralertSlackChannelId.Send a message to alertSlackChannelId.alertSubject
alertBodysiteUrl to Slack. (slackError.message).Show in the output: Could not post the alert for siteUrl to Slack. (slackError.message).alertEmailAddress isn't emptyIf alertEmailAddress isn't emptyemailErrorIf a step below fails, save the error as emailErroralertEmailAddress.Send an email to alertEmailAddress.
Subject: alertSubjectalertBodysiteUrl. (emailError.message).Show in the output: Could not email the alert for siteUrl. (emailError.message).sitesChecked as text site(s); sitesDown as text not answering.Show in the output: Checked sitesChecked as text site(s); sitesDown as text not answering.