// Slides · Sheets · Apps Script

Insert a linked Sheets chart into a slide in Google Slides.

Use Apps Script to insert a linked Sheets chart into a Google Slides presentation and keep it current with a refresh trigger — because insertSheetsChart() only captures the chart at insertion time.

I want to insert a chart from Google Sheets into a Slides deck via Apps Script and have it reflect updated data without re-inserting it every time.

The script

copy · paste · trigger
refreshLinkedCharts.gs
Apps Script
// Insert a Sheets chart onto slide 1, then refresh all linked charts.
// Run insertChart() once; schedule refreshAllCharts() on a time trigger.

function insertChart() {
  var ss = SpreadsheetApp.openById('YOUR_SPREADSHEET_ID');
  var sheet = ss.getSheetByName('Dashboard');
  var chart = sheet.getCharts()[0];

  var pres = SlidesApp.openById('YOUR_PRESENTATION_ID');
  var slide = pres.getSlides()[0];

  slide.insertSheetsChart(chart, 50, 100, 600, 371);
  pres.saveAndClose();
}

function refreshAllCharts() {
  var pres = SlidesApp.openById('YOUR_PRESENTATION_ID');
  var slides = pres.getSlides();
  for (var i = 0; i < slides.length; i++) {
    var charts = slides[i].getSheetsCharts();
    for (var j = 0; j < charts.length; j++) {
      charts[j].refresh();
    }
  }
  pres.saveAndClose();
}

Need a variant? Gnaw writes a custom version from one sentence — fields, triggers, edge cases handled.

Walkthrough

What insertSheetsChart() actually gives you

When you call slide.insertSheetsChart(chart, x, y, width, height), Apps Script embeds the chart as a linked image. The link tracks which Sheets chart object it came from, but the visual is a snapshot taken at that exact moment. The spreadsheet can update a hundred times and the slide will not notice.

The five parameters after the chart object are left offset, top offset, width, and height — all in points (1 point = 1/72 inch). A common 16:9 slide is 720 × 405 points total, so a 600 × 371 chart centered with a small margin is a reasonable starting default. Getting this wrong produces a chart that looks fine in the editor and blurry in a presentation because it was inserted at 200 × 100 and scaled up.

sheet.getCharts() returns an array of EmbeddedChart objects in the order they were created. If your sheet has multiple charts, index carefully. I keep a single named chart per dashboard sheet to avoid index drift when someone adds a decorative sparkline.

The refresh loop you actually need

SheetsChart.refresh() re-fetches the chart image from the source spreadsheet. It is the only way to move new data into an already-inserted chart short of deleting and re-inserting it. The pattern is: getSlides(), loop slides, getSheetsCharts() on each, call refresh() on each result.

getSheetsCharts() returns only the linked Sheets charts on a given slide, not static images or other shape types. If refresh() returns nothing and your chart is visually unchanged, confirm it is actually linked: open the deck manually, click the chart, and check whether a Sheets link icon appears in the toolbar. A chart pasted as an image has no link and cannot be refreshed.

The first time I hit this on a weekly KPI deck, the refresh silently did nothing because the chart had been copy-pasted rather than inserted via the API. The fix was to delete the manual paste and run insertChart() once from the script, after which refresh() worked on every subsequent trigger run.

Setting a time-based trigger

In the Apps Script editor, go to Triggers (the clock icon), add a trigger for refreshAllCharts, set it to Time-driven, and pick your interval. Hourly is usually sufficient for business dashboards. The trigger runs under your account's quota: Apps Script gives you 6 minutes of total execution time per run and 90 minutes per day on the free tier, so a deck with 40 charts across 20 slides refreshing every 15 minutes will eventually hit the ceiling.

If you need the refresh to run on a schedule from a Sheets-side script (for example, tied to a data-import trigger), the same refreshAllCharts() function can be called from there — just open the presentation by ID from within the Sheets-bound script. The authorization scope required is https://www.googleapis.com/auth/presentations, which Apps Script requests automatically when it detects SlidesApp usage.

saveAndClose() at the end of refreshAllCharts() is not strictly required when the presentation is opened by ID rather than getActivePresentation(), but it is good practice: it flushes pending changes and releases the lock. Omitting it occasionally leaves a ghost lock that blocks the next trigger run for a minute while Apps Script times it out.

Want a custom version?

Describe your sheet and the rule you want. Gnaw writes the Apps Script — fields, triggers, edge cases — in one shot.

FAQ

4 questions
Why does my chart still show old data after calling refresh()?
The chart is probably not linked. If it was pasted manually or inserted as an image rather than via insertSheetsChart(), getSheetsCharts() returns it but refresh() has no source to pull from and silently no-ops. Delete it, run insertSheetsChart() via the script, and try again.
Can I insert a chart from a different Google account's spreadsheet?
Only if the running account has at least Viewer access to that spreadsheet. Apps Script uses the OAuth identity of the account that authorized the script. Cross-domain sharing works as long as the permissions are set; there is no API-level restriction beyond that.
How do I target a specific chart on the sheet instead of index 0?
Call sheet.getCharts() and filter by chart.getOptions().get('title'). Chart titles are set in the Sheets chart editor under Chart & axis titles. This is more stable than numeric indexing when the sheet might gain extra charts over time.
Does refresh() count against Apps Script quotas?
Yes. Each refresh() call is a Slides API write operation. On the free Apps Script tier the ceiling is 1,000 write operations per day across all scripts in your account. A deck with 10 charts refreshed hourly for 12 hours is 120 operations, well within limits, but large decks on tight schedules can exhaust it.