SEO Analytics. Looker Studio

Looker Studio SEO Dashboard: Blending GSC and GA4 Without Overstating SEO

15xHow far one all channel scorecard overstated SEO
2 to 3 daysSearch Console lag that empties a date blend
388 rowsLanding pages that earned clicks, joined to orders
4.72%Organic search CVR, against 1.94% for paid social

Written by Ram Kr Shukla, SEO and growth consultant

Quick answer

A Looker Studio SEO dashboard a founder can trust needs three data sources (GA4, plus Search Console twice, as Site Impression and URL Impression), an Organic Search only filter on Session default channel group for every GA4 chart that sits near Search Console numbers, and two separate daily tables in place of a date blend, because Search Console lags two to three days. To put orders next to clicks per page, blend over 28 days on landing page, after a data source field strips the domain off the Search Console URL so it matches GA4’s Landing page path. If item revenue is unreliable, report transactions and CVR.

Most broken SEO dashboards in Looker Studio look perfectly fine. The damage comes from two numbers from different universes sitting on one row, where somebody reads them as one story.

I built one for a D2C beauty brand on Shopify in India. Partway through the build, page one was titled daily organic search. Its Transactions scorecard read 7,140. Organic search had driven about 460 of them. The rest came from paid social, paid search, direct and everything else GA4 tracks. So a page that looked tidy and professional was overstating SEO by roughly 15 times.

This is the build guide: the order I’d wire it in, the traps that produced numbers like that one, and the fixes that held. It’s the plumbing. For what the finished report should actually say to a founder, read vanity metrics vs revenue in e-commerce SEO reporting and what a real Shopify SEO report contains. And if the GA4 events underneath are shaky, fix those first. That’s the job my GA4 conversion tracking work exists for, because no dashboard can be more accurate than the tags feeding it.

A note on the name

Google has renamed Looker Studio back to Data Studio. Same connectors, same blend editor, and existing reports moved across on their own. I’m calling it Looker Studio here because that’s still what most people type into Google.

What an SEO Dashboard Has to Show a Founder

A founder opens the dashboard with one question: is search bringing in customers, and is that number moving? Everything on the page should either answer it or explain why it moved. Rank tracker screenshots and total keyword counts don’t.

Here’s the page structure we ended up with after a few rounds of corrections on a live client build. Four pages, each with one job.

PageWhat’s on itUniverse
1. Daily overviewScorecards for Clicks, Impressions, Add to carts, Transactions, Sessions, CVR. A Search Console daily table beside a GA4 daily table. Organic transactions by landing page, 10 rows.Search Console plus GA4 filtered to Organic Search
2. Organic performanceOrganic totals, then brand vs non-brand clicks and impressions with a two line trend.Organic only
3. Search detailTop queries, and the landing page table with Search Console clicks joined to GA4 orders.Organic only
4. Funnelview_item, add_to_cart, begin_checkout and purchase as event counts, plus a channel table.Funnel organic, channel table all channels and labelled that way

Notice the third column. Every block on every page states which universe it measures. That one habit would have caught the 7,140 problem on day one. The brand split on page two has its own post: branded vs non-branded search traffic.

Connect Three Data Sources, Not Two

You’ll want GA4 once and Search Console twice. The Search Console connector offers two tables, Site Impression and URL Impression, and a single data source can only use one of them. So add both.

  • Site Impression for site totals and the query table. It counts impressions by property, so a result showing several of your links counts once.
  • URL Impression for anything by page. It carries the Landing Page dimension, and its metrics show up as Url Clicks and URL CTR.
  • GA4 for sessions, add to carts, transactions and the channel dimension.

The two Search Console totals won’t agree with each other, and that’s expected. Google counts impressions differently when data is grouped by property and when it’s grouped by page, so a page level total usually runs higher. Use Site Impression for headline clicks and URL Impression only where you need the page.

One irritation from the build: both Search Console sources showed exactly the same display name in the data source picker. You tell them apart by their fields (Landing Page and Url Clicks mean URL Impression). Rename them the minute you add them. Also pick search type web on URL Impression, because the connector lets it report Discover and Google News as well.

