Stamp letterhead and branding onto plain Docs
Add a Northwind cover page and footer to plain Docs automatically.
Published Oct 19, 2025
Northwind’s writers draft proposals and briefs as plain Docs — no cover page, no footer, nothing that says where the document came from. Branding them by hand is the kind of five-minute job everyone forgets, so half the documents that leave the studio look like a blank page someone typed into.
This script does the branding for you. Point it at a Doc and it prepends a titled cover page with the studio address, drops in a page break so the content starts fresh on page two, and sets a centred confidentiality footer. It is a small, repeatable job — exactly the sort of thing to wire to a custom menu so any writer can apply it in one click.
What you’ll need
- A Google Doc to brand. The script works on the Doc’s body and footer, so it does not matter what is already in there.
- Edit access to that Doc — the script opens it by ID and saves it back.
- Nothing else. The cover text and address live in the config block, so there is nothing to install or enable.
The script
// The studio name printed as the cover-page title.
const STUDIO_NAME = 'Northwind Studios';
// The address line printed under the title.
const STUDIO_ADDRESS = '12 Hoxton Square · London · northwind.studio';
// The text shown in the centred footer on every page.
const FOOTER_TEXT = 'Confidential · Northwind Studios';
/**
* Stamps a Northwind cover page and footer onto a plain Doc.
*
* @param {string} docId The ID of the Doc to brand.
*/
function brandDoc(docId) {
// 1. Bail out early if no Doc was passed in.
if (!docId) {
Logger.log('No docId supplied — nothing to brand.');
return;
}
const doc = DocumentApp.openById(docId);
const body = doc.getBody();
// 2. Prepend the studio name as a TITLE-styled paragraph at the top.
body.insertParagraph(0, STUDIO_NAME)
.setHeading(DocumentApp.ParagraphHeading.TITLE);
// 3. Add the address line directly below the title.
body.insertParagraph(1, STUDIO_ADDRESS);
// 4. Drop a page break so the original content starts on page two.
body.insertPageBreak(2);
// 5. Get the footer (or create one), wipe it, and add the centred notice.
const footer = doc.getFooter() || doc.addFooter();
footer.clear();
footer.appendParagraph(FOOTER_TEXT)
.setAlignment(DocumentApp.HorizontalAlignment.CENTER);
// 6. Save and close so the changes are flushed to Drive.
doc.saveAndClose();
Logger.log('Branded "' + doc.getName() + '".');
}
How it works
brandDocchecks it was given adocId. With nothing to open it logs a message and stops, so a missing argument never throws a confusing error.- It opens the Doc and grabs its body — the container every paragraph and page break is inserted into.
- It inserts the studio name at index
0, the very top of the document, and styles it with theTITLEheading so it stands out as a cover. - It inserts the address line at index
1, directly under the title. - It inserts a page break at index
2. Everything the writer drafted now begins cleanly on page two, leaving page one as a dedicated cover. - It fetches the footer with
getFooter(), falling back toaddFooter()if the Doc never had one.clear()removes any old footer text so re-running the script never stacks duplicate notices. - It appends the confidentiality line to the footer and centres it, then
saveAndClose()writes everything back to Drive.
Example run
Start with a plain Doc called “Client proposal — Acme” whose first line is just body text:
Project background
We propose a three-phase rollout starting in March...
After a run, the same Doc has a branded cover page and a footer:
| Page | Content |
|---|---|
| Page 1 | Northwind Studios (title) / 12 Hoxton Square · London · northwind.studio |
| Page 2 | Project background / We propose a three-phase rollout… |
| Footer (every page) | Confidential · Northwind Studios (centred) |
The writer’s content is untouched — it has simply been pushed behind a cover page and given a consistent footer.
Run it
This is an on-demand job, run once per document, so a custom menu is the natural
home for it. Add an onOpen trigger so the menu appears whenever a writer opens
a Doc:
function onOpen() {
DocumentApp.getUi()
.createMenu('Northwind')
.addItem('Apply branding', 'brandActiveDoc')
.addToUi();
}
/**
* Menu wrapper — brands the Doc the user currently has open.
*/
function brandActiveDoc() {
brandDoc(DocumentApp.getActiveDocument().getId());
}
With this in place a writer opens the Northwind menu, clicks Apply
branding, and approves the authorisation prompt the first time. To brand a Doc
the script is bound to outside the editor, run brandActiveDoc from the Apps
Script editor instead.
Watch out for
- Running it twice stacks two cover pages. The footer is rebuilt each run, but the title, address and page break are inserted fresh every time. Brand a Doc once, or add a check for an existing title before inserting.
- The page break lands at index
2, which assumes the Doc already has content there. On a brand-new empty Doc that is still safe, but the cover will sit on its own with a blank page two. - Branding bound to one Doc only affects that Doc. To brand many files in a
folder, loop over them with
DriveAppand callbrandDocon each ID. TITLEstyling follows the Doc’s theme. If a document uses a custom style set, the cover will pick up that theme’s title font rather than a fixed Northwind look — set explicit font and size on the paragraph if you need it pixel-consistent.
Related
Generate personalized study guides from notes
Reformat raw notes into structured study guides — for Northwind's internal training programme.
Updated Feb 8, 2026
Build a contract-clause assembly system
Construct Northwind agreements from a library of approved clauses — drag-drop in code.
Updated Feb 1, 2026
Translate and resolve Doc comments
Localise reviewer feedback on a shared Doc so multilingual teams can collaborate.
Updated Jan 25, 2026
Auto-archive finalized Docs to dated folders
File completed Northwind Docs by month so the active folder stays focused on in-flight work.
Updated Jan 18, 2026
Build a fillable intake form inside a Doc
Create structured intake forms with placeholder fields readers can fill — for client briefs.
Updated Jan 11, 2026