Skip to main content

Google Search Console

πŸ’ŽPremium Feature

This feature is exclusive for Premium users!

The Google Search Console module transforms the Search Console bulk data export into analysis-ready tables. It unions one or more properties, flags branded and question queries, and builds five SEO reports on top: daily trends, query cannibalization, query and page movers and shakers, and a CTR-by-position benchmark.

Key Features​

  • Multiple Properties: Union the bulk exports of several Search Console properties (also from other GCP projects), each with its own friendly name
  • Branded Query Flag: Mark queries that contain your brand - exact terms, regex patterns, or phonetic (SOUNDEX) matching to catch misspellings
  • Question Query Flag: Mark queries that start with a question word (what, how, why, ...), with per-property word lists for other languages
  • Normalized Queries: query_normalized (lowercase, punctuation removed) so casing and punctuation variants group together
  • SEO Reports: Daily trends with 14/28/56-day averages, cannibalization, movers and shakers per query and per page, and CTR underperformers against your own CTR curve
  • Export Monitoring: Export delays and retries per property and day
  • Incremental Processing: Only new export days are loaded into the base tables

Search Console Bulk Data Export​

  • Set up the bulk data export for every property you want to include. Google creates a dataset (default name searchconsole) with the ExportLog, searchdata_site_impression and searchdata_url_impression tables.
  • The export starts from the day you enable it - Search Console does not backfill history.
  • Every listed dataset must be in the same BigQuery region as your GA4Dataform datasets.

Limitations​

  • Search Console exports land 2-3 days late. The reports anchor their windows on the latest exported data_date of each property, not on the current date.
  • Anonymized queries (rare queries Google hides for privacy) have no query text, so they can't be flagged as branded or question queries.
  • is_branded_query and is_question_query are set when a day is first loaded. Changing brand terms or question words doesn't update history - see Applying changes to history.
  • CTR and position differ a lot between search types (WEB, IMAGE, VIDEO, NEWS, DISCOVER). The reports default to WEB only. If you include more search types, filter on a single search_type in your dashboard instead of summing across them.

Configuration​

The module uses a YAML configuration file: includes/custom/modules/google_search_console/config.yaml

# set by Superform Labs team to indicate changes
version: 1
# true/false to toggle this feature, default is false
enabled: true
question_words:
- "what"
- "where"
- "when"
- "why"
- "who"
- "how"
# ... see the full default list in the template
gsc_sources:
- dataset: 'searchconsole'
gsc_property_name: 'Main Site (EN)'
brand_terms:
- "ga4dataform"
- "ga4 dataform"
brand_terms_regex:
- "ga4.?data.?form"
brand_terms_soundex:
- "dataform"
- gcp_project: 'my-other-project'
dataset: 'searchconsole_es'
gsc_property_name: 'Spanish Site'
question_words:
- "quΓ©"
- "dΓ³nde"
- "cΓ³mo"

Each report also has its own settings block - see Report Settings.

Configuration Options​

Essential Settings​

OptionTypeDefaultDescription
enabledbooleanfalseTurns the module on
gsc_sourcesarray[]The Search Console export datasets to read - at least one is required when the module is enabled
question_wordsarrayEnglish list (what, where, when, why, who, how, do, does, is, are, was, did, if, will, can, could)Words that mark a query as a question when they are its first word (case-insensitive)

Data Sources (gsc_sources)​

Each entry describes one Search Console property export. Multiple entries are unioned into the same tables, told apart by source_dataset and gsc_property_name.

OptionRequiredDescription
datasetYesThe bulk export dataset name
gcp_projectNoProject of the dataset - falls back to the current project
gsc_property_nameNoFriendly label, written to the gsc_property_name column. Falls back to project.dataset
brand_termsNoSee Branded queries
brand_terms_regexNoSee Branded queries
brand_terms_soundexNoSee Branded queries
question_wordsNoReplaces the module-level question_words for this property only - see Question queries

Branded Queries​

is_branded_query is TRUE when any of the three brand options of the property matches:

OptionMatching
brand_termsWhole words, case-insensitive. dataform matches "ga4 dataform docs", not "dataforms"
brand_terms_regexRegex patterns, case-insensitive, anywhere in the query
brand_terms_soundexPhonetic: a query is branded if any of its words sounds like a term. dataform also matches "dataphorm". Use single words. SOUNDEX is coarse - check the results before you rely on it

Anonymized queries have no query text, so they are never flagged as branded.

Question Queries​

is_question_query is TRUE when the first word of the query matches a question word (case-insensitive, punctuation ignored).

  • The module-level question_words list applies to every property. The config template ships an English list.
  • A property's own question_words list replaces the module list for that property - for example for a Spanish site.
  • Only single words work - a two-word starter like "por quΓ©" never matches.
  • question_words: [] on a property turns question detection off for it.

Applying Changes to History​

is_branded_query and is_question_query are set when a day is first loaded. After you add a property or change brand terms or question words, update history with one of:

Report Settings​

Each report except the daily trends report has its own settings block. The blocks are plain objects, so you can override one field without repeating the rest:

cannibalization_report:
lookback_days: 30

Set enabled: false in a block to turn off only that report.

search_types restricts a report to specific search types (WEB, IMAGE, VIDEO, NEWS, DISCOVER). The config template sets ["WEB"] for every report. [] means all search types. CTR and position differ a lot between search types - if you include more than one, filter on a single search_type in your dashboard.

