Rastreamento de Primeira Parte com Cloudflare Pages
Configure um proxy de primeira parte usando Cloudflare Pages Functions. Esta é a melhor opção se você já está hospedando seu site no Cloudflare Pages.
Dificuldade: Fácil - Apenas adicione um arquivo ao seu projeto. Leva cerca de 5 minutos.
Por que isso funciona (Mesma origem)
Esta abordagem usa /api/_z/script.js que está na mesma origem do seu site. Firefox ETP e outras proteções de rastreamento bloqueiam apenas solicitações de origem cruzada.
- O navegador vê:
seudominio.com/api/_z/script.js→ Mesma origem ✅ - Sua função faz proxy servidor para servidor Zenovay (o navegador nunca vê isso)
- Toda proteção de rastreamento é ignorada porque a solicitação é de primeira parte
Antes de começar
Certifique-se de que você tem:
- Um projeto implantado no Cloudflare Pages
- Seu código de rastreamento Zenovay (encontrado em Domains, abra seu site e depois a aba General — no cartão de script de rastreamento)
- Acesso ao código-fonte do seu projeto
Formato do seu código de rastreamento
Seu código de rastreamento se parece com: ZV_XXXXXXXXXX
- Começa com
ZV_ - Seguido por 10 caracteres (letras e números)
- CASE-SENSITIVE - copie exatamente
Exemplo: ZV_Q8U0GYD70WR

