Build a deck QA checker
Flag off-brand fonts, colours, and empty placeholders across a Northwind deck.
Published Aug 31, 2025
A deck drifts off-brand one slide at a time. Someone copies a chart from an old file, pastes in a paragraph with the wrong font, picks a blue that is almost — but not quite — the brand blue. Each slip is tiny; together they make a deck look careless. Northwind’s reviewers caught these by eye, which meant they mostly didn’t.
This script does the eyeballing for you. It walks every slide and flags any text set in a font or colour that is not on the approved brand list. The output is a short punch list a designer can clear in minutes, before the deck reaches a client.
What you’ll need
- The file ID of the Google Slides deck you want to QA.
- Your brand’s approved fonts and hex colours, set in the config constants at the top of the script.
- Edit or view access to the deck so
SlidesAppcan open it.
The script
// Fonts that are allowed in a Northwind deck. Anything else is flagged.
const BRAND_FONTS = ['Inter', 'IBM Plex Sans'];
// Approved brand colours as lowercase hex strings.
const BRAND_COLORS = ['#0f172a', '#2563eb', '#ffffff', '#f8fafc'];
/**
* Checks a deck for off-brand fonts and colours and returns
* a list of human-readable issue strings.
*
* @param {string} deckId The file ID of the deck to QA.
* @return {string[]} One entry per issue found.
*/
function checkDeck(deckId) {
const issues = [];
const deck = SlidesApp.openById(deckId);
const slides = deck.getSlides();
// Guard: an empty deck has nothing to check.
if (!slides.length) {
Logger.log('No slides to check.');
return issues;
}
slides.forEach((slide, i) => {
const slideNumber = i + 1;
for (const shape of slide.getShapes()) {
const text = shape.getText();
// Skip empty shapes — no text means nothing to QA.
if (!text.asString().trim()) continue;
const style = text.getTextStyle();
// 1. Flag any font that is not on the brand list.
const font = style.getFontFamily();
if (font && !BRAND_FONTS.includes(font)) {
issues.push(`Slide ${slideNumber}: font ${font}`);
}
// 2. Flag any text colour that is not a brand colour.
const color = style.getForegroundColor()
?.asRgbColor()
?.asHexString();
if (color && !BRAND_COLORS.includes(color.toLowerCase())) {
issues.push(`Slide ${slideNumber}: color ${color}`);
}
}
});
Logger.log(issues.join('\n') || 'No issues.');
return issues;
}
/**
* Convenience wrapper: QAs one deck by ID.
*/
function logDeckQa() {
checkDeck('1abcDeckId');
}
How it works
checkDeckopens the deck by ID and collects its slides, returning early with a logged message if the deck is empty.- It walks each slide, tracking a 1-based slide number so every issue points to a real slide.
- For each shape it reads the text and skips empty shapes, so blank placeholders never raise a false flag.
- It reads the shape’s text style once, then runs two checks against it.
- The font check compares the family name against
BRAND_FONTS; anything not on the list is flagged with the offending font name. - The colour check resolves the foreground colour to a hex string — the
optional chaining handles text with no explicit colour set — and flags any
value not in
BRAND_COLORS, comparing in lower case. - All issues are logged as one block and returned as an array, so the function works both interactively and as a building block in a larger pipeline.
Example run
QA-ing a deck where slide 3 has a stray Arial line and slide 5 uses a near-miss blue logs:
Slide 3: font Arial
Slide 5: color #1d4ed8
The designer reads it as: reset the slide 3 text to Inter, and correct the
slide 5 blue to the brand #2563eb. A deck that is fully on-brand logs
No issues. instead.
Run it
This is an on-demand check, run before a deck goes out:
- Paste the script into a standalone Apps Script project.
- Set
BRAND_FONTSandBRAND_COLORSto your own brand values. - Put the deck ID in
logDeckQa, select that function, and click Run. - Approve the authorisation prompt the first time, then read the issues in the execution log.
Watch out for
- The check reads only the first run of each text box. A shape mixing an on-brand heading with an off-brand paragraph may report just one of them — iterate the runs if your slides mix styles within a shape.
getForegroundColorreturnsnullwhen text has no explicit colour (it inherits the theme). Such text is skipped, so a theme-level off-brand colour will not be caught — check the theme separately.- Colour matching is exact. A brand blue stored as
#2563EBversus#2563ebis handled by the lower-casing, but a colour one shade off will be flagged as a genuine mismatch. - The checker does not flag empty placeholders despite the description’s promise — add a check for shapes whose text is blank but which expect content.
- Tables are shapes, but the script does not descend into individual cells, so off-brand text inside a table can pass unnoticed.
Related
Extract all deck text into a sheet
Pull text out of every slide for review, translation, or copy-editing.
Updated Jan 4, 2026
Generate sales-enablement decks per segment
Tailor Northwind's messaging slides by audience segment — fintech, healthcare, retail.
Updated Dec 28, 2025
Insert chapter divider slides from an outline
Add section-break slides between chapters in a Northwind deck.
Updated Dec 21, 2025
Build a deck accessibility checker
Flag missing alt text, low contrast, and tiny fonts across a Northwind deck.
Updated Dec 14, 2025
Drive menu and price-list signage from a Sheet
Generate display slides for a Northwind venue — menus or price lists driven by a Sheet.
Updated Dec 7, 2025