Raphael Napoleon Atikpo
Project 1 of 10 — Marketing Operations & Automation portfolio

A marketing system built to prove it works, not just to run once.

An end-to-end tracking, CRM, and reporting pipeline for a fictional product launch — instrumented with GTM and GA4, connected to HubSpot, automated with Make.com, and deliberately broken eight different ways to prove the debugging holds up. Built entirely on free-tier tools.

Campaign URL→ GTM→ GA4→ HubSpot→ Make.com→ Sheets→ Looker Studio
The actual pipeline this page describes — every arrow is a real, tested connection, not a diagram of an intention.
7
GTM tags shipped
8 / 8
deliberate failures diagnosed & fixed
12
dashboard charts, 6 sections
$0
total budget

The problem

Marketing and CRM teams typically see only half of the customer journey each. Web analytics captures anonymous behavior; the CRM captures identified leads. Without a deliberate architecture connecting the two, neither side can reliably answer the question that actually matters: which campaign produced this lead. I built this system to design and implement that connective architecture end to end, entirely on free-tier tooling.

What I set out to build

How the pieces fit together

The system runs as two deliberately separate tracks, meeting only at the reporting layer.

Track A — Reference

The real, live Google Merchandise Store GA4 demo account, used read-only to validate measurement-plan decisions against a mature, production ecommerce implementation. Nothing here was ever edited.

Track B — Owned & instrumented

Waypoint Supply Co., an original fictional brand built specifically so every layer — code, tags, CRM, automation — was mine to instrument, test, and break on purpose.

Campaign attribution is joined at the campaign level — shared UTM values — not the user level. GA4 and HubSpot never share a native user identity on this stack, and the architecture was built around that constraint rather than pretending it away.

Stack

Google Analytics 4 Google Tag Manager HubSpot CRM Make.com Google Sheets Looker Studio GitHub Pages

What's actually running

Google Tag Manager

Seven tags across three folders. Native Click and Element Visibility triggers everywhere one existed, with one deliberate exception: a Custom HTML listener bridging HubSpot's cross-origin iframe submission events into the Data Layer, since no native GTM trigger can read postMessage traffic.

GTM Tags list showing 7 tags, one Custom HTML listener and six native GA4 Event / Configuration tags
The full tag list — one Custom HTML tag, six native GA4 tags. No stray duplicates.

GA4

Enhanced Measurement audited, not just switched on — Form interactions deliberately disabled to avoid a second, unreliable count of form activity. Custom dimensions registered for every event parameter that needed to be reportable, one Key Event, one behavioral audience.

HubSpot

Free CRM, five custom properties mirroring the UTM taxonomy exactly, a two-field form kept deliberately short. Campaign attribution captured via HubSpot's native query-string auto-populate — chosen after confirming HubSpot's current default form architecture blocks the classic JavaScript approach most tutorials still describe.

Make.com

One scenario: a router that splits incoming leads by whether they carry campaign data, logs both outcomes, and includes an error handler I forced to fail on purpose to confirm it actually catches a failure instead of losing a lead silently.

Make.com scenario showing HubSpot Watch Contacts trigger into a Router, splitting into two branches each writing to Google Sheets
The router in production — both branches logged, both running on a 15-minute schedule.

Reporting

A six-tab Google Sheets operational layer feeding a twelve-chart Looker Studio dashboard, structured around six real business questions rather than built to look impressive.

Proving it works, not just building it

QA happened in two layers: a systematic pass across every system, then eight failures introduced on purpose and diagnosed from their actual symptoms — not from already knowing the cause.

GA4 Realtime debug device view showing a real session firing teaser_view, teaser_view, then form_view in correct sequence
GA4 Realtime, mid-session — teaser_view → teaser_view → form_view, firing in the order the funnel expects.
  1. 01Mistyped event name — silently created an unrecognized event; caught via a funnel step reading zero. Fixed, verified.
  2. 02Duplicated trigger on one tag — one click fired the tag twice; caught by counting fires in Preview. Fixed, verified.
  3. 03Wrong event marked as a Key Event — inflated the conversion count with a funnel-stage signal, not an outcome. Fixed, verified.
  4. 04Inconsistent UTM casing — split one channel's data into two report rows. Confirmed unrecoverable retroactively; documented as a standing risk of manual tagging.
  5. 05HubSpot property internal name mismatch — a hidden field stayed silently blank with no error anywhere. Fixed, verified.
  6. 06Inverted Make.com filter — valid leads were dropped with nothing overtly labeled as an error. Fixed, verified.
  7. 07Forced automation failure — confirmed the error handler logs a failed run instead of losing the record.
  8. 08Broken dashboard formula — caught by two independently-sourced totals that should always agree, and didn't. Fixed, verified.

One item I haven't closed out

A portion of historical generate_lead events fired without a form ID attached. I ruled out GTM tag duplication and consent-mode interference, and narrowed it most likely to residual noise from an earlier troubleshooting session — but I didn't get a clean, isolated reproduction before mitigating it in the dashboard's reporting window. It's logged as an open item, not quietly patched over.

GA4 event detail for generate_lead showing 123 total events from 11 users, and a Form ID breakdown showing 112 events as not set
The actual evidence: 123 fires, 11 users, 112 with no Form ID attached — this is what "not fully resolved" looks like, not a guess.

What's actually verifiable

Measured: every layer of the pipeline is independently checkable — GTM Preview and GA4 DebugView confirm correct event firing with correct parameters, HubSpot contact records show correctly populated campaign attribution, the Make.com scenario runs autonomously on schedule with a working error path, and the dashboard is live and public. All eight deliberately introduced failures were diagnosed and resolved.

This is a live environment rather than a fixed dataset, so exact lead-volume numbers are visible on the dashboard itself at any given time, rather than quoted here as a static figure.

Looker Studio dashboard showing headline stats, Data Quality and QA Test Log tables, and a Lead Generation Over Time chart
The dashboard itself — headline stats, the Data Quality summary, and the QA test log, all live.
On business impact: this is demonstrated capability, not measured business impact — there's no real company or customer base behind Waypoint Supply Co. What's genuinely demonstrated is a system that, applied to a real launch, would attribute leads to specific campaigns and channels, log every submission without manual entry, and surface tracking breakage before it quietly corrupts a quarter of reporting.

What I'd tell a hiring manager directly

Challenges

The instructive ones weren't the ones I expected going in. HubSpot's current default form architecture broke the JavaScript approach I initially planned for capturing UTM data, forcing a redesign around a native auto-populate mechanism instead. A Make.com field-mapping issue meant most early test submissions logged only a timestamp, not full lead data, until I traced it to an unresolved mapping step.

Limitations

What I'd build next