Automation

How to automate the Google Sheet behind your Data Studio report

Five ways to keep a report's Google Sheet filled without anyone pasting data, how stale each one can get once Data Studio's own refresh is added, and an Apps Script template that appends instead of overwriting.

Lazarina Stoy·

Automate the Google Sheet behind your Data Studio report

To keep the Google Sheet behind a Data Studio report filled without anyone touching it, give the Sheet its own schedule (an Apps Script time-driven trigger, an import formula, or a connector add-on), and remember that Data Studio adds up to 15 more minutes of caching on top. Which one fits depends on where the data comes from and how stale you can live with.

To automate Google Sheets for a report, you have two jobs: filling the Sheet, and getting Data Studio (formerly Looker Studio) to show what landed. This covers:

  • the two clocks behind every Sheet-backed chart, and how old a number can get
  • five ways to fill a Sheet on a schedule, compared in one table
  • an Apps Script that appends and skips duplicates instead of wiping the tab
  • the Sheet rules that stop the data source breaking, and what to check when the numbers stop moving

Connecting a Sheet in the first place is in my guide to connecting Google Sheets to Data Studio. The evidence here is Google’s documentation (read 13 October 2026), vendor pages and Google’s Data Studio forum. The intervals are theirs; I haven’t run a timing test.

How a Sheet-backed report actually updates

Google says two things about Sheets data sources that sound contradictory and are both true:

  1. Data Studio checks the Sheet for changed values and new rows every time a query runs on a report that uses it.
  2. It also caches queries for the data freshness interval: 15 minutes by default for Google Sheets, adjustable to 1, 4 or 12 hours.

The trick is the word query. Data freshness is how long Data Studio may answer a chart from memory. A query it has seen within that window gets the remembered answer; a new one (a different date range, a new filter, a chart nobody has loaded yet) goes to the Sheet. Google promises the data “won’t be older than” the setting, not that it stays cached for all of it.

Left: five things that fill a Sheet and their intervals. Middle: the Data tab. Right: Data Studio's cache at 15 minutes by default, where new queries read the Sheet and repeated ones can come from memory
Two clocks: whatever fills the Sheet, then Data Studio’s freshness on top.

The worst case is the two clocks added together. A few details change who sees what:

  • Credentials. With owner’s credentials, every viewer shares one freshness clock; with viewer’s credentials, each viewer has their own (data sources and credentials covers the choice).
  • Blends take the shortest freshness of their sources.
  • Refresh data. Editors can press it any time (More options → Refresh data), viewers only if allowed, with a one-minute cooldown. The last refresh time sits bottom left.
  • Embeds. Embedded viewers can’t refresh; the report updates when the window runs out.


Caching across every connector is in why your Data Studio report shows yesterday’s numbers. For a Sheet, Data Studio is rarely the slow clock. Whatever fills the Sheet usually is.

Five ways to fill a Sheet on a schedule, compared

Formulas and Apps Script are free and built in. Connector add-ons are the practical answer for non-Google ad platforms. Zapier, Make and n8n suit data that arrives one event at a time. Connected Sheets only makes sense if the data already lives in BigQuery.

Route Fills from Cost Schedule options Runs as Worst case with Data Studio’s 15 min Where it breaks
IMPORTRANGE, IMPORTDATA Other Sheets; a CSV or TSV URL Free None you set: Google recalculates (30 min to 1 h) The document’s creator (for limits) IMPORTRANGE 45–75 min, IMPORTDATA 75 min; Google describes IMPORTRANGE updating while the Sheet is open Nobody opens the Sheet; “Loading…” errors
Apps Script trigger Any API or CSV you can reach by URL Free, within quotas Every 1 min to once a month Whoever created the trigger 75 min hourly; 24 h 15 min daily Owner leaves; quota; script errors
Connector add-on Ad platforms, CRMs, shops Paid plans; some free tiers Set by the plan: daily, hourly, 15 min Your account’s access 30 min to 24 h 15 min, by plan Plan limits on refresh and rows
Zapier, Make, n8n Events (a lead, an order) or a scheduled call Plan-based Zapier hourly to monthly; Make 15 min by default; n8n down to seconds or cron The workflow’s connected account 30 min (Make default); 75 min (Zapier hourly) “Update range” steps that overwrite
Connected Sheets BigQuery BigQuery billing Scheduled refresh Whoever set the schedule Depends on the schedule Pauses if someone else edits the data source