Como funciona
Quando você adiciona uma pasta functions ao seu projeto Cloudflare Pages, o Cloudflare cria automaticamente funções sem servidor. Criaremos uma função que faz proxy de solicitações para a API Zenovay, fazendo-as parecer solicitações de primeira parte para navegadores.
Navegador → seudominio.pages.dev/api/_z/script.js ✅ (Primeira parte)
↓
Função Cloudflare
↓
api.zenovay.com/fp/script.js (Servidor para servidor)
Passo 1: Criar o diretório de funções
Localização do arquivo é CRÍTICA
A pasta functions DEVE estar na raiz do seu projeto. Não dentro de src/, não dentro de public/.
Localização correta:
seu-projeto/
├── functions/ ← AQUI (raiz do projeto)
│ └── api/
│ └── _z/
│ └── [[path]].ts
├── src/
├── public/
└── package.json
LOCALIZAÇÕES ERRADAS:
- ❌
src/functions/api/_z/[[path]].ts- Funções não funcionarão - ❌
public/functions/api/_z/[[path]].ts- Funções não funcionarão
Crie a estrutura de diretórios:
# Criar a estrutura de diretório de funções
mkdir -p functions/api/_z
# Verifique se você está no lugar certo
ls -la
# Você deve ver: functions/ src/ public/ package.json etc.Após executar esses comandos, a estrutura do seu projeto deve ficar assim:
seu-projeto/
├── functions/
│ └── api/
│ └── _z/
│ └── [[path]].ts ← Criaremos isso a seguir
├── src/
├── public/
├── package.json
└── ...
Passo 2: Criar a função de proxy
A nomeação do arquivo é IMPORTANTE
O arquivo DEVE ser chamado [[path]].ts (ou [[path]].js para JavaScript):
- Dois colchetes de abertura:
[[ - A palavra
path - Dois colchetes de fechamento:
]] - Extensão do arquivo:
.tsou.js
Isso cria uma rota "catch-all" que lida com qualquer caminho após /api/_z/.
TypeScript ou JavaScript?
- Use
.tsse seu projeto usa TypeScript - Use
.jsse seu projeto usa JavaScript - Ambos funcionam exatamente da mesma forma
Se não tiver certeza, tente .ts primeiro. Se você receber erros de TypeScript durante a compilação, renomeie para .js.
Crie o arquivo functions/api/_z/[[path]].ts com este conteúdo:
/**
* Zenovay First-Party Proxy
* This function proxies tracking requests to make them first-party
*/
interface EventContext {
request: Request
params: { path?: string[] }
}
export async function onRequest(context: EventContext): Promise<Response> {
const { request, params } = context
// Build path from catch-all parameter
// [[path]] captures: script.js, e/CODE, settings/CODE, etc.
const path = (params.path || []).join('/')
const url = new URL(request.url)
const targetUrl = `https://api.zenovay.com/fp/${path}${url.search}`
// Handle CORS preflight requests
if (request.method === 'OPTIONS') {
return new Response(null, {
status: 204,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
},
})
}
try {
// Get the real client IP for accurate geolocation
const clientIP = request.headers.get('CF-Connecting-IP') || ''
// Forward request with real IP
const proxyHeaders = new Headers(request.headers)
proxyHeaders.set('X-Zenovay-Real-IP', clientIP)
proxyHeaders.delete('Host')
// Build the request
const requestInit: RequestInit = {
method: request.method,
headers: proxyHeaders,
}
// Include body for POST/PUT/PATCH requests
if (['POST', 'PUT', 'PATCH'].includes(request.method)) {
requestInit.body = await request.arrayBuffer()
}
// Forward to Zenovay
const response = await fetch(targetUrl, requestInit)
// Add CORS headers to response
const responseHeaders = new Headers(response.headers)
responseHeaders.set('Access-Control-Allow-Origin', '*')
return new Response(response.body, {
status: response.status,
headers: responseHeaders,
})
} catch (error) {
console.error('Proxy error:', error)
return new Response(JSON.stringify({ error: 'Proxy error' }), {
status: 502,
headers: { 'Content-Type': 'application/json' },
})
}
}Alternativa JavaScript
Se você preferir JavaScript (sem TypeScript), crie functions/api/_z/[[path]].js:
/**
* Zenovay First-Party Proxy
* This function proxies tracking requests to make them first-party
*/
export async function onRequest(context) {
const { request, params } = context
// Build path from catch-all parameter
const path = (params.path || []).join('/')
const url = new URL(request.url)
const targetUrl = `https://api.zenovay.com/fp/${path}${url.search}`
// Handle CORS preflight requests
if (request.method === 'OPTIONS') {
return new Response(null, {
status: 204,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
},
})
}
try {
// Get the real client IP for accurate geolocation
const clientIP = request.headers.get('CF-Connecting-IP') || ''
// Forward request with real IP
const headers = new Headers(request.headers)
headers.set('X-Zenovay-Real-IP', clientIP)
headers.delete('Host')
// Forward to Zenovay
const response = await fetch(targetUrl, {
method: request.method,
headers: headers,
body: ['POST', 'PUT', 'PATCH'].includes(request.method)
? await request.arrayBuffer()
: undefined,
})
// Add CORS headers to response
const responseHeaders = new Headers(response.headers)
responseHeaders.set('Access-Control-Allow-Origin', '*')
return new Response(response.body, {
status: response.status,
headers: responseHeaders,
})
} catch (error) {
return new Response(JSON.stringify({ error: 'Proxy error' }), {
status: 502,
headers: { 'Content-Type': 'application/json' },
})
}
}Passo 3: Adicionar o script de rastreamento
Adicione este script ao HTML do seu site. A localização depende do seu framework:
<!-- Zenovay Analytics - First-Party Tracking -->
<script defer
data-tracking-code="YOUR_TRACKING_CODE"
src="/api/_z/script.js">
</script>Substitua YOUR_TRACKING_CODE pelo seu código de rastreamento real do painel Zenovay (por exemplo, ZV_Q8U0GYD70WR).
Exemplos específicos de frameworks
React / Next.js
export default function RootLayout({ children }) {
return (
<html lang="en">
<head>
<script
defer
data-tracking-code="YOUR_TRACKING_CODE"
src="/api/_z/script.js"
/>
</head>
<body>{children}</body>
</html>
)
}Vue / Nuxt
<!-- In app.vue -->
<script setup>
useHead({
script: [
{
src: '/api/_z/script.js',
defer: true,
'data-tracking-code': 'YOUR_TRACKING_CODE'
}
]
})
</script>Astro
---
const { title } = Astro.props;
---
<html lang="en">
<head>
<title>{title}</title>
<script defer data-tracking-code="YOUR_TRACKING_CODE" src="/api/_z/script.js"></script>
</head>
<body>
<slot />
</body>
</html>HTML simples
<!DOCTYPE html>
<html>
<head>
<title>My Website</title>
<script defer data-tracking-code="YOUR_TRACKING_CODE" src="/api/_z/script.js"></script>
</head>
<body>
<!-- Your content -->
</body>
</html>Passo 4: Implantar
Implante seu projeto no Cloudflare Pages:
Opção A: Usando Git (Recomendado)
Se você tiver implantações automáticas do Git:
git add .
git commit -m "Add Zenovay first-party tracking"
git pushO Cloudflare Pages compilará e implantará automaticamente.
Opção B: Usando Wrangler CLI
# Compile seu projeto primeiro
npm run build
# Faça deploy no Cloudflare Pages
npx wrangler pages deploy ./dist --project-name=your-project-nameSubstitua ./dist pelo seu diretório de saída de compilação (pode ser ./out, ./build, etc.) e your-project-name pelo nome do seu projeto Cloudflare Pages.
Passo 5: Verificar se está funcionando
Verificação 1: Aba Functions no Cloudflare
- Vá para Cloudflare Dashboard → Pages
- Clique em seu projeto
- Clique na aba Functions
- Você deve ver
api/_z/[[path]]listado
Não vê a função?
- Certifique-se de que a pasta
functions/está na raiz do projeto (não dentro desrc/) - Certifique-se de que o arquivo é nomeado
[[path]].tsou[[path]].js - Verifique se a implantação foi concluída com sucesso
Verificação 2: Aba de rede no navegador
- Abra seu site implantado
- Pressione F12 (ou Cmd+Option+I no Mac) para abrir DevTools
- Clique na aba Network
- Atualize a página (Cmd+R ou Ctrl+R)
- Na caixa de filtro, digite
script.js - Procure por
/api/_z/script.js
O que você deve ver:
- Status: 200 ✅
- Domain: Seu domínio Pages (por exemplo,
seu-projeto.pages.dev) - Response: Código JavaScript
Verificação 3: Modo estrito do Firefox (Mais importante!)
Firefox tem a proteção de rastreamento mais rigorosa. Se funcionar no Firefox, funciona em todos os lugares.
- Abra o navegador Firefox
- Clique no menu (☰) → Settings
- Clique em Privacy & Security na barra lateral esquerda
- Em "Enhanced Tracking Protection", selecione Strict
- Visite seu site
- Abra DevTools (F12) → aba Network
- Atualize e verifique se
/api/_z/script.jscarrega com status 200
Verificação 4: Painel Zenovay
- Vá para app.zenovay.com e faça login
- Clique em seu site
- Visite seu site implantado em outra aba
- Em 1-2 minutos, você deve ver a visita aparecer em seu painel
Lista de verificação final
Antes de terminar, verifique TODOS estes itens:
- O arquivo
functions/api/_z/[[path]].tsexiste na raiz do projeto - A função aparece na aba Functions do Cloudflare Pages
- O script carrega em
/api/_z/script.jscom status 200 - O atributo
data-tracking-codecontém seu código de rastreamento correto - Testado no Firefox com Enhanced Tracking Protection definido como Strict
- Visitas aparecendo no painel Zenovay
Solução de problemas
A função retorna 404
Causa: O arquivo da função está no local errado ou tem o nome errado.
Solução:
- Verifique se o arquivo está exatamente em
functions/api/_z/[[path]].ts- A pasta
functionsdeve estar na raiz do projeto - Deve ter os subdiretórios
api/_z/ - Deve ser nomeado
[[path]].tscom colchetes duplos
- A pasta
- Certifique-se de que a pasta
functionsestá incluída na implantação - Verifique a aba Functions no painel Cloudflare
A função retorna 500
Causa: Há um erro de sintaxe ou erro em tempo de execução no código da função.
Solução:
- Verifique os logs de Functions no Cloudflare para detalhes do erro:
- Vá para seu projeto Pages → Functions → Logs
- Verifique se todo o código foi copiado corretamente
- Certifique-se de que você está exportando
onRequest(nãoexport default)
Erros de TypeScript durante a compilação
Causa: Definições de tipo ausentes.
Solução: Opção 1: Instale os tipos do Cloudflare Workers:
npm install --save-dev @cloudflare/workers-typesOpção 2: Use a versão JavaScript (renomeie para [[path]].js)
Erros de CORS no console
Causa: Headers de CORS não estão sendo adicionados corretamente.
Solução: Certifique-se de que sua função inclui ambos:
- O manipulador OPTIONS para solicitações de pré-voo
responseHeaders.set('Access-Control-Allow-Origin', '*')na resposta
Geolocalização incorreta
Causa: IP do cliente não está sendo encaminhado.
Solução: Verifique se sua função inclui:
const clientIP = request.headers.get('CF-Connecting-IP') || ''
proxyHeaders.set('X-Zenovay-Real-IP', clientIP)
O script carrega, mas sem dados no painel
Causa: Incompatibilidade de código de rastreamento.
Solução:
- Abra o Console do DevTools (F12 → aba Console) e procure por erros
- Verifique se seu
data-tracking-codecorresponde exatamente ao que está no seu painel Zenovay (case-sensitive!) - Certifique-se de que o domínio está registrado no Zenovay
Próximos passos
- Eventos personalizados - Acompanhar interações do usuário
- Identificação de visitante - Vincular análises aos usuários
- Solução de problemas - Mais ajuda com problemas