appscript.dev
Automation Beginner Slides Sheets

Extract all deck text into a sheet

Pull text out of every slide for review, translation, or copy-editing.

Published Jan 4, 2026

Northwind decks tend to grow in two directions at once — new slides at the back, tweaks throughout the middle — and the copy inside them quietly drifts away from the brand voice document. Editing in the deck is fiddly: shapes overlap, fonts shift, and reviewing 40 slides means clicking into every text box. What the copy editor actually wants is the words in a single column they can read top to bottom, mark up in place, and hand back.

This script flattens a deck into a sheet. One row per text box, with the slide number and the shape’s object ID alongside the text, so once edits come back you know exactly which shape on which slide to update. It is the first half of a round-trip translation or copy-edit workflow — pair it with a sister script that writes the edited column back into the deck.

What you’ll need

  • A Google Slides deck whose text you want to extract.
  • A Google Sheet to receive the rows — the script writes to the first tab.
  • Nothing else — both files just need to be readable by you.

The script

// The columns the script writes. Keep these names if you plan to round-trip
// edits back into the deck — a sister script can look them up by header.
const HEADERS = ['Slide', 'ShapeId', 'Text'];

/**
 * Walks every shape in every slide of a deck and writes the text into the
 * first tab of the given spreadsheet. One row per non-empty text box.
 *
 * @param {string} deckId  The Slides file ID.
 * @param {string} sheetId The Spreadsheet to write rows into.
 */
function extractDeckText(deckId, sheetId) {
  if (!deckId || !sheetId) {
    throw new Error('extractDeckText needs both a deckId and a sheetId.');
  }

  const deck = SlidesApp.openById(deckId);
  const rows = [];

  // 1. Walk every slide, every shape, and collect non-empty text.
  deck.getSlides().forEach((slide, slideIndex) => {
    for (const shape of slide.getShapes()) {
      // Not every shape is a text container — images, lines, and tables
      // don't have a `.getText()` method, so skip those defensively.
      if (typeof shape.getText !== 'function') continue;

      const text = shape.getText().asString().trim();
      if (!text) continue;

      // Slide number is 1-based for humans; object ID is the stable
      // identifier the round-trip script will use to find the shape again.
      rows.push([slideIndex + 1, shape.getObjectId(), text]);
    }
  });

  // 2. Reset the destination sheet — easier to reason about than diffing.
  const sheet = SpreadsheetApp.openById(sheetId).getSheets()[0];
  sheet.clear();
  sheet.getRange(1, 1, 1, HEADERS.length).setValues([HEADERS]);

  if (!rows.length) {
    Logger.log('Deck has no text shapes — nothing to write.');
    return;
  }

  // 3. Single batch write — much faster than one row at a time.
  sheet.getRange(2, 1, rows.length, HEADERS.length).setValues(rows);
  sheet.setFrozenRows(1);

  Logger.log(`Extracted ${rows.length} text shapes from deck ${deckId}.`);
}

/**
 * Convenience wrapper so you can click Run in the editor without writing a
 * caller. Replace the IDs with your own.
 */
function extractNorthwindDeck() {
  extractDeckText('1abcDeckId', '1abcSheetId');
}

How it works

  1. extractDeckText first guards against missing IDs — running the script from the editor with no arguments would otherwise throw a less helpful error deep inside SlidesApp.
  2. It opens the deck and iterates every slide. For each slide it walks every shape, checking that the shape supports getText — images, lines, and tables don’t, and calling it on them would crash the loop.
  3. For each text shape it reads the string, trims it, and skips empty boxes. Empty placeholders are common in templates and would just create blank rows in the sheet.
  4. It records the 1-based slide number, the shape’s objectId, and the trimmed text. The object ID is the stable handle a round-trip editor would use to write changes back to the right shape.
  5. It clears the destination sheet, writes the header row, and writes all the collected rows in one batched setValues call — far quicker than appending one row at a time.
  6. It freezes the header row so the columns stay labelled when the editor scrolls through a long deck’s worth of text.

Example run

Say 1abcDeckId is a five-slide Northwind pitch. After one run, the sheet looks like this:

SlideShapeIdText
1g123abcNorthwind Studio
1g123defBespoke creative for ambitious brands
2g456abcWhat we do
2g456defStrategy, design, production — all under one roof.
3g789abcSelected work
4g321abcOur process
5g654abcLet’s talk

The copy editor can now read the deck end-to-end, mark up the Text column in place, and hand it back. A round-trip script uses the ShapeId to find each shape again and overwrite its text.

Run it

This is an on-demand job — you run it whenever a deck is ready for review:

  1. In the Apps Script editor, select extractNorthwindDeck and click Run.
  2. Approve the authorisation prompt the first time.
  3. Open the destination sheet to read or edit the extracted text.

If you regularly extract from a folder full of decks, wrap the call in a loop over DriveApp.getFolderById(...).getFiles() and write each deck to its own tab — but for one-off review work, the editor button is enough.

Watch out for

  • Grouped shapes are tricky. A group is itself a shape but its children carry the text — if a slide uses groups heavily, walk shape.getChildren() when the shape type is GROUP instead of skipping it.
  • Tables are skipped by the typeof getText check. If your decks use tables for content, add a branch that iterates shape.asTable().getCell(...) and records each cell separately.
  • Speaker notes are not extracted. They live on slide.getNotesPage(), not on the slide’s shapes — if your reviewer needs the script too, fetch them in a second pass and add a Notes row per slide.
  • The sheet is cleared on every run. If a reviewer has already marked it up, copy the marked-up text out before extracting again or you’ll lose their edits.

Related