cannibalization_report​

OptionDefaultDescription
enabledtrueBuilds this report
lookback_days90Days scanned, counted back from the latest export date
exclude_branded_queriestrueSkip branded queries - several pages ranking for your brand is rarely cannibalization
max_urls_per_query5Competing URLs listed per query (competing_url_count is never capped)
search_types["WEB"]Search types to include

movers_shakers_queries_report​

OptionDefaultDescription
enabledtrueBuilds this report
period_days28Length of each comparison window (last 28 days vs the 28 days before)
exclude_branded_queriestrueSkip branded queries
min_impressions10Minimum impressions in the larger of the two periods
search_types["WEB"]Search types to include

movers_shakers_pages_report​

OptionDefaultDescription
enabledtrueBuilds this report
period_days28Length of each comparison window
exclude_branded_queriesfalseSkip branded queries. Anonymized queries can't be checked, so branded searches inside them still count
exclude_anonymous_queriesfalseDrop anonymized queries from the page totals
min_impressions10Minimum impressions in the larger of the two periods
search_types["WEB"]Search types to include

ctr_benchmark_report​

OptionDefaultDescription
enabledtrueBuilds this report
lookback_days90Days scanned - longer, so each position has enough data
exclude_branded_queriestrueSkip branded queries (they get much higher CTR)
min_impressions5Minimum impressions for a query to enter the curve and the output
min_bucket_sample_size100Minimum impressions in a position bucket before its expected_ctr is trusted
underperformance_threshold0.5A query is flagged when its CTR is below this fraction of the expected CTR
search_types["WEB"]Search types to include

GCS Export​

The GCS_EXPORT block overrides the global cross-cloud export settings for this module only.

Table Structures​

Base Tables​

The base tables are incremental and partitioned by data_date. They keep the grain of the bulk export and add:

ColumnDescription
source_datasetThe export dataset the row came from (project.dataset)
gsc_property_nameThe friendly property name from the configuration
query_normalizedThe query in lowercase, with punctuation collapsed to single spaces - use it to group and join
is_branded_queryThe query matched a brand term
is_question_queryThe query starts with a question word

Build custom analysis on these tables when the reports don't cover your question.

google_search_console_site_impression (incremental)​

Granularity: Same as the export's searchdata_site_impression - per property, date, query, country, device and search type

Property-level search data. Average position = SUM(sum_top_position) / SUM(impressions) + 1.

google_search_console_url_impression (incremental)​

Granularity: Same as the export's searchdata_url_impression - per property, date, URL, query, country, device, search type and search appearance

URL-level search data, including the search appearance flags (is_review_snippet, is_video, is_merchant_listings, ...). Average position = SUM(sum_position) / SUM(impressions) + 1.

Reports​

The reports are full rebuilds on each run, read from the base tables. To run only the reports, use the tag module_google_search_console_reports.

Every report window ends at the latest exported data_date of each property, not at the current date, so the 2-3 day export delay never cuts a window short.

google_search_console_site_impression_report (table)​

Granularity: One row per date, property, branded flag and search type

Daily impressions, clicks, average position and CTR, each with 14, 28 and 56-day trailing averages. Use it for trend charts and to split branded from non-branded traffic. Anonymized queries form their own row with is_branded_query = NULL.

google_search_console_cannibalization_report (table)​

Granularity: One row per property and query

Queries where 2 or more pages get impressions for the same search term. Shows the true number of competing URLs (competing_url_count), the query totals, and the top competing URLs with their clicks, impressions and average position (urls array).

google_search_console_movers_shakers_queries_report (table)​

Granularity: One row per property, query and search type

Compares the last period_days to the period before: impressions, clicks, average position and position bucket (top 3, first page (4-10), second page (11+)) for both periods, plus the absolute and percentage changes. New queries and queries that stopped ranking appear with 0 in one period. A negative position_change is an improvement.

google_search_console_movers_shakers_pages_report (table)​

Granularity: One row per property, URL and search type

The same comparison as the query report, per page, summed over every query that landed on the page. It includes branded and anonymized queries by default, so its totals come closest to the page totals in the Search Console UI.

google_search_console_ctr_benchmark_report (table)​

Granularity: One row per property and query

Builds your site's own expected CTR for each position from its history, then compares each query against it. performance_vs_expected is actual CTR / expected CTR. is_underperforming flags queries below underperformance_threshold. These are usually snippet problems: a weak title or meta description, or a SERP feature that takes the clicks.

Export Monitoring​

google_search_console_exportlog (incremental)​

Granularity: One row per published export (retries included)

The export log of all configured properties. Incremental, not partitioned.

google_search_console_export_delays (view)​

Granularity: One row per property and date

How many hours after the end of the day (Pacific Time) each export arrived, and how many times it was retried.

Common Use Cases​

  1. Branded vs non-branded trends: Track organic growth without brand demand hiding the signal
  2. Cannibalization clean-up: Find pages that compete for the same query and consolidate or re-target them
  3. Weekly SEO review: Spot the queries and pages that gained or lost the most since the previous period
  4. Snippet optimization: Rewrite titles and descriptions of queries that underperform the CTR of their position
  5. Content ideas: Use question queries (is_question_query) to find topics for FAQ and how-to content

Data Studio Template​

warning

We do not (yet) have a Data Studio template for this module.