Skip to main content

GA4 Monitoring: Daily Drop and Spike Alerts in Slack

How the GA4 Monitoring tool compares yesterday with the day before at 2:00 AM in each property's timezone, and posts a Slack message when sessions, users, events, channels or source/medium move past your threshold.

Most GA4 tracking failures are discovered late. A release goes out on Tuesday, a consent banner update strips the config tag on Wednesday, and someone notices on the following Monday that sessions have been sitting at a third of normal for five days. GA4 has custom insights, but they need to be set up per property, they live inside the GA4 interface, and nobody on the team opens that interface daily. The gap is not detection logic. It is that nobody is looking.

The GA4 Monitoring tool in AI Tag Manager closes that gap with a deliberately small model. Each watched property is compared once a day, yesterday against the day before, at 2:00 AM in the property's own timezone. If a watched metric moves by at least the percentage you chose, in either direction, a message lands in one Slack channel for your account. This post walks through what it compares, how the schedule works, what the Slack message looks like, and where the model stops being useful.

Why a previous-day comparison instead of a rolling window

The earlier version of this tool ran twenty-two kinds of check against a rolling seven-day window, with scores, severity floors and digests. It produced a lot of output and very little action. The current model asks one question per metric: how does the just-completed day compare with the day before it, and is the move bigger than the threshold you set?

That is a coarse instrument on purpose. It will not catch a slow weekly decline, and it will flag a Sunday-to-Monday swing on a B2B site if your threshold is tight. What it does catch, on the first morning, is the failure a GTM practitioner actually loses sleep over: a tag that stopped firing, a consent change that halved collection, a bot burst, a campaign that went live with a broken UTM. Those look like a 40% to 90% move in a single day.

The 2:00 AM rule and why yesterday is the day judged

The check runs at 2:00 AM in the property's reporting timezone, not the server's and not your browser's. When you add a property, the tool reads its IANA timezone from the GA4 Admin API and stores it. The scheduled job is a 15-minute metronome; on every tick it computes the local hour for each enabled property and runs the ones sitting in their 2 AM hour that have not yet run for that local date. A property in Asia/Kolkata and one in America/New_York are checked about nine and a half hours apart, each at its own 2 AM.

Why yesterday? At 2 AM local, the current day is two hours old, and judging it against a full day would report a catastrophic drop every morning. The freshest complete day is yesterday, so the comparison is yesterday against the day before. The GA4 Data API resolves yesterday and 2daysAgo in the property's own reporting timezone, so the boundaries match GA4's own reports rather than a UTC approximation.

One threshold, applied to spikes and drops alike

Each property has a single Alert threshold, a percentage between 1 and 500, with presets for 5%, 10%, 20% and 50%. The default is 20%. The rule is that the absolute value of the day-over-day change must be at or above the threshold to fire. A 25% rise and a 25% fall both alert at a 20% threshold. There is no separate spike and drop setting, and there is no per-metric threshold; one number covers everything the property watches.

Drops and spikes are recorded differently once detected. A drop is stored as high severity with the recommendation to check tagging and collection first, because a broken tag and a quiet day look identical in totals. A spike is medium severity with a note to confirm the source is real traffic. In the alerts table, spikes render green and drops render red.

If the previous day was zero, a percentage is undefined, so the tool does not invent one. It still alerts if the current day reached at least 20, and the message says up from zero rather than reporting a 4,000% spike.

The five metrics you can watch

The configuration panel offers five toggles under Metrics to monitor. All of them run against the same threshold.

ToggleWhat is comparedGA4 field
SessionsTotal sessions, both dayssessions
New UsersFirst-time visitorsnewUsers
Event CountAll eventseventCount
Channel PerformanceSessions per default channel group, each group judged on its ownsessionDefaultChannelGroup
Source / MediumSessions per source and medium pair, each pair judged on its ownsessionSourceMedium

The first three are property totals. Channel Performance and Source / Medium each expand into one comparison per row (Organic Search, Paid Social, google / organic, facebook / cpc), and each row can produce its own alert.

Per-row comparisons need a floor that totals do not. A channel going from 2 to 5 sessions is a 150% spike by arithmetic and noise by any human reading, so a row is only judged if the larger of its two days is at least 20 sessions. The floor applies to the larger day deliberately: a channel that collapsed from 500 to 3 must still be judged.

How to use it

