Proxy de Flowsery Analytics con Next.js
Enruta Flowsery Analytics a través de tu propio dominio en una aplicación Next.js para evitar la interferencia de los adblockers y capturar datos de visitantes precisos.
Hay dos pasos para tener un proxy completo: un rewrite (hace que el tracker sea first-party para que sobreviva a los adblockers) y middleware (reenvía la IP real del visitante al backend de Flowsery). Los rewrites por sí solos entregarán eventos, pero todos los visitantes aparecerán desde la región de tu servidor: necesitas ambos.
1. Configura los rewrites
Agrega o actualiza tu next.config.js en la raíz del proyecto:
module.exports = {
async rewrites() {
return [
{
source: '/js/main.js',
destination: 'https://cdn.flowsery.com/main.js',
},
{
source: '/api/track',
destination: 'https://analytics.flowsery.com/analytics/events',
},
{
source: '/:locale/api/track',
destination: 'https://analytics.flowsery.com/analytics/events',
},
];
},
};Si tu proyecto ya usa /api/track, elige otra ruta y pásala mediante data-api en el script del tracker, por ejemplo data-api="/flowsery-events".
2. Inyecta la IP real del visitante (middleware)
Los rewrites de Next.js hacen un fetch servidor a servidor, así que el edge Cloudflare de destino reemplaza cf-connecting-ip por la IP de tu servidor Next.js. Entonces Flowsery ve a todos los visitantes como “tu servidor” y resuelve la geolocalización según tu región de hosting.
Para solucionarlo, agrega middleware que lea la IP real del visitante al llegar y la fije en un encabezado personalizado x-flowsery-real-ip. Ese encabezado personalizado sobrevive intacto al salto del proxy, y el backend de Flowsery lo prioriza sobre cf-connecting-ip cuando está presente.
Crea o actualiza middleware.ts en la raíz del proyecto:
import { NextRequest, NextResponse } from 'next/server';
const TRACKING_PROXY_PATHS = /\/api\/track$/;
export default function middleware(request: NextRequest) {
if (!TRACKING_PROXY_PATHS.test(request.nextUrl.pathname)) {
return NextResponse.next();
}
const realIp = request.headers.get('cf-connecting-ip') || request.headers.get('x-forwarded-for')?.split(',')[0]?.trim();
if (!realIp) return NextResponse.next();
const forwardedHeaders = new Headers(request.headers);
forwardedHeaders.set('x-flowsery-real-ip', realIp);
return NextResponse.next({
request: { headers: forwardedHeaders },
});
}
export const config = {
matcher: ['/api/track', '/:locale/api/track'],
};Si ya tienes middleware
Hay dos cosas que debes fusionar con cuidado:
1. El handler. Ejecuta primero la lógica del proxy de tracking para las rutas /api/track y luego deja que continúe tu lógica actual:
export default function middleware(request: NextRequest) {
// Runs for /api/track + /:locale/api/track. Returns a response only when
// the path matches, otherwise returns NextResponse.next() so your existing
// logic runs below.
if (/\/api\/track$/.test(request.nextUrl.pathname)) {
const realIp = request.headers.get('cf-connecting-ip') || request.headers.get('x-forwarded-for')?.split(',')[0]?.trim();
if (realIp) {
const headers = new Headers(request.headers);
headers.set('x-flowsery-real-ip', realIp);
return NextResponse.next({ request: { headers } });
}
return NextResponse.next();
}
// ...your existing middleware logic here (locale detection, auth, etc.)
}2. El matcher. Mucho middleware de páginas usa una negative lookahead como /((?!api/|_next/...).*) para excluir rutas de API. Ese patrón también excluirá /api/track, así que el middleware nunca se ejecutará para la ruta de tracking. Extiende el array matcher para volver a incluirla:
export const config = {
matcher: [
// Your existing page-level pattern — leave it alone.
'/((?!api/|js/|_next/static|_next/image|favicon.ico|locales|ingest).*)',
// Added so middleware also runs for the tracking proxy paths.
'/api/track',
'/:locale/api/track',
],
};El orden no importa. Las entradas del matcher se evalúan con OR: una ruta ejecuta el middleware si cualquiera de las entradas coincide. Las rutas de página siguen usando tu patrón existente; /api/track coincide con la nueva entrada explícita y llega al handler de tracking anterior.
3. Modifica la etiqueta del script
Haz que el script apunte a la ruta local con proxy:
<script defer data-fl-website-id="flid_******" src="/js/main.js"></script>4. Despliega
El rewrite y el middleware entran en vigor al desplegar.
Confirmar que funciona
- Abre tu sitio en una pestaña normal del navegador.
- Abre DevTools, ve a Network y filtra por
/api/track. - Confirma que cada solicitud va a tu propio dominio, no a
analytics.flowsery.com. - En tu panel de Flowsery, comprueba que los países y ciudades reflejan a tu audiencia y no la región de tu hosting.
Solución de problemas
Todos los visitantes aparecen desde la misma ubicación
Si todos los visitantes muestran una única ubicación geográfica, normalmente la región de tu servidor, el paso del middleware no está aplicando el encabezado x-flowsery-real-ip.
Causas comunes:
- El matcher del middleware no incluye la ruta de tracking. Muchos matchers existentes usan una negative lookahead como
/((?!api/|...).*), que excluye/api/*. Agrega/api/tracky/:locale/api/trackcomo entradas explícitas en el arraymatcher. - Agregaste el encabezado a la respuesta en lugar de a la solicitud. El backend lee los encabezados de la solicitud. Usa
NextResponse.next({ request: { headers } }), noresponse.headers.set(...). - Tu proveedor edge no es Cloudflare. Si estás detrás de Vercel, Fly.io u otro edge, lee la IP del visitante desde el encabezado de ese edge (
x-real-ip,x-vercel-forwarded-for,fly-client-ip, etc.).