mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-07 08:26:51 +00:00
feat: implement enhanced conversion tracking for Google Ads
- Add SHA256 hashing for user data to support enhanced conversions - Update trackGoogleAdsConversion to accept optional user data - Add new trackPageViewConversion for automatic event tracking - Replace direct onClick handlers with proper async tracking - Ensure consent is checked before any tracking occurs This addresses the Google Ads warning about implementing in-page code for enhanced conversions instead of relying on automatic detection.
This commit is contained in:
parent
d0e519de3f
commit
85a16a74a7
2 changed files with 186 additions and 12 deletions
|
|
@ -11,6 +11,7 @@ import {
|
|||
MessageSquareCode,
|
||||
} from "lucide-react"
|
||||
import Image from "next/image"
|
||||
import { useCallback } from "react"
|
||||
|
||||
import { Button } from "@/components/ui"
|
||||
import { AnimatedBackground } from "@/components/homepage"
|
||||
|
|
@ -77,6 +78,30 @@ const howItWorks: Feature[] = [
|
|||
import hero from "/public/heroes/agent-reviewer.png"
|
||||
|
||||
export function ReviewerContent() {
|
||||
// Track the conversion with enhanced data when user clicks to start trial
|
||||
const handleTrialSignupClick = useCallback(async (_e: React.MouseEvent<HTMLAnchorElement>) => {
|
||||
// Don't prevent default - let the link work normally
|
||||
|
||||
// Track enhanced conversion for trial signup
|
||||
// Using async function to allow proper event tracking before navigation
|
||||
try {
|
||||
await trackGoogleAdsConversion(
|
||||
"VtOZCJe_77MbEInXkOVA", // PR Reviewer trial signup conversion label
|
||||
10.0, // Trial value
|
||||
// Enhanced conversion data can be added here when available
|
||||
// For example, if user data is available from context:
|
||||
// {
|
||||
// email: userEmail,
|
||||
// firstName: userFirstName,
|
||||
// lastName: userLastName
|
||||
// }
|
||||
)
|
||||
} catch (error) {
|
||||
// Don't block navigation if tracking fails
|
||||
console.error("Conversion tracking error:", error)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className="relative flex md:h-[calc(70vh-theme(spacing.12))] items-center overflow-hidden">
|
||||
|
|
@ -110,7 +135,7 @@ export function ReviewerContent() {
|
|||
href={EXTERNAL_LINKS.CLOUD_APP_SIGNUP_PRO}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
onClick={trackGoogleAdsConversion}
|
||||
onClick={handleTrialSignupClick}
|
||||
className="flex w-full items-center justify-center">
|
||||
Start 14-day Free Trial
|
||||
<ArrowRight className="ml-2" />
|
||||
|
|
@ -264,7 +289,7 @@ export function ReviewerContent() {
|
|||
href={EXTERNAL_LINKS.CLOUD_APP_SIGNUP_PRO}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
onClick={trackGoogleAdsConversion}
|
||||
onClick={handleTrialSignupClick}
|
||||
className="flex items-center justify-center">
|
||||
Start 14-day Free Trial
|
||||
<ArrowRight className="ml-2 h-4 w-4" />
|
||||
|
|
|
|||
|
|
@ -1,17 +1,166 @@
|
|||
/**
|
||||
* Google Ads conversion tracking utilities
|
||||
* Google Ads conversion tracking utilities with enhanced conversions support
|
||||
* Implements manual enhanced conversion tracking for better attribution
|
||||
*/
|
||||
|
||||
import { hasConsent } from "./consent-manager"
|
||||
|
||||
/**
|
||||
* Track a Google Ads conversion event
|
||||
* This should only be called after user consent has been given
|
||||
* SHA256 hash function for enhanced conversion data
|
||||
* Required for properly hashing user data before sending to Google
|
||||
*/
|
||||
export function trackGoogleAdsConversion() {
|
||||
if (typeof window !== "undefined" && window.gtag) {
|
||||
window.gtag("event", "conversion", {
|
||||
send_to: "AW-17391954825/VtOZCJe_77MbEInXkOVA",
|
||||
value: 10.0,
|
||||
currency: "USD",
|
||||
})
|
||||
async function sha256(text: string): Promise<string> {
|
||||
const utf8 = new TextEncoder().encode(text.toLowerCase().trim())
|
||||
const hashBuffer = await crypto.subtle.digest("SHA-256", utf8)
|
||||
const hashArray = Array.from(new Uint8Array(hashBuffer))
|
||||
return hashArray.map((byte) => byte.toString(16).padStart(2, "0")).join("")
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for enhanced conversion user data
|
||||
*/
|
||||
interface EnhancedConversionData {
|
||||
email?: string
|
||||
phone?: string
|
||||
firstName?: string
|
||||
lastName?: string
|
||||
address?: {
|
||||
street?: string
|
||||
city?: string
|
||||
region?: string
|
||||
postalCode?: string
|
||||
country?: string
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare and hash user data for enhanced conversions
|
||||
* All data is hashed using SHA256 before sending to Google
|
||||
*/
|
||||
async function prepareEnhancedData(
|
||||
userData?: EnhancedConversionData,
|
||||
): Promise<Record<string, string | Record<string, string>[]> | null> {
|
||||
if (!userData) return null
|
||||
|
||||
const enhancedData: Record<string, string | Record<string, string>[]> = {}
|
||||
|
||||
try {
|
||||
if (userData.email) {
|
||||
enhancedData.email = await sha256(userData.email)
|
||||
}
|
||||
if (userData.phone) {
|
||||
// Remove non-numeric characters and add country code if missing
|
||||
const cleanPhone = userData.phone.replace(/[^0-9]/g, "")
|
||||
enhancedData.phone = await sha256(cleanPhone)
|
||||
}
|
||||
if (userData.firstName) {
|
||||
enhancedData.first_name = await sha256(userData.firstName)
|
||||
}
|
||||
if (userData.lastName) {
|
||||
enhancedData.last_name = await sha256(userData.lastName)
|
||||
}
|
||||
if (userData.address) {
|
||||
const address: Record<string, string> = {}
|
||||
if (userData.address.street) {
|
||||
address.street = await sha256(userData.address.street)
|
||||
}
|
||||
if (userData.address.city) {
|
||||
address.city = await sha256(userData.address.city)
|
||||
}
|
||||
if (userData.address.region) {
|
||||
address.region = await sha256(userData.address.region)
|
||||
}
|
||||
if (userData.address.postalCode) {
|
||||
address.postal_code = await sha256(userData.address.postalCode)
|
||||
}
|
||||
if (userData.address.country) {
|
||||
address.country = await sha256(userData.address.country)
|
||||
}
|
||||
if (Object.keys(address).length > 0) {
|
||||
enhancedData.address = [address]
|
||||
}
|
||||
}
|
||||
|
||||
return Object.keys(enhancedData).length > 0 ? enhancedData : null
|
||||
} catch (error) {
|
||||
console.error("Error preparing enhanced conversion data:", error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Track a Google Ads conversion event with enhanced conversions
|
||||
* Implements manual enhanced conversion tracking for improved accuracy
|
||||
*
|
||||
* @param conversionLabel - Optional conversion label (defaults to PR Reviewer trial signup)
|
||||
* @param value - Optional conversion value
|
||||
* @param userData - Optional user data for enhanced conversions
|
||||
*/
|
||||
export async function trackGoogleAdsConversion(
|
||||
conversionLabel = "VtOZCJe_77MbEInXkOVA",
|
||||
value = 10.0,
|
||||
userData?: EnhancedConversionData,
|
||||
) {
|
||||
// Only track if consent has been given
|
||||
if (!hasConsent()) {
|
||||
console.log("Google Ads conversion tracking skipped - no consent")
|
||||
return
|
||||
}
|
||||
|
||||
if (typeof window !== "undefined" && window.gtag) {
|
||||
try {
|
||||
// Prepare enhanced conversion data if provided
|
||||
const enhancedData = await prepareEnhancedData(userData)
|
||||
|
||||
// Build the conversion event parameters
|
||||
const conversionParams: Record<
|
||||
string,
|
||||
string | number | Record<string, string | Record<string, string>[]>
|
||||
> = {
|
||||
send_to: `AW-17391954825/${conversionLabel}`,
|
||||
value: value,
|
||||
currency: "USD",
|
||||
}
|
||||
|
||||
// Add enhanced conversion data if available
|
||||
if (enhancedData) {
|
||||
conversionParams.user_data = enhancedData
|
||||
}
|
||||
|
||||
// Send the conversion event
|
||||
window.gtag("event", "conversion", conversionParams)
|
||||
|
||||
console.log("Google Ads conversion tracked with enhanced data")
|
||||
} catch (error) {
|
||||
console.error("Error tracking Google Ads conversion:", error)
|
||||
// Fall back to basic conversion tracking
|
||||
window.gtag("event", "conversion", {
|
||||
send_to: `AW-17391954825/${conversionLabel}`,
|
||||
value: value,
|
||||
currency: "USD",
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Track a page view conversion (for automatic event tracking)
|
||||
* Used when the conversion should fire on page load rather than user action
|
||||
*/
|
||||
export function trackPageViewConversion(conversionLabel = "VtOZCJe_77MbEInXkOVA", value = 10.0) {
|
||||
// Only track if consent has been given
|
||||
if (!hasConsent()) {
|
||||
return
|
||||
}
|
||||
|
||||
if (typeof window !== "undefined" && window.gtag) {
|
||||
// Use a slight delay to ensure gtag is fully initialized
|
||||
setTimeout(() => {
|
||||
window.gtag("event", "page_view", {
|
||||
send_to: `AW-17391954825/${conversionLabel}`,
|
||||
value: value,
|
||||
currency: "USD",
|
||||
})
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue