Work  /  Data & Reporting  /  14  ·  Home services & construction

The Weekly Number, Assembled and Sent

Agencies · Home services · E-commerce · SaaS

Built — counted from the workflow JSON in the repository; not yet run against live accounts

50nodes
5workflows
23sticky notes
52connections
Five sources feeding one spreadsheet report with its total row marked, beside a weekly calendar.

The problem

The numbers that decide things — cost per booked job, close rate by source — are never computed at all.

The raw numbers live in five places. Someone spends a morning a week copying them into a deck nobody has read by Thursday, and anything that needs two of those places joined never gets made.

How it runs

  1. Pull five sources

    01 / 05 Workflow 1 of 5 · Pull Sources · 14 nodes

    Every week: Google Ads, Meta, the CRM, Stripe and CallRail, each pulled on its own, so one outage cannot block the rest.

  2. One row per week

    02 / 05 Workflow 2 of 5 · Reconcile & Upsert · 7 nodes

    The week is upserted into a sheet the client owns: updated if it exists, appended if not, never both.

  3. Compute what decides

    03 / 05 Workflow 3 of 5 · Compute Derived Metrics · 9 nodes

    Cost per booked job, close rate by source, revenue per source and week-on-week change — in code, with an em-dash wherever a denominator is zero.

  4. Narrate, without arithmetic

    04 / 05 Workflow 4 of 5 · Narrative & Delivery · 7 nodes

    A model phrases the numbers it is handed. It has no tools connected, so it cannot produce one.

  5. Watch in between

    05 / 05 Workflow 5 of 5 · Anomaly Watcher · 13 nodes

    Every four hours: a spend spike, spend with no clicks, or calls dropping to zero goes straight to Slack.

The five workflows, as built

