feat(analytics): update Google Analytics integration and improve fetch interception
- Refactored Google Analytics proxy routes in the Next.js configuration to enhance fallback handling. - Improved fetch interception logic in the RootLayout component for more robust handling of Google Analytics requests, including support for `sendBeacon`. - Updated the analytics script source to align with new API routes for better tracking accuracy.
This commit is contained in:
1 parent
ad6a76efdd
commit
c9b057b674
4 files changed
+154
-19
No files matched your search
@@ -0,0 +1,47 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
export async function GET(
|
||||
request: NextRequest,
|
||||
{ params }: { params: { id: string } }
|
||||
) {
|
||||
const { id } = params;
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`https://www.googletagmanager.com/gtag/js?id=${id}`,
|
||||
{
|
||||
headers: {
|
||||
'User-Agent': request.headers.get('user-agent') || '',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
return new NextResponse('Script not found', { status: 404 });
|
||||
}
|
||||
|
||||
const scriptContent = await response.text();
|
||||
|
||||
// Modificar URLs internas do script para usar o proxy
|
||||
const modifiedScript = scriptContent
|
||||
.replace(
|
||||
/https?:\/\/[^\/]*google-analytics\.com\/g\/collect/g,
|
||||
'/api/metrics'
|
||||
)
|
||||
.replace(
|
||||
/https?:\/\/[^\/]*google-analytics\.com/g,
|
||||
'/api/metrics'
|
||||
);
|
||||
|
||||
return new NextResponse(modifiedScript, {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/javascript',
|
||||
'Cache-Control': 'public, max-age=3600',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('GTM proxy error:', error);
|
||||
return new NextResponse('Proxy error', { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const searchParams = request.nextUrl.searchParams;
|
||||
const url = new URL('https://www.google-analytics.com/g/collect');
|
||||
|
||||
// Copiar todos os parâmetros da query string
|
||||
searchParams.forEach((value, key) => {
|
||||
url.searchParams.append(key, value);
|
||||
});
|
||||
|
||||
try {
|
||||
const response = await fetch(url.toString(), {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'User-Agent': request.headers.get('user-agent') || '',
|
||||
'Accept-Language': request.headers.get('accept-language') || '',
|
||||
},
|
||||
});
|
||||
|
||||
return new NextResponse(null, {
|
||||
status: response.status,
|
||||
headers: {
|
||||
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Google Analytics proxy error:', error);
|
||||
return new NextResponse(null, { status: 200 }); // Retornar 200 para não quebrar o tracking
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
const searchParams = request.nextUrl.searchParams;
|
||||
const url = new URL('https://www.google-analytics.com/g/collect');
|
||||
|
||||
// Copiar todos os parâmetros da query string
|
||||
searchParams.forEach((value, key) => {
|
||||
url.searchParams.append(key, value);
|
||||
});
|
||||
|
||||
try {
|
||||
const body = await request.text();
|
||||
|
||||
const response = await fetch(url.toString(), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'User-Agent': request.headers.get('user-agent') || '',
|
||||
'Accept-Language': request.headers.get('accept-language') || '',
|
||||
'Content-Type': 'text/plain',
|
||||
},
|
||||
body: body || undefined,
|
||||
});
|
||||
|
||||
return new NextResponse(null, {
|
||||
status: response.status,
|
||||
headers: {
|
||||
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Google Analytics proxy error:', error);
|
||||
return new NextResponse(null, { status: 200 });
|
||||
}
|
||||
}
|
||||
+39
-7
@@ -201,11 +201,19 @@ export default function RootLayout({ children }: Readonly<RootLayoutProps>) {
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
(function() {
|
||||
// Interceptar fetch
|
||||
// Interceptar fetch - método mais robusto
|
||||
const originalFetch = window.fetch;
|
||||
window.fetch = function(url, options) {
|
||||
if (typeof url === 'string' && url.includes('google-analytics.com')) {
|
||||
url = url.replace('https://www.google-analytics.com', '/ga');
|
||||
if (typeof url === 'string') {
|
||||
// Interceptar google-analytics.com/g/collect
|
||||
if (url.includes('google-analytics.com/g/collect')) {
|
||||
const urlObj = new URL(url);
|
||||
url = '/api/metrics' + urlObj.search;
|
||||
}
|
||||
// Interceptar outros endpoints do google-analytics.com
|
||||
else if (url.includes('google-analytics.com')) {
|
||||
url = url.replace(/https?:\\/\\/[^\\/]*google-analytics\\.com/g, '/api/metrics');
|
||||
}
|
||||
}
|
||||
return originalFetch.call(this, url, options);
|
||||
};
|
||||
@@ -213,18 +221,39 @@ export default function RootLayout({ children }: Readonly<RootLayoutProps>) {
|
||||
// Interceptar XMLHttpRequest
|
||||
const originalOpen = XMLHttpRequest.prototype.open;
|
||||
XMLHttpRequest.prototype.open = function(method, url, ...rest) {
|
||||
if (typeof url === 'string' && url.includes('google-analytics.com')) {
|
||||
url = url.replace('https://www.google-analytics.com', '/ga');
|
||||
if (typeof url === 'string') {
|
||||
if (url.includes('google-analytics.com/g/collect')) {
|
||||
const urlObj = new URL(url);
|
||||
url = '/api/metrics' + urlObj.search;
|
||||
}
|
||||
else if (url.includes('google-analytics.com')) {
|
||||
url = url.replace(/https?:\\/\\/[^\\/]*google-analytics\\.com/g, '/api/metrics');
|
||||
}
|
||||
}
|
||||
return originalOpen.call(this, method, url, ...rest);
|
||||
};
|
||||
|
||||
// Interceptar sendBeacon (método usado pelo GA4)
|
||||
const originalSendBeacon = navigator.sendBeacon;
|
||||
navigator.sendBeacon = function(url, data) {
|
||||
if (typeof url === 'string') {
|
||||
if (url.includes('google-analytics.com/g/collect')) {
|
||||
const urlObj = new URL(url);
|
||||
return originalSendBeacon.call(this, '/api/metrics' + urlObj.search, data);
|
||||
}
|
||||
else if (url.includes('google-analytics.com')) {
|
||||
url = url.replace(/https?:\\/\\/[^\\/]*google-analytics\\.com/g, '/api/metrics');
|
||||
}
|
||||
}
|
||||
return originalSendBeacon.call(this, url, data);
|
||||
};
|
||||
})();
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
{/* Google Analytics - Script principal via proxy */}
|
||||
<Script
|
||||
src="/gtm/js/G-QTT9QT0T3S"
|
||||
src="/api/gtm/G-QTT9QT0T3S"
|
||||
strategy="afterInteractive"
|
||||
async
|
||||
/>
|
||||
@@ -237,7 +266,10 @@ export default function RootLayout({ children }: Readonly<RootLayoutProps>) {
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-QTT9QT0T3S');
|
||||
gtag('config', 'G-QTT9QT0T3S', {
|
||||
// Forçar uso de fetch em vez de imagem beacon
|
||||
transport_type: 'fetch'
|
||||
});
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
|
||||
Reference in new issue
Block a user