fix utm unicode

This commit is contained in:
dev.daminik00 2025-12-24 22:03:17 +03:00
parent 654e8899a8
commit d6ea5054c2
2 changed files with 48 additions and 9 deletions

View File

@ -30,14 +30,16 @@ export function AnalyticsScripts({ data, externalId }: AnalyticsScriptsProps) {
const googleAnalyticsIds = data?.google_analytics || [];
const yandexMetrikaIds = data?.yandex_metrica || [];
// Track which pixels have been initialized with external_id
// Track which pixels have been initialized (basic init)
const initializedPixelsRef = useRef<Set<string>>(new Set());
// Track which pixels have been enhanced with external_id
const enhancedPixelsRef = useRef<Set<string>>(new Set());
// Initialize FB Pixel when externalId becomes available
// Initialize FB Pixel immediately when SDK is ready
// external_id is OPTIONAL - we must not block tracking for users without fingerprint
useEffect(() => {
if (!externalId || facebookPixels.length === 0) return;
if (facebookPixels.length === 0) return;
// Wait for fbq to be available
const initPixels = () => {
if (!window.fbq) {
// SDK not loaded yet, retry in 100ms
@ -48,20 +50,44 @@ export function AnalyticsScripts({ data, externalId }: AnalyticsScriptsProps) {
facebookPixels.forEach((pixelId) => {
if (initializedPixelsRef.current.has(pixelId)) return;
window.fbq!("init", pixelId, { external_id: externalId });
// Initialize with external_id if available, otherwise without
// This ensures ALL users get tracked, not just those with fingerprint
if (externalId) {
window.fbq!("init", pixelId, { external_id: externalId });
enhancedPixelsRef.current.add(pixelId);
} else {
window.fbq!("init", pixelId);
}
window.fbq!("track", "PageView");
initializedPixelsRef.current.add(pixelId);
});
};
initPixels();
}, [facebookPixels, externalId]);
// Enhance already-initialized pixels with external_id when it becomes available later
// This improves matching for Conversions API deduplication
useEffect(() => {
if (!externalId || facebookPixels.length === 0) return;
if (!window.fbq) return;
facebookPixels.forEach((pixelId) => {
// Only enhance if pixel was initialized but not yet enhanced with external_id
if (initializedPixelsRef.current.has(pixelId) && !enhancedPixelsRef.current.has(pixelId)) {
// Re-init with external_id for better matching (doesn't fire PageView again)
window.fbq!("init", pixelId, { external_id: externalId });
enhancedPixelsRef.current.add(pixelId);
}
});
}, [externalId, facebookPixels]);
if (!data) return null;
return (
<>
{/* Facebook Pixel SDK - loads immediately, init happens in useEffect when externalId ready */}
{/* Facebook Pixel SDK - loads immediately, init happens in useEffect (with or without externalId) */}
{facebookPixels.length > 0 && (
<Script
id="fb-pixel-sdk"

View File

@ -65,17 +65,30 @@ export const getCurrentQueryParams = (): Record<string, string> => {
return utmParams;
};
/**
* Convert bytes to base64 string (handles UTF-8 properly)
* MDN recommended approach: https://developer.mozilla.org/en-US/docs/Web/API/Window/btoa#unicode_strings
*/
const bytesToBase64 = (bytes: Uint8Array): string => {
const binString = Array.from(bytes, (byte) =>
String.fromCodePoint(byte)
).join("");
return btoa(binString);
};
/**
* Encode params as base64 JSON for state parameter
* Uses URL-safe base64 encoding
* Uses URL-safe base64 encoding with UTF-8 support
* Handles Unicode characters (e.g., utm_campaign=)
*/
export const encodeStateParam = (params: Record<string, string>): string => {
if (Object.keys(params).length === 0) return "";
try {
const json = JSON.stringify(params);
// Use btoa for base64, replace unsafe chars for URL
const base64 = btoa(json)
// Encode string as UTF-8 bytes, then convert to base64
const bytes = new TextEncoder().encode(json);
const base64 = bytesToBase64(bytes)
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");