Intervals from Google’s Sheets, Apps Script and Connected Sheets help, Zapier’s, Make’s and n8n’s docs, and each vendor’s plan page, read 13 October 2026. “Worst case” is the fill interval plus Data Studio’s default freshness: arithmetic, not a measurement.

Horizontal bars of the documented worst-case age per route: 30 minutes for 15-minute schedules, 45 to 75 for IMPORTRANGE, 75 for hourly routes, 2 hours 15 for Funnel.io Business, and 24 hours 15 for anything daily
Arithmetic from documented intervals, not a measurement.

Formulas: IMPORTRANGE, IMPORTDATA and a QUERY roll-up

The quickest automation there is needs no code: one Sheet that pulls from others. IMPORTRANGE imports a range from another spreadsheet, IMPORTDATA imports a CSV or TSV from a URL, and QUERY filters and tidies the result. Google itself recommends giving Data Studio a separate worksheet filled by functions like QUERY, which is exactly this.

A common setup, and the answer to a 2024 thread on Google’s forum from someone adding a new Sheet every week: a roster of client Sheets, stacked into one tab.

Tab "Roster":  A = client, B = spreadsheet URL, C = range (e.g. Data!A2:F)

Tab "Rollup", cell A2 (headers typed in row 1):
=QUERY({
  IMPORTRANGE(Roster!B2, Roster!C2);
  IMPORTRANGE(Roster!B3, Roster!C3);
  IMPORTRANGE(Roster!B4, Roster!C4)
}, "select * where Col1 is not null", 0)

Tab "Feed", cell A1 (a published CSV):
=IMPORTDATA("https://example.com/export.csv")

The braces stack the ranges, and QUERY drops the blank rows open-ended ranges drag in. Every source needs the same columns in the same order, and the first import from each asks you to Allow access.

Now the catch. Google describes IMPORTRANGE’s refresh in terms of an open document: it “automatically checks for updates every hour while the document is open”, and reloads when the document is first opened or was opened in the past five minutes. Google’s calculation-settings page (File → Settings → Calculation) gives a different number for the same function: 30 minutes for IMPORTRANGE, an hour for IMPORTDATA.

What neither page says is what happens when nobody has the Sheet open and Data Studio queries it. A user on Reddit (around 2023) reported having to open the Sheet first, let the formulas refresh, then open the report. It’s one person’s report, unconfirmed by Google or by me, but enough that I wouldn’t rely on formulas for a Sheet nobody opens. Use something that writes values: a script or an add-on.

The same roll-up suits an annotations tab several people maintain (adding annotations to Data Studio charts).

Apps Script: pull an API or CSV on a timer, append, don’t overwrite

Apps Script is the JavaScript that lives inside Google Sheets (Extensions → Apps Script), and a time-driven trigger runs a function on a schedule, as often as every minute or as rarely as once a month. It’s the free, unattended route, and it writes values, so nobody needs to open the Sheet.

A common pattern in scripts online clears the sheet each run, then writes today’s pull. Simple, with three side effects: history older than the API’s window disappears, the tab is empty mid-run (exactly when a Data Studio query might arrive), and the row count jumps around under the report. Appending is barely more code.

Left: a tab cleared and rewritten each run, empty mid-run and left with only today's rows. Right: existing rows untouched, two new days added below, duplicates skipped and a log row written
Append below, skip rows whose key is already there, and log every run.

Set it up, step by step

  1. Copy the starter Sheet (box below), or paste the script into your own Sheet via Extensions → Apps Script.
  2. Fill in the Config tab: source URL (CSV or JSON), the key columns that make a row unique (say, date,campaign), and the schedule.
  3. Run setup() once and accept the permissions prompt. It writes the Data headers and installs the trigger.
  4. Or install the trigger by hand: Triggers (left) → Add Trigger → run, time-driven, hour timer. Or in code: ScriptApp.newTrigger('run').timeBased().everyHours(1).create().
  5. Check it ran: the editor’s Executions list, and the Log tab (fetched, appended and skipped rows per run).
  6. Connect the Data tab to Data Studio (how to connect a Sheet) and the Health tab for a “last updated” scorecard.

