← All work Attribution · Reporting · Data platform

What did we spend, on what, and did it work?

Marketing Hub Connect is a single platform that links every ad, email, WhatsApp broadcast and push notification to the property, project and agent it was promoting. It pulls from 25+ sources across six platforms and four regions.

My roleSolo architect & builder
UsersLeadership, regional marketing, agents
RegionsDubai · Abu Dhabi · KSA · UK
TypeInternal web app, live in production
2 hrs → 1 clickweekly management report, previously built by hand
25+sources synced nightly: 4 Meta and 4 Google Ads accounts, CRM portals, email, WhatsApp and 4 push apps
6 levelsof reporting: company, region, channel, listing, project, agent
3currencies (AED, SAR, GBP), each reported on its own

The problem

Marketing was busy but hard to see. Every channel had its own dashboard, and none of them knew which property, project or agent a campaign was for.

Data in silos

Meta, Google, HubSpot, WhatsApp, email and push each held part of the picture, spread over multiple accounts per region.

Manual reporting

Around two hours every week to pull numbers together for leadership, and it was out of date the moment it was done.

Spend with no owner

No reliable way to say which listing or agent a campaign served, or which properties got no marketing support at all.

The system

Five layers. Raw data is kept exactly as each platform sends it, then normalised into one model, then attributed to the business objects people care about.

1 · Sources
HubSpot CRMlistings, projects, owners
Meta Ads4 accounts
Google Ads4 accounts
WhatsAppbroadcast stats
EmailHubSpot + Brevo
Push4 regional apps
2 · Raw storage
Native payloads keptreprocess without re-fetching
Sync run logstatus, counts, errors
3 · Unified model
Accounts & campaigns
Daily performance facts
Marketing assets
4 · Attribution
Ad → Listing / Projectauto-match + manual map
Listing → Agentderived from CRM owner
5 · Reporting
Country overview
Agent leaderboard
Coverage gaps
Attribution health
External system / output Data layer Business logic Runs nightly, and any sync can also be triggered by hand

Every dirham, riyal and pound gets a status

Instead of hiding what can't be matched, the platform labels it. That turns data quality into something the team can see and fix.

attributed

Exactly one owner resolved. Counts toward the agent and listing.

unassigned

Mapped to a listing, but that listing has no owner yet.

ambiguous

Two equally specific mappings point to different owners.

unmapped

No mapping exists. It shows up on the attribution health report.

How it works

What happens every night, without anyone touching it.

  1. 01

    Sync the CRM first

    Projects come in before listings, so every listing can link to its project on arrival. Full-portfolio pagination across three CRM portals, plus a suppression list so retired listings never come back.

  2. 02

    Pull every channel

    Ad hierarchies and daily insights from Meta and Google, email sends from five accounts, push notifications from four apps, and WhatsApp delivery events through a webhook.

  3. 03

    Match ads to properties automatically

    Campaign, ad group and ad names are scanned for property reference codes and project tags. Manual mappings made by the team survive every rebuild.

  4. 04

    Resolve the owner

    Ad → listing or project → CRM owner → regional agent record. Nothing is copied, so when a listing changes hands, the history follows automatically.

  5. 05

    Reconcile and report

    Raw platform totals are checked against unified totals, so no spend is lost or double counted in translation. Then the dashboards refresh.

Decisions that matter

The choices that make the numbers trustworthy enough for leadership to act on.

The finest mapping wins

An ad can be mapped at campaign, ad group or ad level. The most specific mapping always wins, so the same spend is never counted twice.

Never add currencies together

AED, SAR and GBP stay separate everywhere. Without an agreed exchange-rate policy, a combined total would look precise and be wrong.

Daily facts, not lifetime totals

Performance is stored per day, so any period can be reported accurately, from last week to this quarter.

Keep the raw data

Each platform's original payload is stored before transformation. If the business rules change, history can be reprocessed without calling the APIs again.

Region-level access in the database

Role and region permissions are enforced by the database itself, so a user only ever sees the countries they're entitled to.

Every sync leaves a receipt

Each run logs its status, timing, record counts and errors, and can be re-run from an admin console with live step-by-step progress.

Where else this works

Any business that spends across many channels and needs to know what each product, location or team actually gets.

  • Multi-brand retail
  • E-commerce
  • Franchises
  • Automotive dealer groups
  • Hospitality groups
  • B2B SaaS with regional teams

Built with

TypeScriptReact 19TanStack StartPostgreSQLRow-level securityTailwind CSSHubSpot APIMeta Marketing APIGoogle Ads APIGallabox webhooksBrevoOneSignalGitHub ActionsLovableClaude