Add a home market filter to all three while you’re here. On the store I audited, roughly 91% of blog sessions turned out to be bots, nearly all from outside the home country. My sibling post on separating blog bot traffic from real readers in GA4 covers that filter properly.

Trap 1: The Date Blend That Looks Broken Every Morning

The obvious first build is one daily table with Search Console clicks and GA4 orders side by side, blended on Date. It looks great when you set it up. It looks broken the next morning.

Search Console data is normally available in 2 to 3 days. GA4 is much quicker. So the newest two or three rows of a date-keyed blend carry GA4 numbers and empty Search Console cells. A founder scrolling the table at breakfast sees the gap and assumes the dashboard (or worse, the SEO) has stopped working. You’ll spend the call explaining reporting lag instead of results.

Date blend vs landing page blendSearch Console lags 2 to 3 days. Only one layout shows that as a hole.DATE-KEYED, DAILYLANDING PAGE, 28 DAYSDateGA4 ordersGSC clicksLanding pageClicksOrdersDay 2221301Day 2318287Day 2424312Day 2519296Day 2622emptyDay 2717emptyDay 2820empty/2,905273/products/a1,12298/collections/b1610/products/c667/products/d96/products/e46/collections/f355Newest rows read as brokenThe lag is a sliver of each totalRamKrShukla.comIllustrative. Anonymised client data.
A date-keyed blend leaves the newest Search Console cells empty. A 28 day landing page blend absorbs the same lag. Right side uses anonymised client figures.

The client’s original spec asked for one table with both sources’ columns and also said not to blend. We resolved it with two tables side by side: a Search Console daily table (Date, Impressions, Clicks, Site CTR, Average Position) and a GA4 daily table (Date, Sessions, Transactions, CVR), both sorted newest first, both under one date range control set to Last 28 days. Empty days now look like what they are, which is not yet reported.

The same lag explains a rule for anyone posting numbers daily: never put a fresh Search Console day against a fresh GA4 day and call it a day’s performance. They don’t describe the same day yet.

Trap 2: Two Universes on One Row of Scorecards

Search Console only knows about Google search results. Every click it reports is organic search by definition. GA4 with no channel filter counts every session from every source: paid social, email, direct, ads, the lot.

Put them on one row and the brain joins them. On that store’s first build, 8,328 Search Console clicks sat right beside 7,140 GA4 transactions. The natural reading is that SEO drove 7,140 orders. It drove about 458.

One row of scorecards, two universesA page titled “daily organic search”, four weeks, home market.Search Console clicks (organic search by definition)8,328GA4 transactions, no channel filter (all channels)7,140GA4 transactions, Organic Search onlyabout 460Read side by side, SEO looks responsible for about 15 times its real orders.RamKrShukla.comIllustrative. Anonymised client data.
Search Console clicks next to unfiltered GA4 transactions invite the wrong reading. Filtered to Organic Search, the order count is about one fifteenth of it.

The channel table told the real story, and it’s a better one than the inflated version. Paid social was about 75% of home market sessions and 58% of orders. Organic search was only about 3.5% of sessions but 6.4% of orders, converting at 4.72% against 1.94% for paid social. Organic visitors were more than twice as likely to buy. That’s the line a founder should remember. The full channel picture, and the funnel checks behind it, sit in my Shopify GA4 funnel audit, so I won’t repeat them here.

Build the Organic Search Only Filter

Make it once as a saved filter so every chart uses the identical definition:

  • Open Resource, then Manage filters, then Add a filter, and pick the GA4 data source.
  • Name it Organic Search only. Set it to Include, dimension Session default channel group, condition Equal to, value Organic Search.
  • Add it to every GA4 scorecard, table and time series that sits near Search Console numbers, from the chart’s Setup panel under Filter.
  • Check that the number on the canvas actually drops. On my build the filter click failed silently three times on the Transactions scorecard before it stuck.

