A consent-capture, storage, and suppression system for a fictional B2B SaaS company — cookie consent gated with Google Consent Mode v2, layered email consent captured in HubSpot as five distinct signals instead of one flag, and suppression logic verified against a live, shared HubSpot portal rather than a clean sandbox. Built entirely on free-tier tools.
The actual pipeline this page describes — every arrow below is backed by a real screenshot, not a diagram of an intention.
The problem
Lumen Metrics, a small e-commerce analytics SaaS company, had spent eight months growing its contact database with no consent discipline: every demo request, ebook download, and imported conference lead was emailed the same way, with no record of who had actually agreed to marketing contact — and no cookie consent on the website at all, with analytics tracking firing unconditionally on every page load. As the company's first Marketing Operations hire, the brief was to answer one question with evidence, not assumptions: can this database actually be used legally and safely for marketing?
What I set out to build
Cookie/tracking consent that genuinely gates analytics — not a banner that displays while tracking fires anyway.
Marketing email consent modeled as its own explicit, unbundled, non-required choice — never inferred from someone simply submitting a form.
A HubSpot data model that separates tracking consent, marketing consent, legal basis, and subscription status, rather than one generic flag.
Suppression logic that actively controls who's eligible for a send, not just a dashboard that describes who should be.
A system I could prove was working, not just assert — evidenced with real screenshots, not staged ones.
How the pieces fit together
The system runs as two deliberately separate layers, meeting only at the moment a real send happens.
HubSpot's native subscription status and legal-basis property. This layer is unconditional — no custom logic built on top of it can override it, which is exactly why it's the layer this project's suppression segments were checked against.
Six purpose-built properties and four rule-based segments, engineered specifically to represent what HubSpot's free tier has no native way to model — category-level marketing consent chief among them.
Consent is modeled as five distinct signals rather than one flag:
Cookie/tracking consent
Can this anonymous browser be tracked — held in localStorage, signaled to GTM's dataLayer.
Marketing consent, by category
Did this known contact agree to Product Updates, Promotions, or Sales Outreach — specifically, not generically.
Legal basis
Why we may process this person's data at all, which can differ from why we may email them.
Subscription status
HubSpot's native, unconditional enforcement layer — the layer that actually blocks a send.
Data subject rights
Has this person asked to see, correct, or delete their data — captured, not assumed.
Stack
What's actually running
Cookie consent banner
Hand-built in vanilla JavaScript rather than a packaged CMP. Stores the visitor's choice in
localStorage, re-announces it to the dataLayer on every page load, and stays reopenable anytime via a persistent "Cookie Settings" control in the footer.The banner live on lumenmetrics.dev — Necessary Only or Accept Analytics, with no pre-checked assumption either way.
Google Tag Manager & Consent Mode v2
A Consent Initialization tag sets Google Consent Mode v2 defaults to denied before anything else runs. A custom trigger, reading the banner's own consent event through a Data Layer Variable, is the only trigger available to the GA4 tag — meaning GA4 is structurally incapable of firing before consent, not merely delayed.
Before consent: GA4 Realtime shows 0 active users, despite the page having fully loaded.
Seconds after clicking "Accept Analytics": 1 active user appears — tracking begins exactly when consent is given, not before.
HubSpot CRM data model
Six custom properties in a dedicated Consent & Privacy group, modeling tracking consent, category-level marketing consent, and suppression reason as separate fields — deliberately not collapsed into one. Getting there required first auditing and archiving four unused properties from an earlier portfolio project, after hitting HubSpot Free's 10-property, portal-wide cap.
The Consent & Privacy property group as configured — six purpose-built fields, each with its own fill rate, none of them collapsed into a single flag.
HubSpot Forms
Three forms — Demo Request, Newsletter & Ebook, Manage Preferences — each unbundling "submit this form" from "agree to marketing" as two separate, optional actions.
The Demo Request form, live: requesting a demo and opting into marketing are visibly, explicitly two different actions — none of the three category boxes are pre-checked.
Preference management & real unsubscribe enforcement
A native HubSpot GDPR consent element on the Manage Preferences form ties directly to real subscription status, layered on top of the custom audit property rather than replacing it. Verified with an actual send-and-unsubscribe test, not a simulated one — HubSpot's own reporting captured the unsubscribe reason natively.
A real unsubscribe event, captured and reported natively by HubSpot — proof the preference layer is wired to the platform's actual enforcement mechanism, not just a form field.
Suppression segments
One segment,
Suppressed - Consent Not Valid, built as the single source of truth; two "Valid Marketing Contacts" segments reference its membership rather than re-implementing the same rules — a redesign made mid-build once HubSpot's actual segment-membership filter made the cleaner pattern possible.Proving it works, not just building it
QA happened in two layers: five test contacts engineered to sit right on the boundary of the rules rather than safely inside them, and three genuine free-tier platform constraints hit and resolved mid-build — all tested against a live, shared HubSpot portal already carrying contacts and properties from an earlier project, not a clean sandbox.
The Suppressed - Consent Not Valid segment, built exactly as specified — four conditions joined by OR, matching 15 of 16 contacts in the portal.
An honest read on that 93.75%
That figure looks alarming out of context, and it's worth explaining rather than hiding: this portal is shared with an earlier portfolio project, so most of that 15 is sample contacts and legacy leads that simply never had Lumen Metrics' consent properties set at all — which correctly matches the "Marketing Consent Categories is unknown" condition. It's the rule working exactly as designed on data it was never scoped to, which is itself a real lesson: a segment built to run in a production portal would need an additional filter scoping it to this project's own contacts, and I've noted that in the limitations below rather than quietly cropping the screenshot to hide it.
Portal-wide property cap — HubSpot Free's 10-custom-property limit blocked the sixth property mid-build; traced to four unused properties from an earlier project and archived them to free a slot. Fixed, verified.
Mid-build product rename — HubSpot renamed "Lists" to "Segments" across the entire product; every segment-related step had to be re-verified against the live interface rather than trusted from documentation written days earlier.
Silent archive failure — attempting to archive an old property failed with no clear cause at first, blocked by an existing asset still referencing it; resolved by locating and clearing that reference before archiving.
Segment scope check — reviewing the Valid Marketing Contacts segment surfaced one contact needing manual exclusion via HubSpot's individual-contact exclusion control, alongside the rule-based logic — a reminder that automated segmentation still benefits from a human spot-check before a real send.
What's actually verifiable
Measured: the "Valid Marketing Contacts - Product Updates & Tips" segment, filtered by category consent and membership exclusion from the Suppressed segment, resolved to exactly the two contacts predicted at design time — out of a shared portal containing sixteen. Consent Mode v2 was confirmed live: zero analytics activity before consent, tracking beginning within seconds of it being granted.
Full configuration, all documentation, and the complete test log are in the case study and documentation in the project repo.
The eligibility proof: of everyone in the portal, exactly two contacts — Sarah Chen and David Osei — resolve into this segment, matching the design's prediction exactly.
On business impact: this is demonstrated capability, not measured business impact — there's no real company or customer base behind Lumen Metrics. What's genuinely demonstrated is a system that, applied to a real company's database, would keep marketing sends restricted to people who've actually and specifically agreed to them, and make that restriction provable on demand rather than assumed.
What I'd tell a hiring manager directly
Challenges
The most instructive snags weren't compliance questions at all — they were free-tier platform mechanics: a property cap that had nothing to do with this project specifically, and a mid-build product rename that made previously-correct instructions wrong within the same week. Working around both, rather than upgrading past them, is most of what this project actually demonstrates.
Limitations
The suppression segment is currently portal-wide rather than scoped to this project's own contacts, which is correct behavior but would need an added filter before running in a shared production portal.
Custom Subscription Types and Workflow-based automation both require Marketing Hub Starter or above; this project substitutes a custom audit property and a documented manual review process instead.
Two consent-context properties (tracking and marketing consent capture dates) are populated manually per contact rather than automatically, since reliable auto-population without a paid Workflow proved fragile enough not to trust.
This is an educational portfolio project, not a certified compliance system, and does not make any real company legally GDPR or CCPA compliant.
What I'd build next
Add a project-scoping filter to every segment before this pattern is reused against a shared or production portal.
Upgrade to Marketing Hub Starter to replace the manual audit process with real Workflow-based automation.
Turn the five test scenarios into a repeatable regression checklist, re-run after any property or segment change.
Route any real deployment through actual legal review before pointing this at a real company's database.
0 likes · 0 views · Oct 19, 2026
Comprehensive project involving GTM and GA4 configuration with Consent Mode v2 to respect real-time user consent state.