The page lives at /ga4-monitoring and needs a Google connection with Analytics access, the same one used by the GA4 audit tool. The walkthrough below uses the actual labels on the page.

  1. Click Add property in the page header. The Add GA4 property dialog shows one combobox labelled Account and property, grouped by GA4 account, with properties you already watch hidden. If the account can see no properties, the empty state tells you to grant access in GA4 Admin and press Refresh.
  2. Pick a property. The dialog reads its timezone straight away and shows a line like Timezone: Asia/Kolkata. The daily check runs at 2:00 AM there.
  3. Click Add property. The new row is selected in the Watched properties list on the left and its configuration opens on the right. The threshold defaults to 20% and all five metrics start enabled.
  4. Adjust the Alert threshold with the number field or one of the presets, tick or untick the metrics, and set Monitoring ON or OFF with the switch in the panel header. Nothing is stored until you press Save configuration; the button stays disabled until something has changed.
  5. Press Run now to check this property immediately, or Check all now in the header to check every enabled property. A banner reports the result, for example Monitoring complete. 2 checked, nothing crossed a threshold.
  6. Connect Slack from the Slack notifications card (the Manage button) or the Slack KPI tile. Until a channel is connected, alerts are still recorded on the page; they are simply not sent anywhere.

Connecting Slack: one channel per account

Slack is connected once per AI Tag Manager account, not per property, and every watched property posts to that one channel. An agency wanting each client's alerts in a separate channel needs a separate account per client, the same boundary the agency workspace workflow recommends for GTM access.

In the Slack notifications dialog, press Add to Slack, authorise the app in your workspace, and you are returned to the monitoring page with the dialog open on the channel step. The Slack channel combobox lists public channels and the private channels you are a member of. Private channels the app is not in yet are marked app will be invited on save; picking one invites the app on your behalf, so you do not have to run a manual /invite in Slack.

Saving the channel is itself the delivery test. The confirmation message goes through the exact path alerts will use, so a channel the app cannot post to is never stored as connected. Once connected, the dialog offers Send test, which posts a bell message to the stored channel and shows Test sent for a few seconds; Disconnect; and Preview message. Connections made under the older webhook model keep working and are shown as Connected through a legacy webhook, with a Switch to the Slack app button.

What the Slack message looks like

The message has a fixed shape: the account name, the property name, and a Notification block with one line per metric that crossed the threshold. Each line carries the metric, the direction, the percentage, the date being reported, and both raw values. Here is what an alert reads like for a property with a 20% threshold, where a config tag broke on 23 August while a paid campaign kept spending.

Account Name: Meridian Retail
Property Name: Meridian Store - Web
Notification:
• Sessions: Drop of 46.2% on 2026-08-23 (3,058 → 1,645)
• Event Count: Drop of 61.8% on 2026-08-23 (41,920 → 16,010)
• Channel: Organic Search: Drop of 58.1% on 2026-08-23 (1,412 → 592)
• Source / Medium: google / organic: Drop of 57.9% on 2026-08-23 (1,380 → 581)
• Source / Medium: facebook / cpc: Spike of 24.4% on 2026-08-23 (410 → 510)

The Preview notification dialog renders this same shape from your current draft, with the numbers sitting exactly on the configured threshold, so the preview shows the smallest move that would send you a message.

The once-per-day latch, re-runs and dedup

Each property carries a last_notified_date stamp. When the scheduled sweep runs a property during its 2 AM hour, it writes the local date into that stamp, and the sweep will not pick the property up again until the local date changes. That is the once-per-day notification latch. It is also written when a property is skipped because the account's Google token could not be retrieved, so a broken Google connection does not make the scheduler retry the same property every fifteen minutes forever.

Manual runs are separate from the latch. Run now and Check all now do not write the stamp, so you can re-check as often as you want.

Duplicate Slack messages are prevented at the alert level. Every alert has a key made from the metric and the reported date, for example daily:sessions:2026-08-23. A re-run of the same day finds the existing alert row and updates its last-seen time without posting to Slack again. The same metric alerting on a new day is a new key, a new row and a new message.

Reading alerts on the dashboard

The Recent alerts table at the bottom shows the six most recent open alerts; View all opens the full history. Each row expands to show the detail line and the recommendation. Acknowledging an alert removes it from the Open alerts count without deleting it.

Every check is recorded with its per-metric numbers, so Last check in the KPI strip reflects real activity even on a quiet day. A run where nothing could be read is marked critical; a failed read is never treated as a quiet day.

When an alert arrives, the follow-up is diagnostic. For a drop, start with the tagging side: the silent tag failure guide covers the usual suspects, and the tag verification tool confirms whether the GA4 config is still firing on the live site. For a channel-specific drop where totals held, check the consent setup against the Consent Mode v2 playbook.

Limits, and when to use something else

A day-over-day percentage check has clear edges.

If you need intraday detection, a learned baseline, or alerts on revenue, GA4's own custom insights or a BigQuery scheduled query are the better tool. This monitor is for the blunt, high-value case: knowing on the first morning that something large changed.

Setting it up this week

Add your two or three most important properties, leave the threshold at 20% and all five metrics on, press Check all now once to confirm the Google connection reads them, then connect Slack and press Send test. After a week, tune the threshold per property: a high-traffic consumer site can usually run at 10%, a low-volume B2B property is happier at 50%. Open the tool at /ga4-monitoring to start. If you have not run a baseline check on the properties first, the ninety-minute measurement audit is the place to begin, so that the first alert you receive is a real change and not a pre-existing problem.