Saltar al contenido principal
7 min de lectura

First-Party Tracking with Next.js

Set up a first-party proxy in your Next.js application to bypass ad blockers and browser tracking protection.

Difficulty: Easy - This is the simplest option for Next.js projects. Just add a few lines to your config file.

Why This Works (Same-Origin)

This approach uses /api/_z/script.js which is on the same origin as your website. Firefox ETP and other tracking protections only block cross-origin requests.

  • Browser sees: yourdomain.com/api/_z/script.js → Same origin ✅
  • Next.js rewrites the request to Zenovay server-side (browser never sees this)
  • All tracking protection is bypassed because the request is first-party

Before You Start

Make sure you have:

  • A Next.js 12+ project (App Router or Pages Router)
  • Your Zenovay tracking code (found in Dashboard → Your Site → Settings)
  • Access to your next.config.js or next.config.ts file

Your Tracking Code Format

Your tracking code looks like: ZV_XXXXXXXXXX

  • Starts with ZV_
  • Followed by 10 characters (letters and numbers)
  • CASE-SENSITIVE - copy it exactly

Example: ZV_Q8U0GYD70WR


How It Works

Next.js rewrites act as a server-side proxy. When a browser requests /api/_z/script.js, Next.js fetches it from api.zenovay.com/fp/script.js and returns it. The browser only sees your domain.

Browser → yourdomain.com/api/_z/script.js ✅ (First-party)
               ↓
         Next.js Rewrite
               ↓
         api.zenovay.com/fp/script.js (Server-to-server)

Step 1: Configure Rewrites

Add the rewrite configuration to your Next.js config file.

Which config file?

  • next.config.js - If your project uses JavaScript
  • next.config.mjs - If your project uses ES modules
  • next.config.ts - If your project uses TypeScript (Next.js 15+)

For next.config.js (JavaScript)

next.config.jsJavaScript
/** @type {import('next').NextConfig} */
const nextConfig = {
// Add this rewrites configuration
async rewrites() {
  return [
    {
      // Proxy all requests to /api/_z/* to Zenovay's first-party endpoint
      source: '/api/_z/:path*',
      destination: 'https://api.zenovay.com/fp/:path*',
    },
  ]
},
}

module.exports = nextConfig

For next.config.mjs (ES Modules)

next.config.mjsJavaScript
/** @type {import('next').NextConfig} */
const nextConfig = {
async rewrites() {
  return [
    {
      source: '/api/_z/:path*',
      destination: 'https://api.zenovay.com/fp/:path*',
    },
  ]
},
}

export default nextConfig

For next.config.ts (TypeScript - Next.js 15+)

next.config.tsTypeScript
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
async rewrites() {
  return [
    {
      source: '/api/_z/:path*',
      destination: 'https://api.zenovay.com/fp/:path*',
    },
  ]
},
}

export default nextConfig

If You Already Have Rewrites

If your config already has a rewrites() function, add the Zenovay rewrite to the existing array:

next.config.js (with existing rewrites)JavaScript
const nextConfig = {
async rewrites() {
  return [
    // Your existing rewrites...
    {
      source: '/old-page',
      destination: '/new-page',
    },
    // Add Zenovay rewrite
    {
      source: '/api/_z/:path*',
      destination: 'https://api.zenovay.com/fp/:path*',
    },
  ]
},
}

module.exports = nextConfig

Step 2: Add the Tracking Script

Now add the tracking script to your application.

App Router (Next.js 13+)

Add the script to your root layout:

app/layout.tsxTSX
import Script from 'next/script'

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
  <html lang="en">
    <head>
      <Script
        src="/api/_z/script.js"
        data-tracking-code="YOUR_TRACKING_CODE"
        strategy="afterInteractive"
      />
    </head>
    <body>{children}</body>
  </html>
)
}

Pages Router

Add the script to your custom _app.tsx:

pages/_app.tsxTSX
import Script from 'next/script'
import type { AppProps } from 'next/app'

export default function App({ Component, pageProps }: AppProps) {
return (
  <>
    <Script
      src="/api/_z/script.js"
      data-tracking-code="YOUR_TRACKING_CODE"
      strategy="afterInteractive"
    />
    <Component {...pageProps} />
  </>
)
}

Replace YOUR_TRACKING_CODE with your actual tracking code from the Zenovay dashboard (e.g., ZV_Q8U0GYD70WR).


Step 3: Restart Your Development Server

