appscript.dev
Automation Intermediate Slides Drive

Swap logos and branding across decks

Replace logo assets across every Northwind deck when branding changes — old logo out, new logo in.

Published Nov 2, 2025

Northwind rebrands every few years and the side effect everyone forgets is the back catalogue of decks. Sales has a folder of pitches, marketing has case studies, the leadership team has board updates — all of them carry the old logo in the top-left corner of every slide. Updating by hand means opening each deck, clicking the logo on each slide, replacing the image, and getting the position close enough. A 30-deck library is a week of work.

This script does the swap in one pass. It walks every Slides file in a Drive folder, finds the image in the top-left corner of each slide — that’s where the logo lives in the Northwind template — and replaces it with the new logo in place. Position and size are preserved because image.replace() swaps the bytes without moving the frame. It is the kind of script you write once and run on every rebrand.

What you’ll need

  • A Drive folder containing the decks to update. Sub-folders are ignored — flatten or run per folder.
  • The new logo as a file in Drive (PNG or JPG). The script reads it as a blob and reuses it across every replacement.
  • The position rule that identifies your logo. The Northwind template puts it at roughly top < 50, left < 100; adjust the constants if yours differs.

The script

// Position rule for "this image is the logo". Anything in the top-left
// rectangle with these EMU bounds gets swapped. Tune to your template.
const LOGO_MAX_TOP = 50;
const LOGO_MAX_LEFT = 100;

/**
 * Walks every Google Slides file in a folder and replaces logo-shaped
 * images with a new logo. Position is identified by top-left bounds; size
 * and frame are preserved because image.replace() swaps the bytes only.
 *
 * @param {string} folderId   The Drive folder of decks to update.
 * @param {string} newLogoId  The Drive file ID of the new logo (PNG/JPG).
 */
function swapLogos(folderId, newLogoId) {
  if (!folderId || !newLogoId) {
    throw new Error('swapLogos needs both a folderId and a newLogoId.');
  }

  // 1. Read the new logo once, reuse the blob for every replacement.
  const newLogo = DriveApp.getFileById(newLogoId).getBlob();

  const files = DriveApp.getFolderById(folderId)
    .getFilesByType(MimeType.GOOGLE_SLIDES);

  let decksTouched = 0;
  let imagesSwapped = 0;

  while (files.hasNext()) {
    const file = files.next();
    const deck = SlidesApp.openById(file.getId());
    let swappedInDeck = 0;

    // 2. Walk every slide, every image, and apply the position rule.
    for (const slide of deck.getSlides()) {
      for (const image of slide.getImages()) {
        // The logo lives in the top-left corner of the template. Anything
        // outside that rectangle is content — leave it alone.
        if (image.getTop() < LOGO_MAX_TOP && image.getLeft() < LOGO_MAX_LEFT) {
          // 3. replace() swaps the underlying bytes without touching the
          //    frame, so the new logo lands at the same size and position.
          image.replace(newLogo);
          swappedInDeck++;
        }
      }
    }

    if (swappedInDeck > 0) {
      decksTouched++;
      imagesSwapped += swappedInDeck;
      Logger.log(`${file.getName()}: swapped ${swappedInDeck} logo(s).`);
    }
  }

  Logger.log(`Done — touched ${decksTouched} decks, swapped ${imagesSwapped} logos.`);
}

/**
 * Convenience wrapper so you can click Run in the editor without writing a
 * caller. Replace the IDs with your own.
 */
function swapNorthwindLogos() {
  swapLogos('1abcDeckFolderId', '1abcNewLogoFileId');
}

How it works

  1. swapLogos reads the new logo once at the start. The blob is reused for every replacement, so the script makes a single trip to Drive for the asset instead of one per slide.
  2. It iterates files in the folder filtered by MIME type — only Google Slides files are touched, so PDFs and exports sitting in the same folder are ignored.
  3. For each deck it walks every slide and every image. slide.getImages() returns just the inline images, not the underlying placeholder shapes — which is exactly what we want for a logo swap.
  4. The position rule is the heart of the script. The Northwind template parks the logo in the top-left corner; any image with top < 50 and left < 100 (in points) is treated as the logo. Anything outside that rectangle is content and stays put.
  5. image.replace(blob) swaps the underlying image bytes without touching the frame. The new logo lands at the same position, the same size, and inherits any rotation or cropping the original had — which is usually what you want for a rebrand.
  6. It logs per-deck counts as it goes and a final tally, so you can confirm the right number of files were touched before sharing the folder back.

Example run

Say 1abcDeckFolderId contains six Northwind decks, each with the old logo on a title slide and a smaller version on every content slide. After one run, the log looks like:

Northwind pitch 2024.pptx: swapped 12 logo(s).
Q3 board update: swapped 8 logo(s).
Case study — Acme: swapped 10 logo(s).
Onboarding deck: swapped 14 logo(s).
Sales overview: swapped 9 logo(s).
All-hands September: swapped 11 logo(s).
Done — touched 6 decks, swapped 64 logos.

Open any deck and the new logo sits where the old one was — same size, same position, no manual realignment needed.

Run it

This is an on-demand job — run it once per rebrand:

  1. Drop the new logo into Drive and copy its file ID.
  2. Make a copy of the deck folder if you want a safety net.
  3. In the Apps Script editor, select swapNorthwindLogos and click Run.
  4. Approve the authorisation prompt the first time.
  5. Spot-check two or three decks before sharing the folder with the team.

For a really big library, split into batches by sub-folder and run each batch separately — each call has its own six-minute execution budget.

Watch out for

  • The position rule is brittle. If a deck has been resized or uses a different aspect ratio, the logo may sit outside the top < 50, left < 100 box. Audit the folder before running and adjust the constants to match.
  • Other top-left images get swapped too. If a slide has a freeformed icon in the corner, this script will replace it with the logo. Either fix those decks first or tighten the rule (match an exact size or an alt-text tag).
  • The script does not undo. There is no per-deck backup — make a folder copy first or accept that the rebrand is one-way.
  • Placeholder-anchored images are not touched. If the logo lives inside a master-layout placeholder rather than as an inline image, getImages() doesn’t see it and you’d need to update the master directly.

Related