Back to writing
2 min read

Automating Weekly Reports with Apps Script Triggers

A step-by-step trigger-based pipeline that gathers scattered data into the same document format every week.

A weekly report is more about collection than content. Gathering numbers scattered across places, formatting them the same way, and sending them out — that repeats every week. Move the repetition onto a trigger, and what’s left for the person is reading and judging the report.

This is a demonstration draft.

A time-based trigger

Apps Script lets you create triggers in code. For a report that runs Monday mornings, you set it up like this.

function installWeeklyTrigger() {
  ScriptApp.newTrigger("buildWeeklyReport")
    .timeBased()
    .onWeekDay(ScriptApp.WeekDay.MONDAY)
    .atHour(8)
    .create();
}

Creating triggers in code means they reproduce without any clicking when you move to another environment.

Funnel collection into one shape

The heart of a report is “which numbers, from where, and how.” Even with several sources, unifying the collection into a single shape makes everything downstream easier.

function collectMetrics() {
  return {
    week: weekLabel(),
    inquiries: countRows("Inquiries"),
    delivered: countRows("Done"),
    pending: countRows("Pending"),
  };
}

function countRows(sheetName) {
  const sheet = SpreadsheetApp.getActive().getSheetByName(sheetName);
  return Math.max(0, sheet.getLastRow() - 1); // exclude header
}

Output to a document

Fill the collected values into a Google Docs template. Define placeholders and substitute them, and the format stays consistent week to week.

function buildWeeklyReport() {
  const metrics = collectMetrics();
  const doc = DocumentApp.create(`Weekly Report — ${metrics.week}`);
  const body = doc.getBody();
  body.appendParagraph(`Weekly Report (${metrics.week})`).setHeading(
    DocumentApp.ParagraphHeading.HEADING1,
  );
  body.appendParagraph(`Inquiries: ${metrics.inquiries}`);
  body.appendParagraph(`Delivered: ${metrics.delivered}`);
  body.appendParagraph(`Pending: ${metrics.pending}`);
  doc.saveAndClose();
}

Don’t let failures pass quietly

The most dangerous thing in automation is a silent failure. If a trigger stops and no one notices, you only realize the report is missing much later. So I leave a short confirmation signal at the end of a run.

function buildWeeklyReport() {
  try {
    // ... the logic above ...
  } catch (err) {
    GmailApp.sendEmail(Session.getActiveUser().getEmail(),
      "Weekly report failed", String(err));
    throw err;
  }
}

Wrapping up

Report automation doesn’t need to be fancy. Funnel collection into one shape, pin the output format, and make failures visible — that’s enough. The time you get back goes into interpreting the numbers.