MSP

Automating Alert Tagging in Freshservice Using Google Sheets, Apps Script, and Cloudflare Workers

6 min read
Share:

Introduction

When an alarm triggers, a ticket is created in Freshservice, and the on-call team member has to stop everything, open a spreadsheet, find the right person’s name, head to Slack, and tag them. Every single time.It becomes very difficult specially when the team is dealing with multiple alerts, that five step manual process adds real delay to incident response.

This blog covers an automation built in order to remove that lookup step entirely. When an alert ticket is created, the system now automatically finds the right person and posts that information as a private note directly on the ticket. so that the on-call team members already know exactly who to tag in Slack, without opening anything else.

Goal of this automation

When an alert is triggered by monitoring tool, a ticket is created in Freshservice. And the team had to refer sheet to find out who owns that alert type and what is the priority of that alert. The process was clear. But it was entirely manual and time consuming.

After automating this process, when an alert ticket is created, a private note is automatically added in the ticket saying who to tag and at what priority.

Step by step Setup

Step 1 – Alarm Creates a Ticket

When a monitoring tool detects an issue, a ticket is created in Freshservice. The subject line looks like:

 
ALARM: CPU high in US West (Oregon)

Step 2 – Freshservice fires a webhook

An automator rule in Freshservice watches for ticket. When the ticket is created, it automatically sends ticket id and ticket subject to a Cloudflare Worker:

{
"ticket_id": "12345",
"ticket_subject": "ALARM: CPU high in US West (Oregon)"
}

Step 3 – The Cloudflare Worker passes the information

The Worker takes the exact same data and passes it to the Google Apps Script.

Why does this relay exist ?

Google Apps Script don’t respond to requests directly. When called, Google first sends back a redirect (HTTP 302) pointing to a separate link, and the real response lives there. Freshservice’s webhook caller doesn’t know how to follow that kind of redirect, it would just report the call as failed.

The Worker fixes this by:

  • Calling Google Apps Script
  • Receiving the redirect
  • Following it to the real response
  • Returning a response “OK” back to Freshservice

Step 4 – Google Apps Script Does the Real Work

This is where the logic lives. The script does three things:

1. Cleans up the subject line

Alert names from monitoring tools are messy and inconsistent. The same alert might arrive as:

ALARM: CPU high in US West (Oregon)
“CPU High” in EU West
CPU high
A direct match would fail on all of these. So the script normalizes everything first — stripping the ALARM: prefix, removing quote characters, and cutting off region suffixes:

function normalizeSubject(subject) {
return subject
.toLowerCase()
.replace(/alarm:\s*/i, "")
.replace(/['"«»""''`]/g, "")
.replace(/\sin\s+(us|eu|ap)\s+.$/i, "")
.replace(/\s+/g, " ")
.trim();
}

All three examples above become cpu high — which is what the sheet row says too.

2. Searches the Google Sheet

The sheet has multiple tabs, one per alert category. Each row has three columns:

Column A — Alert name
Column B — Who to tag in Slack
Column C — Priority
The script searches every tab, normalizes each row’s alert name the same way, and checks if the ticket subject and the sheet row contain each other (a fuzzy two-way match). The first match wins.

3. Posts the note on the ticket

Once a match is found, the script calls the Freshservice API and posts a private note directly on the ticket:

Alert Type: Server Alerts
Tag in Slack: @John
Priority: High
Please tag the above person(s) in Slack when posting the alert and findings.

What if there’s no match?

The script posts a different note instead:

⚠️ No match found in tagging sheet.
Ticket Subject: ALARM: CPU high in US West (Oregon)
Normalized: cpu high
Please check the sheet manually.

This is just as important as the match case. Without it, unmatched alerts would fail silently. With it, gaps show up clearly and the sheet can be updated to fix them.

Step 5 – A Person Tags Slack

Whoever picks up the ticket reads the note and tags the right person in Slack by hand. The automation stops at writing the note — the actual Slack message involves context and judgment, so that part stays manual.

What the Full Flow Looks Like

Alarm fires
→ Freshservice ticket created
→ Automator rule fires webhook
→ Cloudflare Worker receives it
→ Passes it to Google Apps Script
→ Script cleans up subject line
→ Searches Google Sheet
→ Posts private note on ticket
→ Person reads note → Tags Slack

Current Status and Open Items
The automation is built but not yet live. Two things need to be addressed before switching it on:

API key exposure — The Freshservice API key is currently hardcoded in plain text inside the script. It needs to be moved to Script Properties (Google’s built-in secret store) and the current key should be rotated.
Automator rule is off — The Freshservice rule is currently set to Inactive. It gets turned on once the API key issue is resolved.

Conclusion

What started as a small, annoying five-step manual task turned into a clean end-to-end automation using tools the team already had — Freshservice, Google Sheets, and a lightweight script.

The biggest lesson? The normalization step made or broke the whole thing. Alert names from monitoring tools are never clean or consistent, and a direct string match would have failed most of the time. Getting that cleanup logic right was the difference between an automation that works on paper and one that works in the real world.

The no-match note was the second key decision. It’s easy to only think about the happy path — but surfacing gaps clearly, rather than letting them fail silently, is what makes a system trustworthy over time.

If your team is dealing with a similar problem — alert routing, ticket tagging, on-call lookups — this same pattern applies. No new infrastructure or expensive tools are needed. A spreadsheet, a script, and a webhook can go a long way.

Does your team still handle this manually? Or have you built something similar? Drop a comment below — it would be great to hear how others are approaching alert routing.

 

Leave a Reply

Your email address will not be published. Required fields are marked *