The core of the script

Written from Google’s docs, not tested here. The full version, with setup(), CSV and JSON parsing, and removeTriggers(), is in the starter Sheet.

function run() {
  var lock = LockService.getScriptLock();
  if (!lock.tryLock(30000)) return;            // a previous run is still going
  var t0 = Date.now();
  try {
    var cfg = readConfig_();                   // from the Config tab
    var records = fetchRecords_(cfg);          // UrlFetchApp + parseCsv / JSON.parse
    var data = SpreadsheetApp.getActive().getSheetByName('Data');
    var headers = data.getRange(1, 1, 1, data.getLastColumn()).getValues()[0];
    var keyIdx = cfg.keys.map(function (k) { return headers.indexOf(k); });

    var seen = {}, n = data.getLastRow() - 1;  // keys already in the tab
    if (n > 0) {                               // read only the key columns
      var cols = keyIdx.map(function (i) { return data.getRange(2, i + 1, n, 1).getValues(); });
      for (var r = 0; r < n; r++) {
        seen[cols.map(function (c) { return keyPart_(c[r][0]); }).join('|')] = true;
      }
    }

    var out = [], skipped = 0, now = new Date();
    records.forEach(function (rec) {
      var row = headers.map(function (h) {
        return h === 'imported_at' ? now : (rec[h] == null ? '' : rec[h]);
      });
      var key = keyIdx.map(function (i) { return keyPart_(row[i]); }).join('|');
      if (seen[key]) { skipped++; return; }
      seen[key] = true;
      out.push(row);
    });

    if (out.length) {                          // one batch write, below the last row
      data.getRange(data.getLastRow() + 1, 1, out.length, headers.length).setValues(out);
    }
    log_(records.length, out.length, skipped, (Date.now() - t0) / 1000, 'OK', '');
  } catch (e) {
    log_(0, 0, 0, (Date.now() - t0) / 1000, 'ERROR', String(e.message || e));
    throw e;                                   // so Apps Script emails the failure
  } finally {
    lock.releaseLock();
  }
}

Four details do the work. muteHttpExceptions: true makes UrlFetchApp.fetch return an error response instead of throwing, so the script checks the status and retries once. LockService stops runs overlapping. One setValues call writes every new row. And re-throwing keeps Apps Script's failure email: a failed trigger shows nothing on screen, but Google emails a "Summary of failures for Apps Script" with a link to fix it.

Two caveats. A trigger runs under the account of whoever created it, invisible to everyone else, so use an account that won't leave. And it isn't to the minute: a 9 AM trigger fires between 9 and 10 AM, then keeps that time.

How far the free quota stretches

Quota Free Google account Google Workspace What it means for a scheduled import
Script runtime 6 min per execution 6 min per execution Each run must finish in 6 minutes
Triggers total runtime 90 min / day 6 hr / day Hourly, free: 3.75 min per run on average. Every 15 min: about 56 s (Workspace: 3.75 min)
URL Fetch calls 20,000 / day 100,000 / day Every 5 min on a free account: at most 69 fetches per run
Triggers 20 per user per script Plenty for one import
URL Fetch response size 50 MB per call Page through big exports

From Google's Apps Script quotas page, read 13 October 2026. Google says limits can change without notice. Per-run budgets are the daily total divided by runs per day.

For a daily or hourly pull of marketing data, that's plenty. Every minute (everyMinutes(1)) leaves a free account under four seconds per run.

Connector add-ons that write to Sheets on a schedule

For Meta, LinkedIn, TikTok or Shopify data there's no native Google route into a Sheet, so a connector add-on (a vendor's Sheets extension that pulls a platform into a tab on a schedule) is the practical answer.

