Pular para o conteúdo principal
11 min de leitura

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

Cartão de script de rastreamento mostrando o snippet de script com abas HTML, React, Next.js e First-Party
O cartão de script de rastreamento nas configurações gerais do seu domínio — copie o código da aba First-Party.

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:

Terminal - Execute a partir da raiz do seu projetoBash
# 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: .ts ou .js

Isso cria uma rota "catch-all" que lida com qualquer caminho após /api/_z/.

TypeScript ou JavaScript?

  • Use .ts se seu projeto usa TypeScript
  • Use .js se 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:

functions/api/_z/[[path]].ts - Copie todo este arquivoTypeScript
/**
* 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:

functions/api/_z/[[path]].js - Versão JavaScriptJavaScript
/**
* 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:

Script de rastreamento - Adicione à seção <head> do seu HTMLHTML
<!-- 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

app/layout.tsx ou _app.tsxTSX
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

app.vue ou nuxt.config.tsVUE
<!-- In app.vue -->
<script setup>
useHead({
script: [
  {
    src: '/api/_z/script.js',
    defer: true,
    'data-tracking-code': 'YOUR_TRACKING_CODE'
  }
]
})
</script>

Astro

src/layouts/Layout.astroASTRO
---
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

index.htmlHTML
<!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:

TerminalBash
git add .
git commit -m "Add Zenovay first-party tracking"
git push

O Cloudflare Pages compilará e implantará automaticamente.

Opção B: Usando Wrangler CLI

TerminalBash
# Compile seu projeto primeiro
npm run build

# Faça deploy no Cloudflare Pages
npx wrangler pages deploy ./dist --project-name=your-project-name

Substitua ./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

  1. Vá para Cloudflare Dashboard → Pages
  2. Clique em seu projeto
  3. Clique na aba Functions
  4. 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 de src/)
  • Certifique-se de que o arquivo é nomeado [[path]].ts ou [[path]].js
  • Verifique se a implantação foi concluída com sucesso

Verificação 2: Aba de rede no navegador

  1. Abra seu site implantado
  2. Pressione F12 (ou Cmd+Option+I no Mac) para abrir DevTools
  3. Clique na aba Network
  4. Atualize a página (Cmd+R ou Ctrl+R)
  5. Na caixa de filtro, digite script.js
  6. 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.

  1. Abra o navegador Firefox
  2. Clique no menu (☰) → Settings
  3. Clique em Privacy & Security na barra lateral esquerda
  4. Em "Enhanced Tracking Protection", selecione Strict
  5. Visite seu site
  6. Abra DevTools (F12) → aba Network
  7. Atualize e verifique se /api/_z/script.js carrega com status 200

Verificação 4: Painel Zenovay

  1. Vá para app.zenovay.com e faça login
  2. Clique em seu site
  3. Visite seu site implantado em outra aba
  4. 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]].ts existe na raiz do projeto
  • A função aparece na aba Functions do Cloudflare Pages
  • O script carrega em /api/_z/script.js com status 200
  • O atributo data-tracking-code conté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:

  1. Verifique se o arquivo está exatamente em functions/api/_z/[[path]].ts
    • A pasta functions deve estar na raiz do projeto
    • Deve ter os subdiretórios api/_z/
    • Deve ser nomeado [[path]].ts com colchetes duplos
  2. Certifique-se de que a pasta functions está incluída na implantação
  3. 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:

  1. Verifique os logs de Functions no Cloudflare para detalhes do erro:
    • Vá para seu projeto Pages → Functions → Logs
  2. Verifique se todo o código foi copiado corretamente
  3. Certifique-se de que você está exportando onRequest (não export 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:

TerminalBash
npm install --save-dev @cloudflare/workers-types

Opçã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:

  1. O manipulador OPTIONS para solicitações de pré-voo
  2. 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:

  1. Abra o Console do DevTools (F12 → aba Console) e procure por erros
  2. Verifique se seu data-tracking-code corresponde exatamente ao que está no seu painel Zenovay (case-sensitive!)
  3. Certifique-se de que o domínio está registrado no Zenovay

Próximos passos

Esta página foi útil?