feat: add Meta CAPI + Google Enhanced Conversions server-side tracking

- Add /api/conversions endpoint (Meta CAPI + GA4 Measurement Protocol)
- SHA-256 PII hashing, event_id deduplication, fbp/fbc cookies
- Client-side sendConversion() utility in PageShell.astro
- Lead event tracking on form submit in home.js
- GA4 allow_enhanced_conversions config
This commit is contained in:
Kunthawat Greethong
2026-07-02 14:50:51 +07:00
parent c20883cb4f
commit 2b423be1e4
5 changed files with 348 additions and 10 deletions

View File

@@ -78,16 +78,18 @@ const organizationJsonLd = JSON.stringify({
<!-- ConsentOS (cookie consent — load first) -->
<script src="https://consent.moreminimore.com/consent-loader.js" data-site-id="2f6d0ab5-f7d6-4d06-b299-5069c21f6238" data-api-base="https://consent.moreminimore.com"></script>
<!-- Google Analytics 4 -->
<!-- Google Analytics 4 + Enhanced Conversions -->
<script is:inline async src="https://www.googletagmanager.com/gtag/js?id=G-74BHREDLC3"></script>
<script is:inline>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-74BHREDLC3');
gtag('config', 'G-74BHREDLC3', {
allow_enhanced_conversions: true
});
</script>
<!-- Meta Pixel -->
<!-- Meta Pixel + event_id support -->
<script is:inline>
!function(f,b,e,v,n,t,s)
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
@@ -98,7 +100,57 @@ const organizationJsonLd = JSON.stringify({
s.parentNode.insertBefore(t,s)}(window, document,'script',
'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', '418349260078648');
fbq('track', 'PageView');
// Generate event_id for PageView deduplication
var pvEventId = 'pv_' + Date.now() + '_' + Math.random().toString(36).substr(2,9);
fbq('track', 'PageView', {}, {eventID: pvEventId});
</script>
<!-- Conversion Tracking Utilities -->
<script is:inline>
window.generateEventId = function(prefix) {
return (prefix || 'evt') + '_' + Date.now() + '_' +
Math.random().toString(36).substr(2,9) +
Math.random().toString(36).substr(2,9);
};
window.getMetaCookies = function() {
var c = document.cookie.split(';').reduce(function(a,x) {
var p = x.trim().split('=');
a[p[0]] = p[1]; return a;
}, {});
return { fbp: c._fbp || null, fbc: c._fbc || null };
};
window.sendConversion = function(eventName, eventData, userInfo) {
var eventId = window.generateEventId(eventName.toLowerCase());
var mc = window.getMetaCookies();
// Client-side fire
if (window.fbq) fbq('track', eventName, eventData || {}, {eventID: eventId});
if (window.gtag) gtag('event', eventName, eventData || {});
// Server-side: Meta CAPI + Google EC
fetch('/api/conversions', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
event_name: eventName,
event_id: eventId,
event_time: Math.floor(Date.now() / 1000),
event_source_url: window.location.href,
user_data: {
em: userInfo?.email || null,
ph: userInfo?.phone || null,
fn: userInfo?.firstName || null,
ln: userInfo?.lastName || null,
fbp: mc.fbp,
fbc: mc.fbc
},
custom_data: eventData || {}
})
}).catch(function(e) { console.error('[CAPI]', e); });
};
</script>
<!-- Umami Analytics -->