Important! Next.js caches the config file. You MUST restart your dev server after editing next.config.js.

TerminalBash
# Stop your current dev server (Ctrl+C)
# Then restart it
npm run dev

Step 4: Deploy Your Changes

TerminalBash
# For Vercel (automatic deployment)
git add .
git commit -m "Add Zenovay first-party tracking"
git push

# Or manual Vercel deployment
vercel deploy

# For other platforms
npm run build && npm run start

Step 5: Verify It's Working

Check 1: Local Development

  1. Open your site at http://localhost:3000
  2. Press F12 to open DevTools
  3. Click the Network tab
  4. Refresh the page
  5. Filter by script.js
  6. You should see a request to /api/_z/script.js with status 200

Check 2: Firefox Strict Mode (Most Important!)

Firefox has the strictest tracking protection. If it works in Firefox, it works everywhere.

  1. Open Firefox browser
  2. Click the menu (☰) → Settings
  3. Click Privacy & Security in the left sidebar
  4. Under "Enhanced Tracking Protection", select Strict
  5. Visit your website
  6. Open DevTools (F12) → Network tab
  7. Refresh and verify /api/_z/script.js loads with status 200

Check 3: Zenovay Dashboard

  1. Go to app.zenovay.com and log in
  2. Click on your website
  3. Visit your site in another tab
  4. Within 1-2 minutes, you should see the visit appear in your dashboard

Final Checklist

Before you're done, verify ALL of these:

  • next.config.js has the rewrite rule for /api/_z/:path*
  • Development server was restarted after config change
  • Script tag uses /api/_z/script.js (not the direct Zenovay URL)
  • data-tracking-code attribute contains your correct tracking code
  • Tested in Firefox with Enhanced Tracking Protection set to Strict
  • Visits appearing in Zenovay dashboard

Troubleshooting

Script Returns 404

Cause: The rewrite is not configured correctly or server wasn't restarted.

Solution:

  1. Restart your dev server - This is the most common fix
  2. Verify the next.config.js file is saved
  3. Check the path matches exactly: /api/_z/:path*
  4. Make sure you're using source and destination (not from and to)

Script Loads But No Data Appears

Cause: The tracking code might be incorrect.

Solution:

  1. Check your tracking code in the Zenovay dashboard
  2. Ensure data-tracking-code matches exactly (case-sensitive)
  3. Check the browser console (F12 → Console tab) for errors

Rewrites Work Locally But Not in Production

Cause: Some hosting platforms handle rewrites differently.

Solution:

  • Vercel: Rewrites work automatically
  • Netlify: Add the rewrite to netlify.toml as well
  • Self-hosted: Make sure your server supports Next.js rewrites

Geolocation is Wrong

Cause: The visitor's real IP isn't being forwarded.

Solution: For Vercel, this works automatically. For other platforms, you may need middleware:

middleware.tsTypeScript
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
if (request.nextUrl.pathname.startsWith('/api/_z/')) {
  const response = NextResponse.rewrite(
    new URL(`https://api.zenovay.com/fp/${request.nextUrl.pathname.replace('/api/_z/', '')}${request.nextUrl.search}`)
  )

  // Forward the real client IP
  const clientIP = request.headers.get('x-forwarded-for')?.split(',')[0]
                || request.headers.get('x-real-ip')
                || ''

  response.headers.set('X-Zenovay-Real-IP', clientIP)

  return response
}
}

export const config = {
matcher: '/api/_z/:path*',
}

Complete Example

Here's a complete next.config.js example:

next.config.jsJavaScript
/** @type {import('next').NextConfig} */
const nextConfig = {
// Your existing config options...
reactStrictMode: true,

// Zenovay first-party proxy rewrite
async rewrites() {
  return [
    {
      source: '/api/_z/:path*',
      destination: 'https://api.zenovay.com/fp/:path*',
    },
  ]
},
}

module.exports = nextConfig

And a complete app/layout.tsx:

app/layout.tsxTSX
import Script from 'next/script'
import './globals.css'

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
  <html lang="en">
    <head>
      {/* Zenovay Analytics - First-Party Tracking */}
      <Script
        src="/api/_z/script.js"
        data-tracking-code="ZV_Q8U0GYD70WR"  // Replace with your tracking code
        strategy="afterInteractive"
      />
    </head>
    <body>{children}</body>
  </html>
)
}

Next Steps

¿Fue útil esta página?