appscript.dev
Automation Advanced Slides

Build a deck accessibility checker

Flag missing alt text, low contrast, and tiny fonts across a Northwind deck.

Published Dec 14, 2025

A deck that looks polished can still be unreadable for part of its audience. An image with no alt text is silent to a screen reader; a 9pt caption disappears from the back of a room. Northwind’s pitch decks went out the door looking fine on the designer’s monitor — and nobody checked whether they actually worked for everyone.

This script audits a deck for the two accessibility problems that are easy to miss and easy to fix: images with no alt text, and text set below a legible size. It walks every slide and returns a plain list of what to correct, so an accessibility pass becomes a two-minute job instead of a slide-by-slide hunt.

What you’ll need

  • The file ID of the Google Slides deck you want to check — the long string in its URL.
  • Edit or view access to that deck so SlidesApp can open it.
  • Nothing else — the script only reads the deck and reports; it makes no changes.

The script

// The smallest font size, in points, that counts as legible.
const MIN_FONT_SIZE = 14;

/**
 * Audits a Slides deck for accessibility problems and returns
 * a list of human-readable issue strings.
 *
 * @param {string} deckId  The file ID of the deck to check.
 * @return {string[]}      One entry per issue found.
 */
function checkAccessibility(deckId) {
  const issues = [];
  const deck = SlidesApp.openById(deckId);
  const slides = deck.getSlides();

  // Guard: an empty deck has nothing to audit.
  if (!slides.length) return issues;

  slides.forEach((slide, i) => {
    const slideNumber = i + 1;

    // 1. Every image should carry alt text for screen readers.
    //    Slides stores it as the image description, with title as a fallback.
    for (const image of slide.getImages()) {
      const alt = image.getDescription() || image.getTitle();
      if (!alt) {
        issues.push(`Slide ${slideNumber}: image missing alt text`);
      }
    }

    // 2. Text below the minimum size is hard to read from a distance.
    for (const shape of slide.getShapes()) {
      const text = shape.getText();

      // Skip empty shapes — there is no text to size-check.
      if (!text.asString().trim()) continue;

      const size = text.getTextStyle().getFontSize();
      if (size && size < MIN_FONT_SIZE) {
        issues.push(`Slide ${slideNumber}: tiny font (${size}pt)`);
      }
    }
  });

  return issues;
}

/**
 * Convenience wrapper: checks one deck and logs the result.
 */
function logAccessibility() {
  const issues = checkAccessibility('1abcDeckId');
  Logger.log(issues.length ? issues.join('\n') : 'No accessibility issues.');
}

How it works

  1. checkAccessibility opens the deck by ID and collects its slides. If the deck has no slides it returns an empty list straight away.
  2. It walks each slide, tracking a 1-based slide number for readable messages.
  3. For every image on the slide it reads the description, falling back to the title. An image with neither is flagged as missing alt text — the thing a screen reader needs to describe it.
  4. For every shape it reads the text. Empty shapes are skipped so a blank placeholder never produces a false flag.
  5. It reads the shape’s font size and, if a size is set and it falls below MIN_FONT_SIZE (14pt), records a “tiny font” issue with the exact size.
  6. The collected issues are returned as a flat list of strings. logAccessibility is a wrapper that runs the check on one deck and prints the result.

Example run

Running the checker against a six-slide deck might log:

Slide 2: image missing alt text
Slide 4: tiny font (10pt)
Slide 4: image missing alt text
Slide 6: tiny font (9pt)

That is the to-do list: add descriptions to the images on slides 2 and 4, and bump the small captions on slides 4 and 6 up to at least 14pt. A clean deck logs No accessibility issues. instead.

Run it

This is an on-demand check, run before a deck ships:

  1. Paste the script into a standalone Apps Script project.
  2. Set the deck ID in logAccessibility (or pass it to checkAccessibility directly).
  3. Select logAccessibility in the editor, click Run, and approve the authorisation prompt the first time.
  4. Read the issues in the execution log, fix them in the deck, and re-run to confirm a clean result.

Watch out for

  • The font check only sees a shape’s first run style. If one text box mixes a 12pt line with a 24pt heading, only the leading run’s size is tested — split the shape or iterate the runs for full coverage.
  • Despite the description, this version does not measure colour contrast. SlidesApp can read foreground colours, but background contrast needs the fill behind the text — add that check if low-contrast text is a real risk.
  • Decorative images legitimately have no alt text. The checker cannot tell a decorative image from a meaningful one, so expect a few flags you will consciously ignore.
  • It reads tables as shapes but does not descend into individual table cells, so small text inside a table can slip through.
  • Large decks mean many getImages and getShapes calls. A deck of 100+ slides may approach the Apps Script execution time limit — check decks one at a time.

Related