Use the session scoped dimension, because it describes how the session arrived, which is what a landing page report needs. And Organic Search means Organic Search: Organic Social, Organic Shopping and Organic Video are separate channels and they don’t belong in an SEO number.

Two things still won’t line up perfectly. Google’s definition of the Organic Search channel covers every search engine on its source list, plus clicks from AI Overviews and AI Mode, while Search Console web data is Google only. And a click isn’t a session: consent banners and blockers stop some visits being recorded. On that store, organic sessions came in within about 8% of Search Console clicks for the top pages, which is the kind of gap you should expect. If your organic number is contaminated by mistagged paid traffic, the gap goes the other way and no dashboard setting will fix it.

Leave exactly one chart unfiltered: the channel table. It’s the proof of where organic sits. Label it in plain words, something like all channels, for context, so nobody mistakes it for SEO.

Trap 3: Revenue You Can’t Trust

Revenue is the number founders want. It’s also the number most likely to be wrong in GA4 on Shopify, because it depends on item level data arriving intact.

On that store, after the tracking fix, one product line still reported zero item revenue against well over a thousand units sold. Any revenue total, and any revenue split by product, silently understated it. Transaction counts weren’t affected, because a transaction is counted when the purchase event fires whatever the item data says.

So the dashboard dropped revenue everywhere. Purchase revenue became Sessions, AOV became CVR, and the daily GA4 table became Date, Sessions, Transactions, CVR. It’s less exciting to look at, and every number on it is defensible.

Run this check before you show revenue

In a GA4 exploration, put Item name against Items purchased and Item revenue for the last 28 days. Any row with units and zero revenue means your revenue figures understate. Until that’s fixed, show transactions.

A related gotcha if you want an Add to carts scorecard. The GA4 connector I used had no metric called Add to carts. It had Add to baskets, which is item scoped, so it counts items rather than cart actions and breaks any funnel built on it. Use Event count with a filter on Event name equal to add_to_cart. On that build it landed within 1% of GA4’s own figure, which is how I knew the wiring was right.

CVR as a Calculated Field

You want transactions per session, and the simplest way to get exactly that is a calculated field. In the chart, click Add metric, then Add calculated field:

Name:     CVR
Formula:  Transactions / Sessions
Type:     Number > Percent

Both inputs are already aggregated metrics, so the division runs on the totals for whatever the chart groups by. A landing page row gets that page’s CVR. A scorecard gets the period’s. Organic CVR on that store came out at 4.74% for the window we built it on, close to the 4.72% in the channel table, which is a decent cross-check.

The annoyance: a chart level calculated field lives in that one chart. It doesn’t carry to the next one, so I recreated CVR in every chart that needed it. If you own the GA4 data source, add it there once and every chart can pick it up.

Trap 4: The Join Key That Matches Nothing

Sooner or later someone asks for orders next to the Search Console landing page table. That’s the most useful table on the whole dashboard, and the first blend attempt usually returns a column of nulls.

The two sources spell the same page differently. Search Console’s Landing Page is a full URL, protocol and domain included. GA4’s landing page dimensions are page paths. There are two of them in GA4, too. Landing page + query string keeps the parameters, so it split the homepage into / and /?openCart=true on that store. Landing page drops them.

Same page, two spellingsSearch Console stores a full URL. GA4 stores a path.SEARCH CONSOLE: Landing Pagehttps://www.example.com/collections/aGA4: Landing page + query string/collections/a/?openCart=trueStraight join on these two: zero matchesFIX 1: DATA SOURCE FIELD ON SEARCH CONSOLEREGEXP_REPLACE(Landing Page, “^https?://[^/]+”, “”)FIX 2: USE GA4 Landing page (NO QUERY STRING)/collections/a = /collections/amatchRamKrShukla.comIllustrative.
Search Console and GA4 store the same landing page in different formats. A data source field on the Search Console side makes them comparable.

The fix has two parts.

First, use GA4’s plain Landing page. It collapses /?openCart=true back into /. On that store the homepage showed 266 transactions in the table built on Landing page + query string and 273 in the one built on Landing page. Both were right. They’re cut differently, so expect small gaps between tables and don’t chase them as bugs.

