How I Reduced Weekly Reporting from 3 Hours to 90 Seconds

python-for-marketingautomationreportingbuilding-in-public

3 hours. Every Monday morning. For 18 months.

That was my reality. Export from the CRM. Export from the ad platform. Export from analytics. Paste into the master spreadsheet. Fix the dates that never formatted right. Recalculate the formulas that broke again. Build the summary table. Export to PDF. Send to leadership.

By 11 AM I was finally done — exhausted, annoyed, and behind on actual work.

Now? I run one command. 90 seconds later, the report is ready.

Here’s exactly how that happened, what went wrong along the way, and what I’d do differently if I started today.


The Before State (Why This Mattered)

I’m not complaining about “boring work.” I’m complaining about expensive work.

Let’s do the math:

  • 3 hours per week × 52 weeks = 156 hours per year
  • At a conservative estimate of $25/hour for marketing ops time: $3,900 per year
  • But the real cost is not money. It’s attention.

While I was copy-pasting, I was not analyzing. While I was fixing formulas, I was not identifying which campaigns were underperforming. The report was technically done, but I had no energy left to ask: “So what?”

That is the hidden cost of manual reporting. You don’t just lose time. You lose the capacity to act on what the data is telling you.

The Breaking Point

The breaking point was not dramatic. It was a Monday in March when I realized I had spent 3.5 hours on the report, sent it, and immediately got a Slack message: “Can you break this down by channel?”

I almost cried. Not because the request was unreasonable — it was completely reasonable. But because I knew it would take another hour, and I had a campaign review at 2 PM I hadn’t prepared for.

I opened VS Code that evening and wrote the first version of the script. It was terrible. It had hardcoded file paths, no error handling, and it broke if the CSV had an extra column. But it ran. And it produced a report that looked 80% like what I was building manually.

That terrible script was the most valuable code I’ve ever written.

The Approach (Not The Code)

I want to be clear about something: I did not start by learning Python. I started by documenting my process.

Before writing any code, I opened a blank document and wrote down every step I took to build that report:

  1. Download CSV from CRM (deals closed this week)
  2. Download CSV from ad platform (spend, clicks, impressions)
  3. Open master spreadsheet
  4. Copy CRM data into Sheet 1
  5. Copy ad data into Sheet 2
  6. Fix date formats (CRM uses MM/DD/YYYY, ads use YYYY-MM-DD)
  7. Rename columns to match master template
  8. Calculate weekly totals
  9. Build summary table
  10. Create spend vs revenue chart
  11. Export to PDF
  12. Email to leadership

That list was my roadmap. Every item became a function in the script. The dates that were painful to fix manually became pd.to_datetime(). The copy-paste became pd.merge().

The code was not elegant. But it was correct — because it mapped to a real process I understood completely.

The Stack (Simple, On Purpose)

I deliberately kept the stack small:

  • pandas — for loading, cleaning, and transforming
  • openpyxl — for writing formatted Excel files
  • matplotlib — for basic charts (later replaced with plotly for interactivity)

That’s it. No cloud databases, no complex pipelines, no frameworks. I wanted something I could run on my laptop, debug in 10 minutes, and explain to my manager if needed.

The script lives in a single file. It reads from a /data folder and writes to an /output folder. Configuration is in a YAML file anyone can edit.

This simplicity was intentional. Complex systems fail when you’re not a full-time engineer. Simple systems keep working.

The After State (What Changed)

Here’s what Monday mornings look like now:

  1. Drop CSV exports into /data
  2. Run python report.py --week 2026-W24
  3. 90 seconds later, open the output file
  4. Spot-check for anything weird
  5. Email to leadership

Total time: ~10 minutes, mostly spot-checking. The actual report generation is under 2 minutes.

But the bigger change is not the time saved. It’s what happens after the report is done.

I now spend that recovered time on:

  • Analysis: Why did ROAS drop in Week 23?
  • Experimentation: What if we shifted 20% of Meta budget to Google?
  • Conversation: Actually discussing the numbers with leadership instead of rushing through them

The report became a starting point, not a destination.

What Went Wrong (So You Don’t Repeat It)

I made three mistakes that cost me weeks:

1. I tried to automate everything at once.

The first version tried to handle CRM data, ad data, analytics data, and email delivery all in one script. It broke constantly because I couldn’t tell which part was failing.

The fix: I rebuilt it in stages. First, just CRM + ads. Got that stable. Then added analytics. Then added email delivery. Each stage took 2-3 days instead of 2-3 weeks of debugging everything at once.

2. I assumed source data was clean.

I spent my first week assuming the CSV exports would always have the same columns. They do not. Platforms rename columns. Dates change format. Some weeks have no data at all.

The fix: I added a validation step at the start of the script. It checks for required columns, warns about missing data, and fails with a clear error message instead of producing a broken report.

3. I didn’t version control the config.

The config.yaml file changed constantly as I added sources and adjusted metrics. One afternoon I accidentally deleted a section and couldn’t remember what it was supposed to be.

The fix: I put the whole project on GitHub. Not because anyone else was using it — because I needed version history for myself.

The Numbers (If You’re Skeptical)

I tracked time for 4 weeks before and after:

TaskBefore (manual)After (automated)
Pull data from sources25 min5 min (drop files)
Clean and format45 min0 min (script handles)
Build summary table35 min0 min (script handles)
Create charts20 min0 min (script handles)
Spot-check and send15 min10 min
Total~2 hours 20 min~15 minutes

The remaining 15 minutes is intentional. I still spot-check the output. Automation does not mean zero oversight. It means oversight instead of assembly.

Who This Is For

This approach works if:

  • You spend more than 1 hour per week on repetitive reporting
  • Your data comes from 2-5 sources that export to CSV
  • The report follows the same structure every week
  • You’re comfortable installing Python packages (or willing to learn)

This approach does not work if:

  • Your data is in real-time APIs that need constant syncing
  • Your report structure changes completely every week
  • You need pixel-perfect visual design (this is functional, not beautiful)

What I’m Building Next

The current script is v1. Here’s what’s on the roadmap:

  • Direct API connections — eliminate the CSV export step entirely
  • Scheduled runs — report generates automatically Monday at 7 AM
  • Slack integration — summary posts to team channel
  • Alerting — flag unusual numbers before they become problems

Each of these builds on the same principle: reduce manual work, increase decision speed.


The Real Lesson

I didn’t learn Python to become a developer. I learned Python because I was tired of losing Monday mornings to a computer that could do the work for me.

The best automation projects don’t start with code. They start with annoyance.

If you have a task that makes you groan every time you do it — that same task, every week, same steps — that’s your candidate. Document the steps. Find the tool that handles those steps. Start ugly. Iterate.

The goal is not elegant code. The goal is never doing that manual work again.


The code: marketing-report-automation on GitHub

Want the same result for your team? I work with marketing teams to automate reporting, build analytics dashboards, and replace manual data work with Python-powered workflows. Start a conversation →

Facing the same problem?

I work with marketing teams to automate reporting, build analytics dashboards, and replace manual data work with Python-powered workflows.

Start a conversation →