Vendor Sheets refresh by plan Entry price Free plan or trial Workspace add-on rating
Coupler.io Free: manual · Starter and Active: daily · Pro: hourly · Custom: every 15 min Starter $32/mo billed monthly, $24/mo billed annually Free plan (100 rows per run); 7-day trial at Pro limits 4.8 from 277 ratings
Windsor.ai Basic: daily · Standard and Plus: daily or hourly · Professional: also every 15 min Basic $23/mo billed monthly, $19/mo billed annually Forever Free: 1 source, 1 account 4.41 from 27 ratings
Supermetrics Add-on listing: monthly, weekly, daily or hourly refreshes (not tied to plans on the pricing page) Starter from €39/mo billed yearly (EU view; varies by region). Data Studio and Sheets is a destination extra Not checked for this post 4.41 from 950 ratings
Catchr Scheduled export exists; frequency not published Starter $24/mo billed monthly, or $239/yr 14-day trial 3.55 from 11 ratings
Porter Metrics Hourly, daily or weekly $15 per account/mo billed monthly, $12.50 billed annually, falling with volume Free plan after a 14-day trial 3.3 from 10 ratings
Funnel.io Starter: daily · Business and Enterprise: every 2 hours Starter from €280/mo billed annually None advertised (demo-led) —

Prices and limits from each vendor's pricing page and Google Workspace Marketplace listing, checked 13 October 2026. USD and EUR as each vendor publishes them; no conversion.


Supermetrics' pricing page carried a refresh row on 9 September 2026 saying weekly, daily and hourly refreshes were "(Google Sheets only)"; on 13 October that row is gone. Whether the limits behind it changed, the page doesn't say. And permissions: the Sheets add-ons from Supermetrics, Windsor.ai and Catchr ask to run when you're not present and to see all your spreadsheets. Scheduled refreshes need that, but know it before installing on a shared account.

If Data Studio is the only destination, ask whether you need the Sheet at all: most of these vendors also connect to Data Studio directly. The Sheet earns its place for history you control, joins with your own columns and manual notes. See Data Studio connectors compared, Porter vs Windsor vs Supermetrics and Supermetrics pricing.

Zapier, Make and n8n: when rows should arrive on an event

Workflow tools shine when each new thing (a lead, an order, a form) should become one row. For "pull yesterday's metrics", they're a scheduler around an API call, which Apps Script does free.

Tool Schedule options What counts against the plan Note
Zapier Schedule by Zapier: every hour, day, week or month, plus custom intervals The schedule trigger itself doesn't count toward task usage Hourly + 15 min freshness = 75 min worst case
Make (make.com) Every 15 minutes by default The minimum interval depends on the plan Default + 15 min freshness = 30 min
n8n Seconds, minutes, hours, days, weeks, months, or a cron expression — The most flexible schedule of the three

From Zapier's Schedule help, Make's scheduling help and n8n's Schedule Trigger docs, read 13 October 2026.

The append rule applies here too: map the step to "add a row", not "update a range".

Connected Sheets, and when the Sheet should be BigQuery instead

Connected Sheets runs BigQuery queries from inside a Sheet, on request or on a schedule, and saves the results there. It needs Google Cloud access, BigQuery access and a project with billing (or a BigQuery trial). A scheduled refresh runs as the person who set it up, and it pauses if someone else adds or updates a data source. Extracts are capped at 500,000 rows or 5 million cells.

But if the data is already in BigQuery, Data Studio can read it directly, so the Sheet only earns its place for people who work in the spreadsheet. And if an append-only tab is heading for millions of cells, move the table to BigQuery.

Signs the Sheet has become the wrong layer

  • Size: a Sheets file holds up to 20 million cells, so a 20-column tab alone in the file tops out at 1,000,000 rows.
  • Many writers on one tab.
  • Joins rebuilt in every report.

Sheet rules that keep Data Studio from breaking

Automation changes the Sheet with nobody looking, so every rule here keeps the structure fixed and lets only rows change. Data Studio doesn't detect schema changes: an added, removed, renamed or reordered column needs Refresh fields (edit the data source, Refresh fields bottom left, Apply). On Google's forum in 2024, one edit to one column's formula broke around 30 reports; Google staff's answer: refresh the fields whenever the Sheet changes.