Second, add a calculated field to the Search Console URL Impression data source that strips the protocol and domain. Name it Landing page path:

REGEXP_REPLACE(Landing Page, "^https?://[^/]+", "")

That’s REGEXP_REPLACE with a pattern that has no backslashes in it, so there’s no escaping to get wrong. It removes everything up to the first slash after the domain and leaves the path.

Make it a data source field, through the data source’s field editor. The blend editor wouldn’t accept a chart level calculated field as a join key in my build, which cost a round of head scratching.

You could go the other way and build a full URL on the GA4 side with CONCAT, something like CONCAT(“https://www.example.com”, Landing page). It works if your property only ever reports one protocol and host. Stripping is safer, because a domain property can report several hosts and the regex doesn’t care which one it meets.

One more variant to watch. When Google shows jump links to sections of a long article, Search Console can list each section’s #anchor URL as its own row. That same store had 21 of them across four articles. Strip the fragment too, nesting one replace inside the other:

REGEXP_REPLACE(REGEXP_REPLACE(Landing Page, "^https?://[^/]+", ""), "#.*$", "")

Then check the row count after the join. If two Search Console rows reduce to the same path, the GA4 numbers repeat on both rows, and the table total double counts. I’d test this nested version on a handful of rows before trusting it, since the build I’m describing only needed the first one.

Blend on Landing Page Over 28 Days

Here’s the part people get stuck on. If the date blend is a bad idea, why is a landing page blend fine? Because the lag hurts differently. Across a 28 day window, the missing two or three days are a sliver of each page’s total, not an empty cell. Nothing reads as broken.

The blend that’s running on that store:

SettingValue
Table 1 (left)Search Console URL Impression. Dimensions Landing Page and Landing page path. Metrics Url Clicks, Impressions, URL CTR, Average Position. Home market filter.
Table 2 (right)GA4. Dimension Landing page (no query string). Metrics Transactions, Sessions. Home market filter and Organic Search only.
JoinLeft outer, one condition: Landing page path equals Landing page.
Date rangeLast 28 days, from the page’s date control.
SortTransactions, descending, set in the Setup panel.

A left outer join keeps every row from the left table and adds matches from the right. Search Console goes on the left because the question is about search: which pages earned clicks, and what did those visitors do next? Some guides put GA4 on the left. That answers a different question (every page sessions started on, with search data where it exists), and that’s fine if it’s the one you’re asking.

Expect the table to be shorter than GA4’s landing page list. On that store it had 388 rows. GA4 showed 2,214 organic landing pages, and most of those never showed up as a Search Console landing page with clicks in the window. 388 is correct. Just don’t describe it as a complete landing page list.

Then sanity check two rows before you show anyone. The homepage had 2,905 Search Console clicks and 3,165 organic sessions. The top product page had 1,122 clicks and 1,212 sessions. Within about 8% on both is a healthy match. If yours are out by half, the join or a filter is wrong.

Three Things That Bit During the Build

  • The chart’s own filter broke. After the blend, the chart level home market filter threw Invalid filter, because Country wasn’t in the blend’s output. Delete it from the chart and keep the filters inside the blend, on both tables. Don’t add Country as a join dimension to rescue it, or you risk duplicated rows.
  • Metric aggregation flipped to SUM. Harmless here, because each page is one row and the sum of one row is that row. That’s why the Search Console columns came back identical to the pre-blend table. If an edit ever makes a page appear twice, URL CTR and Average Position will quietly go wrong.
  • Nulls where you might expect zeros. A page with clicks but no organic sessions in GA4 shows null. Honest, because null admits there’s no data, while zero claims there were no sales. Warn the client before they see it.

What the Landing Page Table Showed

Sorted by transactions, the table made an argument no scorecard could. The third row was a collection page with about 18,900 impressions at an average position of 5.57, which had turned into 16 clicks and 10 transactions. It’s on page one, it sells when people land, and almost nobody clicks it. That’s a title and snippet problem with a page name attached, and it’s far more actionable than a sitewide CTR figure.

Another row had zero clicks and four transactions. Don’t present that as a miracle. It’s Search Console lag at the edge of the window, or clicks credited to a slightly different URL variant.

Collection pages carrying the money is a pattern I’ve seen before. On the fashion Shopify store in my published case study, collection pages drove more than 70% of organic revenue. A per page table is how you find out whether yours do.

Small Settings That Quietly Break a Dashboard

None of these show up in template guides. All of them cost me time on a live build.

  • Clicking a column header doesn’t save a sort. It applies an interactive sort to your view only. The Sort panel kept saying Url Clicks while the table showed Transactions order, and the report’s Reset button wiped it. Set Sort in the Setup panel, choosing the field from the Chart fields group, then press Reset to prove it holds.
  • Tables don’t scroll inside their box. With rows per page set higher than the box could show, the table simply cut off at row 11 with no way to reach the rest. Size rows per page to the box. Ten rows suited a phone screenshot anyway, and the pager still reaches all 2,214.
  • Comparison arrows can measure a tracking fix. Ecommerce tracking on that store went live partway through the comparison period, so Transactions showed +803.5% against the previous 28 days. The arrow was measuring the tracking fix itself. Report absolute numbers until both windows sit after the change. My sibling post on fake growth in GA4 comparisons after a tracking fix works out when the arrows become honest.
  • Start dates before tracking existed read as a crash. Set the date control’s default to Last 28 days and never let a window start before your ecommerce events went live. The GA4 comparison window calculator gives the first safe date for each comparison on the dashboard.
  • Query tables sum short of the total. Search Console leaves anonymised queries out of query rows, so brand plus non-brand will always total less than site clicks. The Search Console API post on missing keywords explains the gap.

The Daily Posting Rhythm

The deal with that client was simple. All the data in one place, numbers posted to the team’s group every day, and targets set only after the data existed. The dashboard is built around that daily post, which is why page one carries everything that matters and fits in one screenshot.

What goes in the post:

  • A screenshot of page one, Daily overview, with the 28 day date range showing.
  • Absolute numbers only. Clicks, organic transactions, organic CVR. No arrows while the comparison window still spans a tracking change.
  • One standing line: Search Console runs two to three days behind GA4, so the newest search days are still filling in.
  • A short note if something moved, with the page from the landing page table that explains it.

Hold target setting until roughly four weeks of clean, post-fix data exists. A target set on a broken baseline gets beaten by accident and missed by accident, and both teach the team nothing.

Daily suits a founder’s pulse check. Decisions need longer windows, so read the landing page blend weekly and make content and snippet calls from 28 day totals. On a store doing about 16 organic orders a day, day to day swings are mostly noise.

How to Build a Looker Studio SEO Dashboard, Step by Step

The full sequence, in the order that avoids rework:

1
Connect three data sources

Add your GA4 property, then the Search Console connector twice: once as Site Impression and once as URL Impression, search type web. Rename all three straight away, because both Search Console sources show the same name in the picker.

2
Save reusable filters

Under Resource, Manage filters, create Organic Search only (Include, Session default channel group, Equal to, Organic Search), a home market filter for each source, and Event add_to_cart if you need cart counts. Filters saved once can be added to any chart in two clicks.

3
Build the daily page with two tables

Put a Search Console daily table and a GA4 daily table side by side, both sorted newest first, under one date range control set to Last 28 days. Don’t blend them on Date, because Search Console lags two to three days and the newest rows would come back empty.

4
Filter every GA4 chart to Organic Search

Apply Organic Search only to every GA4 scorecard, table and time series that sits near Search Console numbers. Check that the number on the canvas actually changes. Leave one channel table unfiltered and label it all channels, for context.

5
Report transactions and CVR

If any product shows units sold with zero item revenue, drop Purchase revenue and AOV. Show Transactions and Sessions, and add CVR as a calculated field: Transactions / Sessions, type Percent.

6
Create the landing page join key

On the Search Console URL Impression data source (not in a chart) add a calculated field called Landing page path with REGEXP_REPLACE(Landing Page, “^https?://[^/]+”, “”). On the GA4 side use the plain Landing page dimension, without the query string.

7
Blend Search Console to GA4 on landing page

Table 1 is URL Impression with Landing Page path, clicks, impressions, CTR and position. Table 2 is GA4 with Landing page, Transactions and Sessions, filtered to your home market and Organic Search only. Use a left outer join on Landing page path equals Landing page and set the chart to the last 28 days.

8
Lock the settings and start posting

Set the sort in the Setup panel, size rows per page to fit the table box, press Reset to prove the saved state holds, and label each block with the universe it measures. Then post page one daily with absolute numbers and a note that Search Console runs two to three days behind.

If you’d rather have someone audit the tracking and build this for you, that sits inside my SEO and CRO funnel audit. The Search Console side of it pairs well with the seven Search Console reports most marketers never open.

Common Questions

Can you blend Search Console and GA4 data in Looker Studio?

Yes. Blend on landing page over a period such as 28 days, with Search Console URL Impression as the left table and GA4 as the right, using a left outer join. Avoid blending on Date for a daily view, because the newest Search Console rows will be empty.

Why are the newest days empty in my blended Search Console and GA4 table?

Search Console data usually takes two to three days to arrive, while GA4 is much quicker. A blend keyed on Date shows GA4 values with blank Search Console cells for those days. Use two separate daily tables under one date control instead.

Why does my GSC and GA4 blend match no rows?

The join keys are spelled differently. Search Console Landing Page is a full URL with the protocol and domain, and GA4 Landing page is a path. Add a data source calculated field on the Search Console side that strips the domain, then join it to the GA4 Landing page dimension.

Why don’t Search Console clicks match GA4 organic sessions?

They count different things. A click isn’t a session, consent banners and blockers stop some sessions being recorded, and GA4 Organic Search also includes other search engines. On one store the two were within about 8% per page, which is normal.

How do I show only organic search in a Looker Studio GA4 chart?

Create a filter that includes Session default channel group equal to Organic Search, save it under Resource, Manage filters, and add it to each GA4 chart. Then check the number on the canvas changes, because the click doesn’t always stick.

Should an SEO dashboard show revenue or transactions?

Show revenue only if item revenue is reliable. If any product reports units sold with zero item revenue, revenue totals understate silently and transaction counts are the safer number. Add CVR beside them so the founder sees quality as well as volume.

How do I calculate conversion rate in Looker Studio?

Add a calculated field with the formula Transactions / Sessions and set its type to Percent. A chart level field has to be recreated in every chart, so add it to the data source once if you own it.

Is a free Looker Studio SEO dashboard template good enough?

It’s a fine starting point for layout. Before you trust one, check that GA4 charts are filtered to Organic Search, that daily views aren’t blended on Date, that the landing page join key matches, and that comparison arrows don’t span a tracking change.

Does your SEO dashboard mix organic and all channel numbers?

I check the GA4 events first, then rebuild the dashboard so every number states the universe it measures, and the one a founder quotes is the right one.

GA4 Conversion TrackingSEO and CRO Funnel Audit

Tags: SEO AnalyticsLooker StudioGA4Search Console

RS

Written by Ram Kr Shukla

SEO and growth consultant with 20+ years in SEO and growth across 50+ brands, working as a consultant or Fractional Chief Digital Officer. Google Analytics and Google Ads certified. Builds the measurement before judging the SEO, and works daily in GA4, Search Console and Looker Studio.

Client Results, Not Claims

5x D2C revenue in 18 months via SEO
10x SaaS trials, zero new blog posts
120K Monthly organic visitors from zero

Free Resource

Steal My 40 Point SEO Audit Checklist

The exact list I run on every paid audit. Score your site in 30 minutes.

Get the checklist →

Is your site invisible to AI search?

Ask ChatGPT to recommend brands in your category. If you are not the answer, we should talk.

Book a Free Strategy Call