← All case studies

Build

The Five-Domain Dashboard

Building a multi-domain SEO dashboard from an empty report was the easy half. The harder half was making every number provably match a known-good baseline before I handed it over.

ClientHigher-education client (anonymized)
ScopeFive domains, one report
StackLooker Studio, GA4, BigQuery, Search Console, Adverity
Hard partNumbers that had to reconcile
StatusBuilt, validated, shipped
01 The brief

The client is a college with several distinct web properties, each on its own subdomain, and they wanted one monthly SEO dashboard covering all of them: organic traffic, search performance, and engagement across five domains in a single report. There was a prior month's report to match against, which mattered more than it first appeared, because it meant the new build wasn't just supposed to look right, it was supposed to agree with a number the client had already seen and trusted.

02 The access problem, first

Check who's allowed to see it before assuming the data is broken.

Before any of the building, I hit a wall that had nothing to do with the dashboard. The data connection I was handed to pull GA4 through Adverity didn't actually have access to these properties. The account it authenticated with listed dozens of other properties but not the ones I needed, so every attempt to connect the data source came back empty.

Rather than assume the properties were missing or misconfigured, I checked the authenticating account's property list directly and confirmed the gap: the properties existed, the connection just wasn't authorized for them. The fix was to create a fresh authorization through an account that did have access, which unblocked the whole build. It's a small thing, but it's the kind of thing that eats a day if you assume the data is broken instead of checking who's allowed to see it.

# GA4 connection returning empty authenticating account -> 55 properties visible target properties -> not in that list # properties exist; the connection just isn't authorized. re-auth through an account that is.
03 The build

With access sorted, I built the report from an empty canvas: layout and grid, a shared theme, then the data source connections for each domain across GA4, BigQuery, and Search Console. From there the dashboard pages themselves, structured so each domain reads consistently and the whole thing holds together as one report rather than five separate ones bolted side by side.

That part was straightforward work. The part worth writing about is what happened when I started checking the numbers against the prior report.

04 Where the numbers disagreed

Plausible, confident, and quietly wrong.

The sessions figures came in noticeably higher than the previous month's report, across every domain. The traffic hadn't actually jumped, so something in how I was counting was inflating the totals. This is the trap with GA4 data pulled from BigQuery: the raw sessions field over-counts relative to what most people mean by a session, because of how GA4 segments events. If you take the field at face value, your numbers look plausible and are quietly wrong.

The prior report had been built to count sessions a particular way, so to agree with it I had to match that methodology rather than trust the raw field. I rebuilt the session metric as a calculated field with an event-name filter, so it counted sessions the same way the baseline did instead of the way the raw export presented them.

# raw BigQuery sessions field -> inflated vs known baseline # GA4 segments events in a way the raw field over-counts session metric = calculated field, filtered on event_name # now counting the way the trusted report counted
05 Proving it, domain by domain

Rewriting the metric wasn't enough on its own. I had to show the new numbers actually landed on the old ones, so I validated all five domains against the prior report rather than spot-checking one and assuming the rest followed. New-user counts came in within a few percent across the board, and on the largest domain the match was down to a handful of users out of nearly seventeen thousand.

That kind of margin is the difference between a dashboard someone glances at and a dashboard someone trusts enough to make decisions from. Getting the largest domain to agree within three users out of roughly sixteen thousand eight hundred meant the methodology was right, not just close.

5 / 5
Domains validated against baseline
±3%
New users vs prior report
3
User variance on the largest domain (of ~16,860)
06 The filter that wasn't filtering

A filter that silently does nothing is worse than no filter.

One more problem surfaced during validation. A URL-exclusion filter I'd set on the Search Console charts, meant to strip out a set of paths that shouldn't count, wasn't changing the numbers at all. The chart looked filtered and behaved as though it wasn't.

A filter that silently does nothing is worse than no filter, because it looks handled. I traced it to the filter configuration itself rather than the data: the kind of mismatch where the include-versus-exclude setting or the targeted field is slightly off, so the rule matches nothing and passes everything through untouched. Once corrected, I built the Search Console version as a deliberate twin of the GA4 exclusion so the two data sources were filtering the same way, and I mapped out which domain pages actually needed the exclusion and which didn't, rather than blanket-applying it and hoping.

07 What this taught me

Provably right, not merely reasonable.

The building was maybe a third of this job. The rest was refusing to trust a number until it agreed with a number someone already believed. GA4 data out of BigQuery will hand you plausible, confident, wrong totals if you take the raw fields at face value, and a filter will happily sit on a chart doing nothing while looking like it works. The work that made this dashboard worth shipping was the part nobody sees in the final report: checking every domain against the baseline until the methodology was provably right rather than merely reasonable.

← All case studies