Rule What breaks in Data Studio if you ignore it Google's source
One header row, frozen Field names come from the first row (with "Use first row as headers" on); a second header row becomes data Sheets connector notes
One type per column; dates with day, month and year Mixed columns get the wrong type; text dates don't work with date ranges Connector notes; Sheets data source tutorial
Values, not formula errors A #N/A from a lookup reaches the chart as-is. Wrap lookups in IFERROR (a fix suggested on Google's forum, December 2025) Connector notes: cells hold data only
No merged cells, no totals rows Merged cells may make data appear incorrectly; totals get summed again Connector notes; tutorial
Append below; never insert, rename or move a column A renamed field is treated as removed plus new; charts using it show a configuration error until Refresh fields, and it can't be undone Refresh data source fields
Changed a column's type? Reconnect Refresh fields doesn't detect a changed type Refresh data source fields
A dedicated tab nobody types in One stray edit is a schema change. Google recommends a separate worksheet for the data Data Studio reads Sheets data source tutorial
The whole tab, or an open-ended range The connector's optional range (e.g. A1:Z26) ignores rows below it Connector options
Watch the 20 million cells That's the file limit, for every tab together; an append-only tab grows towards it every run Google Drive file limits

From Google's Sheets connector, Refresh data source fields and Drive file limits pages, read 13 October 2026.


Google also says long beats wide: a row per day, not a column per day. The formatting basics are in the connection guide; the starter Sheet has these rules as a checklist.

When the numbers stop updating: what to check, in order

Check the filler first, then the structure, then the cache, then access. Of the eleven threads I read for this piece, four were a Sheet that changed and broke the report, four were a report not showing new data, and two were platform problems Google fixed.

A flowchart of four yes-or-no checks in order: did the fill fail, did a column change, is the report's timestamp older than the Sheet's last write, has the data source lost access, then Google's forum
The first yes points to the fix.
Symptom Likely cause Fix
The Sheet stopped filling after someone left The trigger ran under their account Recreate it from an account that stays (report ownership)
Runs start failing later in the day The daily Apps Script quota is used up Run less often, or batch the fetches
IMPORTRANGE cells say "Loading…" Too many import functions across the creator's Sheets Fewer imports, or a script
Charts show a configuration error A column was renamed, moved or deleted Refresh fields, then fix the charts
A metric shows zero or the wrong type The column's type changed Reconnect the data source
Totals are double what they should be A totals row in the data Remove it; let Data Studio do the sums
The Sheet won't connect at all A shared drive (below), or a different Google account Move it to My Drive; use the same account in Drive and Data Studio

On that shared-drive row: Google's connector page says "Data Studio does not support accessing files on Team Drive" (the old name for shared drives). The line has no date of its own; the page was updated 9 October 2026.

And sometimes it isn't you. In January 2025, Google staff confirmed on their forum that Sheets data sources were showing wrong data across reports, and fixed it the next day. Look there before rebuilding anything. To spot all this early, add a data health page to client reports; the starter's Health tab is built to feed one. Chapter 24 of my ebook, Data Storytelling in Data Studio, covers how a health page carries a report's caveats, and how to show the reader how old a number is.

Where to go next

Frequently asked questions

How often does Data Studio refresh Google Sheets data?

A query Data Studio hasn't run before reads the Sheet. Repeated queries can come from memory for up to 15 minutes by default, adjustable to 1, 4 or 12 hours.

Do IMPORTRANGE formulas update if nobody opens the sheet?

Google documents updates while the file is open, not when it's closed. For unattended Sheets, use Apps Script or an add-on, which write values.

Why did my report break after I edited the Sheet?

A column was added, renamed or moved. Edit the data source and click Refresh fields.

How many rows can a Sheet hold for Data Studio?

The file limit is 20 million cells or 100 MB. Google documents no separate row limit for the Sheets connector.

Do I need a paid connector to automate a Sheet?

Not for Google data or any API or CSV you can reach by URL. For Meta, LinkedIn, TikTok and similar platforms, in practice, yes.

Shopping Cart
Scroll to Top