Below are a few Apps Scripts you can use in a browser (NOT mobile app) with Google Slides.
/**
* Export Slides speaker notes to a specified sheet in a Sheets file.
* Author: Mr Shane
* Version: 2025-02-22
*/
function speakerNotes() {
const ssId = "1gH913FHutEjAPkn6ZhanpMYJqqYQTgza8vVU07PmftA"; // Configure the file id of the target Sheets file.
const shName = "speaker"; // Configure the name of the sheet to export the speaker notes to.
const presentation = SlidesApp.getActivePresentation(); // Get the active Google Slides presentation.
const slides = presentation.getSlides(); // Get all the slides in the presentation.
const allNotes = slides.map((slide, index) => { // Map through each slide to extract speaker notes.
const shape = slide.getNotesPage().getSpeakerNotesShape(); // Get the shape that contains speaker notes.
const note = shape ? shape.getText().asString().replace(/\n/g, '') : ''; // If the shape exists, extract the text; otherwise, return an empty string.
return [`${index + 1})`, note]; // Return an array containing slide number and its corresponding notes.
});
const ss = SpreadsheetApp.openById(ssId); // Open the Sheets file by its Id.
const sheet = ss.getSheetByName(shName); // Get the sheet by its name.
if (allNotes.length > 0) { // IF there are notes to write...
sheet.getRange(1, 1, allNotes.length, allNotes[0].length).setValues(allNotes); // Write the collected notes to the sheet starting from cell A1
sheet.autoResizeColumns(1,2); // Automatically resize columns for better readability.
}
}
/**
* Format all tables in the Slides file.
* Author: Mr Shane.
* Version: 2025-03-11
*/
function formatTablesInSlides() {
headerFF = "Arial Black"; // Configure the font family of the header row.
dataFF = "Arial Narrow"; // Configure the font family of the data rows.
headerFS = 18; // Configure the text size of the header row.
dataFS = 16; // Configure the text size of the data rows.
headerB = false; // Configure bold for the header row (true or false);
dataB = true; // Configure bold for the data rows (true or false);
headerI = true; // Configure italics for the header row (true or false);
dataI = false; // Configure italics for the data rows (true or false);
headerFC = "#0000FF"; // Configure the HEX colour code for text in the header row.
dataFC = "#008000"; // Configure the HEX colour code for the text in data rows.
headerSF = "#008000"; // Configure the HEX colour code for background of the header row.
dataSF = "#0000FF"; // Configure the HEX colour code for background of the data rows.
SlidesApp.getActivePresentation().getSlides().forEach(slide => { // Get the active Google Slides presentation and loop through all slides.
slide.getTables().forEach(table => { // Get all tables on the current slide and loop through them.
for (let row = 0; row < table.getNumRows(); row++) { // Loop through each row in the table.
for (let col = 0; col < table.getNumColumns(); col++) { // Loop through each column in the row.
let cell = table.getCell(row, col); // Get the current cell.
let textRange = cell.getText(); // Get the text content of the current cell.
if (textRange.asString().trim()) { // Check if the cell contains any text before applying formatting. (If this check isn't done then errors occur when trying to apply formatting on cells that don't have text.)
let textStyle = textRange.getTextStyle();
textStyle.setFontFamily(row === 0 ? headerFF : dataFF) // Apply font families.
.setFontSize(row === 0 ? headerFS : dataFS) // Apply font sizes.
.setBold(row === 0 ? headerB : dataB) // Apply bold.
.setItalic(row === 0 ? headerI : dataI) // Apply italics.
.setForegroundColor(row === 0 ? headerFC : dataFC); // Apply text colours.
}
cell.getFill().setSolidFill(row === 0 ? headerSF : dataSF); // Apply background colours.
}
}
});
});
}
/**
* Insert speaker notes in blank slide pages for each group of [N] slides.
* This effectively turns Print preview 'Handout' into '[N] slides with notes'
* Author: Mr Shane
* Version: 2025-05-08
*/
function insertSlidesAndCopyNotes() {
const presentation = SlidesApp.getActivePresentation(); // Get the active presentation
const blanks = 3; // Configure how many blank slides to insert after each group of slides (Should be: 2,3,4,6,9)
let i = 0; // Initialize the index to track the current slide being processed
while (true) { // Loop indefinitely until a break condition is met
const slides = presentation.getSlides(); // Get all the slides in the presentation
if (i + blanks > slides.length) break; // If we reach the end, break the loop
const group = slides.slice(i, i + blanks); // Get the group of original slides to work with
const insertIndex = i + blanks; // Set the index where the new blank slides will be inserted
const newSlides = []; // Initialize an array to store the new blank slides
for (let j = 0; j < blanks; j++) { // Loop through the number of blank slides to insert
const newSlide = presentation.insertSlide(insertIndex + j); // Insert a new blank slide at the insertIndex
newSlides.push(newSlide); // Store the newly created slide in the newSlides array
}
for (let j = 0; j < blanks; j++) { // Loop through each blank slide to add the speaker notes
const originalNotesShape = group[j].getNotesPage().getSpeakerNotesShape(); // Get the speaker notes shape of the original slide
const speakerNotesText = originalNotesShape ? originalNotesShape.getText().asString() : ''; // Extract the speaker notes text
const newSlide = newSlides[j]; // Get the corresponding new slide to copy the speaker notes into
createTextBoxForSpeakerNotes_(newSlide, speakerNotesText); // Create a text box with the speaker notes on the new slide
}
i += blanks * 2; // Move to the next group (original slides and newly inserted slides)
}
const finalSlides = presentation.getSlides(); // Get the final list of slides after the loop
const leftover = finalSlides.length % (blanks * 2); // Calculate how many leftover slides are there
if (leftover > 0 && leftover < blanks) { // If there are leftover slides to handle
const start = finalSlides.length - leftover; // Get the start index for the leftover slides
for (let j = 0; j < leftover; j++) { // Loop through the leftover slides
const originalSlide = finalSlides[start + j]; // Get the original leftover slide
const newSlide = presentation.appendSlide(); // Append a new blank slide
const originalNotesShape = originalSlide.getNotesPage().getSpeakerNotesShape(); // Get speaker notes from the original slide
const speakerNotesText = originalNotesShape ? originalNotesShape.getText().asString() : ''; // Extract speaker notes text
createTextBoxForSpeakerNotes_(newSlide, speakerNotesText); // Create a text box with the speaker notes on the new slide
}
}
}
/**
* Helper function to create a text box for speaker notes
*/
function createTextBoxForSpeakerNotes_(slide, speakerNotesText) {
const textBox = slide.insertTextBox(speakerNotesText); // Insert a text box with the speaker notes text
textBox.setTop(100); // Set the vertical position of the text box
textBox.setLeft(50); // Set the horizontal position of the text box
textBox.setWidth(400); // Set the width of the text box
textBox.setHeight(300); // Set the height of the text box
}
/**
* Replace all slide pages in the current Slides file with all slides from a different Slides file.
* Author: Mr Shane
* Version: 2024-10-01
*/
function mergeSlidesIntoCurrent() {
const sourceId = "your_source_presentation_id"; // Configure the source Slides file ID.
const currentDeck = SlidesApp.getActivePresentation(); // Get the current Slides file.
const sourceDeck = SlidesApp.openById(sourceId);// Open the source file by its file ID.
const sourceSlides = sourceDeck.getSlides(); // Get all slide pages from the source deck.
let currentSlides = currentDeck.getSlides();
for (let i = currentSlides.length - 1; i >= 0; i--) { // For every slide page in the current file...
currentSlides[i].remove(); // Remove the slide pages.
}
for (let i = 0; i < sourceSlides.length; i++) { // For every slides page in the source file...
currentDeck.appendSlide(sourceSlides[i]); // Append the slides pages to the current deck.
}
}
/**
* Reverse the order of ALL slide pages.
* Author: Mr Shane
* Version: 2024-09-06
*/
function reverseSlidePositions() {
const slides = SlidesApp.getActivePresentation().getSlides(); // Get all slides in the presentation.
const len = slides.length; // The number of slides.
for (let i = len - 1; i >= 0; i--) { // Reverse the order of the slides.
slides[i].move(len - 1 - i); // Move each slide to its reverse position.
}
Logger.log("Slides reversed successfully");
}
/**
* Speaker notes default font setting
* Simulates setting a default style for speaker notes (NOT a true master-level default).
* Author: Mr Shane
* Version: 2025-05-14
*/
const DEFAULT_SPEAKER_NOTES_FONT_SIZE = 20; // 🔧 Configure the font size to be used.
function onOpen() {
SlidesApp.getUi()
.createMenu("⚠️Admin Menu⚠️")
.addItem("Set font size for active slide speaker notes", "setFontSizeForActiveSlideSpeakerNotes")
.addItem("Set font size for all speaker notes", "setFontSizeForAllSpeakerNotes")
.addItem("Set font size for empty speaker notes only", "setFontSizeForEmptySpeakerNotes")
.addToUi();
}
function setFontSizeForActiveSlideSpeakerNotes() {
const presentation = SlidesApp.getActivePresentation(); // Get the current presentation
const selection = presentation.getSelection(); // Get the current user selection
const currentPage = selection.getCurrentPage(); // Get the currently selected page
if (!currentPage || currentPage.getPageType() !== SlidesApp.PageType.SLIDE) { // Check if a slide is selected
Logger.log("No slide is currently selected."); // Log if nothing is selected
return; // Exit if no slide is selected
}
const slide = currentPage.asSlide(); // Cast the selected page to a Slide object
applyFontSizeToNotes(slide, "all"); // Apply font size to speaker notes (regardless of content)
}
function setFontSizeForAllSpeakerNotes() {
const presentation = SlidesApp.getActivePresentation(); // Get the active presentation
const slides = presentation.getSlides(); // Get all slides in the presentation
slides.forEach((slide, index) => applyFontSizeToNotes(slide, "all", index)); // Apply font size to each slide's speaker notes
Logger.log("Font size updated on all speaker notes."); // Log final summary
}
function setFontSizeForEmptySpeakerNotes() {
const presentation = SlidesApp.getActivePresentation(); // Get the current presentation
const slides = presentation.getSlides(); // Get all slides in the presentation
slides.forEach((slide, index) => applyFontSizeToNotes(slide, "emptyOnly", index)); // Apply font size only to empty speaker notes
Logger.log("Font size applied only to empty speaker notes."); // Log final summary
}
/**
* Helper function to apply font size to speaker notes.
*
* @param {Slide} slide - The slide object
* @param {string} mode - "all" to always apply font size, "emptyOnly" to apply only if empty
* @param {number} [index] - Slide index for logging (optional)
*/
function applyFontSizeToNotes(slide, mode = "all", index = null) {
const placeholder = "___TEMP___"; // Temporary placeholder text for empty notes
try {
const notesShape = slide.getNotesPage().getSpeakerNotesShape(); // Get the speaker notes shape from the notes page
const textRange = notesShape.getText(); // Get the editable text range of the notes
const currentText = textRange.asString().trim(); // Read and trim the existing text
if (mode === "emptyOnly" && currentText !== "") { // If only empty notes should be updated, and this one is not empty
Logger.log(`Slide ${index + 1}: Skipped (already has speaker notes).`); // Log skip
return; // Skip this slide
}
if (currentText === "") { // If the notes are empty
textRange.setText(placeholder); // Insert placeholder text to initialize the shape
textRange.getTextStyle().setFontSize(DEFAULT_SPEAKER_NOTES_FONT_SIZE); // Apply default font size
textRange.clear(); // Clear placeholder (without deleting the shape)
Logger.log(`Slide ${index + 1 || "Active"}: Font size set on empty speaker notes.`); // Log success
} else {
textRange.getTextStyle().setFontSize(DEFAULT_SPEAKER_NOTES_FONT_SIZE); // Apply font size to existing notes
Logger.log(`Slide ${index + 1 || "Active"}: Font size updated on existing speaker notes.`); // Log success
}
} catch (err) {
Logger.log(`Slide ${index + 1 || "Active"}: Skipped due to error - ${err.message}`); // Catch and log any errors
}
}
/**
* Unlink ALL slide pages.
* To unlink slides from the slides they are linked to.
*/
function unlinkAllSlides() {
const slides = SlidesApp.getActivePresentation().getSlides(); // Get all slides in the presentation.
for (let i = 0; i < slides.length; i++) {
const slide = slides[i];
if (slide.getSlideLinkingMode() === SlidesApp.SlideLinkingMode.LINKED) {
slide.unlink();
}
}
}