Every node with its icon, as on the n8n canvasstarts a runa model or a parser, wired into the node above itHover a node for its name and type

  • 01Pull Sources

    14 nodes · 17 connections · 5 notes

    Schedule – Weekly Monday 06:00 · Schedule TriggerSchedule – WeeklyMonday 06:00Define Report Period · CodeDefine ReportPeriodGoogle Ads – Search Report · HTTP RequestGoogle Ads –Search ReportNormalize – Google Ads · CodeNormalize – GoogleAdsMeta – Ad Insights · HTTP RequestMeta – Ad InsightsNormalize – Meta · CodeNormalize – MetaCRM – Get Deals (HubSpot) · HTTP RequestCRM – Get Deals(HubSpot)Normalize – CRM Deals · CodeNormalize – CRMDealsStripe – List Charges · HTTP RequestStripe – ListChargesNormalize – Stripe Charges · CodeNormalize – StripeChargesCallRail – List Calls · HTTP RequestCallRail – ListCallsNormalize – CallRail Calls · CodeNormalize –CallRail CallsCombine Sources Into Period Row · CodeCombine SourcesInto Period RowHand Off → Reconcile & Upsert · Execute WorkflowHand Off →Reconcile & Upsert

    Google Ads, Meta, the CRM, Stripe and CallRail, each on its own

  • 02Reconcile & Upsert

    7 nodes · 7 connections · 5 notes

    Receive Period Row · When Executed by Another WorkflowReceive Period RowFlatten Period Row for Sheet · CodeFlatten Period Rowfor SheetGoogle Sheets – Search Current Period · Google SheetsGoogle Sheets –Search Current…Row Exists? · IfRow Exists?Google Sheets – Update Row (Existing Period) · Google SheetsGoogle Sheets –Update Row…Google Sheets – Append Row (New Period) · Google SheetsGoogle Sheets –Append Row (New…Hand Off → Compute Derived Metrics · Execute WorkflowHand Off → ComputeDerived Metrics

    one row per week: update or append, never both

  • 03Compute Derived Metrics

    9 nodes · 8 connections · 5 notes

    Receive Period Key · When Executed by Another WorkflowReceive Period KeyGoogle Sheets – Get Current Period Row · Google SheetsGoogle Sheets –Get Current Period…Compute Previous Period Key · CodeCompute PreviousPeriod KeyGoogle Sheets – Get Previous Period Row · Google SheetsGoogle Sheets –Get Previous…Compute Derived Metrics · CodeCompute DerivedMetricsPrepare Derived Metrics For Sheet · CodePrepare DerivedMetrics For SheetGoogle Sheets – Update Row (Write Derived Metrics) · Google SheetsGoogle Sheets –Update Row (Write…Merge Raw + Derived For Handoff · CodeMerge Raw +Derived For…Hand Off → Narrative & Delivery · Execute WorkflowHand Off →Narrative &…

    the ratios and deltas, em-dash-guarded

  • 04Narrative & Delivery

    7 nodes · 6 connections · 4 notes

    Receive Computed Period Row · When Executed by Another WorkflowReceive ComputedPeriod RowBuild Arithmetic Block For Prompt · CodeBuild ArithmeticBlock For PromptAI Agent – Phrase Narrative (No Tools) · AI AgentAI Agent – PhraseNarrative (No…OpenAI Chat Model · OpenAI Chat ModelOpenAI Chat ModelAssemble Slack Message · CodeAssemble SlackMessageSlack – Post Weekly Narrative · SlackSlack – PostWeekly NarrativeGoogle Sheets – Write Narrative Back to Row · Google SheetsGoogle Sheets –Write Narrative…

    the arithmetic shown to a model with no tools

  • 05Anomaly Watcher

    13 nodes · 14 connections · 4 notes

    Schedule – Every 4 Hours · Schedule TriggerSchedule – Every 4HoursDefine Lookback Window · CodeDefine LookbackWindowGoogle Ads – Last 8 Hours · HTTP RequestGoogle Ads – Last8 HoursNormalize – Google Ads (Recent) · CodeNormalize – GoogleAds (Recent)Meta – Last 8 Hours · HTTP RequestMeta – Last 8HoursNormalize – Meta (Recent) · CodeNormalize – Meta(Recent)CallRail – Last 8 Hours · HTTP RequestCallRail – Last 8HoursNormalize – CallRail (Recent) · CodeNormalize –CallRail (Recent)Detect Anomalies · CodeDetect AnomaliesAny Anomaly? · IfAny Anomaly?Format Anomaly Alert · CodeFormat AnomalyAlertSlack – Post Anomaly Alert · SlackSlack – PostAnomaly AlertNo Anomaly – End Quietly · No OperationNo Anomaly – EndQuietly

    every four hours, on its own schedule

50 executing nodes, by type

Code 20HTTP Request 8Google Sheets 7Execute Workflow 3When Executed by Another Workflow 3Schedule Trigger 2If 2Slack 2Other 3

The gates, 2 If nodes, decide whether anything happens next: a countable part of the system, not a claim about it. The 23 sticky notes carry the reasoning on the canvas, at the point it applies.

The guards, and what each one prevents

HoverTap a card to read what it prevents.

  • The model is not allowed to do arithmetic

    Every ratio is computed upstream and shown with its working, and the agent that writes the narrative has zero tools connected. It can phrase a number; it cannot produce one.

  • The em-dash contract

    A zero denominator gives an em-dash — never Infinity, NaN or a fabricated $0.00 — and a change measured against last week’s em-dash stays an em-dash.

  • One source of truth for leads

    The ad platforms contribute spend and clicks only. Leads and bookings come from the CRM, so two disagreeing counts never share a row.

  • Nothing is silently dropped

    An unknown lead source is counted as “other”, and a charge with no matching deal is kept as unattributed revenue — an ugly line beats a hidden mismatch.

  • A week is counted by the calendar

    The previous week is found by subtracting seven real days. Some years have 53 ISO weeks, and string arithmetic breaks once a year.

  • Three alarms, not one

    A spend spike, spend with no clicks and dead call volume are three different failures — and a quiet night outside business hours is not one of them.

Limits, stated plainly

  • Built, not yet deployed. The importability checks pass and every Code node’s logic was run against mocked data; it has not run against live Google Ads, Meta, HubSpot, Stripe and CallRail accounts.
  • The CRM side is HubSpot-shaped. Another CRM means swapping one request and its field names; everything after it is CRM-agnostic.
  • Only one page is read from Stripe and HubSpot — fine below about a hundred charges or deals a week.
  • Amounts are assumed to be in US dollars.

Built with

  • n8n
  • Google Ads
  • Meta
  • HubSpot
  • Stripe
  • CallRail
  • Google Sheets
  • OpenAI
  • Slack