appscript.dev
Automation Beginner Docs

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

  1. brandDoc checks it was given a docId. With nothing to open it logs a message and stops, so a missing argument never throws a confusing error.
  2. It opens the Doc and grabs its body — the container every paragraph and page break is inserted into.
  3. It inserts the studio name at index 0, the very top of the document, and styles it with the TITLE heading so it stands out as a cover.
  4. It inserts the address line at index 1, directly under the title.
  5. 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.
  6. It fetches the footer with getFooter(), falling back to addFooter() if the Doc never had one. clear() removes any old footer text so re-running the script never stacks duplicate notices.
  7. 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:

PageContent
Page 1Northwind Studios (title) / 12 Hoxton Square · London · northwind.studio
Page 2Project 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 DriveApp and call brandDoc on each ID.
  • TITLE styling 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