TrafficLane — GA4 & Search Console to SheetsGoogle Sheets™ add-on · reports free · Pro $4.99/mo · Version 1.0Read the setup guide

How to get Google Analytics 4 and Search Console data into Google Sheets

Updated 12 November 2026 · 6 min read

Short answer: Google Analytics™ 4 and Google Search Console™ can each export a table to Google Sheets™ once, by hand. Nothing in either one keeps that copy up to date. For numbers that refresh, the free way is a short Apps Script: it asks the Google Analytics Data API or the Search Console API for the report, writes the rows into a tab, and a time-driven trigger runs it every morning. An add-on such as TrafficLane does the same without code, for both sources in one panel.

1. The exports built into GA4 and Search Console

Both are fine for a one-off look. Next week, you export again, and paste the new numbers where the old ones were.

Looker Studio™ connects to both GA4™ and Search Console™ and can email a report on a schedule, but what arrives is a dashboard, not rows in your spreadsheet. Teams that already work in BigQuery can send GA4™ and Search Console™ data there and read it into Sheets with Connected Sheets, where their Google Workspace™ edition includes it; that means a Google Cloud project and SQL.

2. The Apps Script way: GA4 top pages into a tab

  1. In your spreadsheet, add a tab named GA4 Top pages, then choose Extensions → Apps Script.
  2. Next to Services on the left, click +, choose Google Analytics Data API and click Add.
  3. Replace the code with the script below. Put in your property ID, the number from GA4 → Admin → Property details, and click Save.
  4. Click Run. The first time, Google asks you to allow the script to see your Google Analytics data and your spreadsheets. Then look at the tab.
function importTopPages() {
  const propertyId = '123456789';                    // GA4 → Admin → Property details
  const report = AnalyticsData.Properties.runReport({
    dateRanges: [{ startDate: '28daysAgo', endDate: 'yesterday' }],
    dimensions: [{ name: 'pagePath' }],
    metrics: [{ name: 'screenPageViews' }, { name: 'sessions' }],
    orderBys: [{ metric: { metricName: 'screenPageViews' }, desc: true }],
    limit: 1000
  }, 'properties/' + propertyId);
  const header = report.dimensionHeaders.map(h => h.name)
    .concat(report.metricHeaders.map(h => h.name));
  const rows = (report.rows || []).map(r =>
    r.dimensionValues.map(v => v.value).concat(r.metricValues.map(v => Number(v.value))));
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('GA4 Top pages');
  sheet.clearContents();
  sheet.getRange(1, 1, rows.length + 1, header.length).setValues([header].concat(rows));
}

The dimension and metric names are the API names, listed in Google’s GA4 Dimensions & Metrics Explorer: date, sessionDefaultChannelGroup, activeUsers, keyEvents and so on. Date ranges take dates such as 2026-10-01, or today, yesterday and NdaysAgo.

3. Search Console from Apps Script

Apps Script has no built-in service for Search Console™, so the script calls its API directly:

function importQueries() {
  const site = 'sc-domain:example.com';              // or 'https://www.example.com/'
  const url = 'https://www.googleapis.com/webmasters/v3/sites/' +
    encodeURIComponent(site) + '/searchAnalytics/query';
  const res = UrlFetchApp.fetch(url, {
    method: 'post',
    contentType: 'application/json',
    headers: { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() },
    payload: JSON.stringify({ startDate: '2026-10-01', endDate: '2026-10-31',
      dimensions: ['query'], rowLimit: 1000 })
  });
  const rows = (JSON.parse(res.getContentText()).rows || [])
    .map(r => [r.keys[0], r.clicks, r.impressions, r.ctr, r.position]);
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Search queries');
  sheet.clearContents();
  sheet.getRange(1, 1, rows.length + 1, 5)
    .setValues([['Query', 'Clicks', 'Impressions', 'CTR', 'Position']].concat(rows));
}

For this one the script needs Search Console’s permission written into its manifest. In Project Settings, tick Show “appsscript.json” manifest file in editor, and add an oauthScopes list with https://www.googleapis.com/auth/webmasters.readonly, https://www.googleapis.com/auth/spreadsheets and https://www.googleapis.com/auth/script.external_request. Once that list is there, Google asks for exactly those permissions.

4. Make it refresh every morning

  1. In the Apps Script editor, click Triggers (the clock icon on the left), then Add Trigger.
  2. Choose the function, such as importTopPages, the event source Time-driven, the type Day timer and a time such as 6am to 7am.
  3. Click Save.

From then on Google runs the script once a day at some point in that hour, while the spreadsheet is closed. A Week timer or Month timer refreshes less often.

5. Where the simple script falls short

None of this is hard on its own. Together, it is a small program to keep up every time someone asks for one more report.

6. With an add-on: TrafficLane

TrafficLane is our Google Sheets™ add-on for this job. It does what the scripts above leave to you:

How to set it up: TrafficLane help.

TrafficLane — GA4 & Search Console to SheetsGA4 and Search Console reports in Sheets, without a script.
Read the setup guide

Questions

Can Google Analytics 4 export to Google Sheets automatically?

Not by itself. An export from a GA4 report is a one-time copy. For a copy that refreshes, you need an Apps Script with a time-driven trigger, or an add-on.

How do I get Search Console data into Google Sheets?

For a one-time copy, use Export in the Performance report, up to 1,000 rows per table. For more rows or a regular refresh, call the Search Console API from Apps Script, or use an add-on.

How many rows can the Search Console API return?

Up to 25,000 rows per request, and more by asking again with startRow. It keeps about 16 months of data.

Why do numbers from the GA4 API differ from the GA4 screens?

Usually because of data thresholds, which hide rows with very few users, or sampling on very large reports. The API says so in the metadata of its answer, which a simple script does not read.

RelatedTrafficLane: GA4 and Search Console reports in Google SheetsTrafficLane helpComparing with an earlier period