Case study · · 4 min read · Lurto

The Monday spreadsheet: ad reporting for a skincare brand that writes itself

The Monday spreadsheet: ad reporting for a skincare brand that writes itself

Quick answer

Every Monday somebody copied numbers out of Meta Ads Manager and a skincare brand's store analytics into a spreadsheet, for about an hour. A nightly n8n pipeline with a Postgres store now pulls both, reconciles spend against revenue onto the same row, and sends a one-page summary with the slipped ad sets marked. It removed about four hours a month, but the change that mattered was that a bad ad set gets noticed the day it slips instead of at month end. There is no model in the nightly path at all.

Every Monday, somebody opened Meta Ads Manager, a skincare brand's store analytics and a spreadsheet, and copied numbers from the first two into the third for about an hour. That was how anyone found out what last week had earned. This is a small build, and we are writing it up precisely because it is small: most of the work we are asked for looks like this, and the value is easy to underestimate from the outside.

How it got that way

We are deliberately not saying whose desk that hour came off, because on this kind of account it is sometimes the brand and sometimes the agency running the ads, and the job is identical either way. Nobody decided reporting should work like this. The spreadsheet was made once to answer one question, the question kept coming back, and the copying became somebody's job. Ads Manager knew what each campaign had spent. The store knew what had sold. Neither knew the other, and the person with the spreadsheet was the join.

The cost was not really the hour. It was that a bad ad set could run for a week before anyone saw it, because the only time anyone looked was Monday.

What we built

A reporting pipeline in n8n with a Postgres store underneath it. Every night it pulls ad set, creative and purchase data from the Meta Marketing API, pulls the store's orders, and reconciles the two so that spend and revenue sit on the same row. Each morning a one-page summary goes out with the ad sets that slipped marked on it. The person who used to copy now reads the page and decides what to turn off.

The reconciliation is the part worth describing, because it is where these builds usually go wrong. Ad platforms and shop analytics count differently: attribution windows, time zones, refunds, orders that touched two campaigns. We made the rules explicit, wrote them down, and put the unreconciled remainder on the page as its own line rather than hiding it. A report that quietly forces two systems to agree is a report nobody trusts once they notice.

What changed

BeforeAfter
An hour of copying every MondayThe report writes itself overnight
Underperformers noticed at the end of the monthFlagged the day they slip
Numbers that depended on who did the copyingOne reconciliation rule, written down, applied every night
Manual reporting timeAbout four hours a month removed

Four hours a month is not a big number, and we would not build a case on it. The change that mattered was the second row. A bad ad set now gets noticed the day it slips instead of at the end of the month, because nobody has to go looking. That is the thing the owner would have paid for if anyone had offered it, and it fell out of removing the copying.

What it costs to run

The running cost is the platform line for n8n, a small database, and the API calls, all on the client's own accounts at the provider's price. It sits at the low end of the monthly running costs of an automation, and the client can read every meter without asking us. There is no model in the nightly path at all, which is a point worth making: a good deal of what gets sold as AI automation is a workflow with a join in it, and this one did not need a model to earn its keep.

Where this shape shows up

Almost every company has one of these spreadsheets. It is usually the thing somebody just does on Monday. The pattern is two systems that do not talk, a person who is the join, and a question that only gets answered when that person sits down. Ad spend against orders is one instance. Invoices against purchase orders, bookings against payroll, support tickets against product returns are others. If you can name the spreadsheet, you can usually name the build, and reporting is one of the jobs we quote as a single build at what we automate.

Questions people ask about this

Where do reporting builds like this usually go wrong?

The reconciliation. Ad platforms and shop analytics count differently: attribution windows, time zones, refunds, orders that touched two campaigns. We made the rules explicit, wrote them down, and put the unreconciled remainder on the page as its own line rather than hiding it. A report that quietly forces two systems to agree is a report nobody trusts once they notice.

Is four hours a month worth a build?

Not on its own, and we would not build a case on it. The cost was never really the hour, it was that a bad ad set could run for a week before anyone saw it, because the only time anyone looked was Monday. Being flagged the day it slips is the thing the owner would have paid for if anyone had offered it, and it fell out of removing the copying.

Does a build like this need AI?

No. There is no model in the nightly path at all. A good deal of what gets sold as AI automation is a workflow with a join in it, and this one did not need a model to earn its keep.

Where else does this shape show up?

Two systems that do not talk, a person who is the join, and a question that only gets answered when that person sits down. Ad spend against orders is one instance. Invoices against purchase orders, bookings against payroll, and support tickets against product returns are others. If you can name the spreadsheet, you can usually name the build.

Have a system that needs this treatment?