Skip to main content
7 min read

First-Party Tracking with Netlify

Set up a first-party proxy on Netlify using simple redirect rules. Works with any static site or framework.

Difficulty: Easy - Just add a few lines to a 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 ✅
  • Netlify redirects 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 project deployed on Netlify
  • Your Zenovay tracking code (found in Dashboard → Your Site → Settings)
  • Access to your project's build configuration

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


Option 1: Using _redirects File (Simplest)

The easiest way to set up the proxy is using Netlify's _redirects file.

Step 1: Create the Redirects File

Create a _redirects file in your public/ folder (or wherever your static assets go):

public/_redirectsTEXT
# Zenovay first-party tracking proxy
/api/_z/*  https://api.zenovay.com/fp/:splat  200

How it works: The 200 status code makes this a rewrite (proxy) instead of a redirect. The browser sees your domain, but Netlify fetches from Zenovay's API behind the scenes.

Step 2: Add the Tracking Script

Your HTMLHTML
<script defer
data-tracking-code="YOUR_TRACKING_CODE"
src="/api/_z/script.js">
</script>

Step 3: Deploy

TerminalBash
netlify deploy --prod

Or push to your Git repository if you have continuous deployment configured.


Option 2: Using netlify.toml (More Explicit)

For more complex configurations, use netlify.toml:

Step 1: Create or Update netlify.toml

Add the redirect rule to your netlify.toml in your project root:

netlify.tomlTOML
# Zenovay first-party tracking proxy
[[redirects]]
from = "/api/_z/*"
to = "https://api.zenovay.com/fp/:splat"
status = 200
force = true

If you already have a netlify.toml, add the redirect to your existing file:

netlify.toml (with existing config)TOML
[build]
command = "npm run build"
publish = "dist"

# Zenovay first-party tracking proxy
[[redirects]]
from = "/api/_z/*"
to = "https://api.zenovay.com/fp/:splat"
status = 200
force = true

# Your other redirects...
[[redirects]]
from = "/*"
to = "/index.html"
status = 200

Order matters! Put the Zenovay redirect BEFORE any catch-all redirects (like SPA fallbacks). Netlify processes redirects in order.

Step 2: Add the Tracking Script

Your HTMLHTML
<script defer
data-tracking-code="YOUR_TRACKING_CODE"
src="/api/_z/script.js">
</script>

Step 3: Deploy

TerminalBash
netlify deploy --prod

Framework-Specific Examples

React (Create React App)

public/_redirectsTEXT
/api/_z/*  https://api.zenovay.com/fp/:splat  200
public/index.htmlHTML
<!DOCTYPE html>
<html lang="en">
<head>
  <script defer data-tracking-code="YOUR_TRACKING_CODE" src="/api/_z/script.js"></script>
  <!-- other head elements -->
</head>
<body>
  <div id="root"></div>
</body>
</html>

Vue.js (Vite)

public/_redirectsTEXT
/api/_z/*  https://api.zenovay.com/fp/:splat  200
index.htmlHTML
<!DOCTYPE html>
<html lang="en">
<head>
  <script defer data-tracking-code="YOUR_TRACKING_CODE" src="/api/_z/script.js"></script>
</head>
<body>
  <div id="app"></div>
  <script type="module" src="/src/main.js"></script>
</body>
</html>

Gatsby

netlify.tomlTOML
[build]
command = "gatsby build"
publish = "public"

[[redirects]]
from = "/api/_z/*"
to = "https://api.zenovay.com/fp/:splat"
status = 200
force = true
gatsby-ssr.jsJSX
import React from 'react'

export const onRenderBody = ({ setHeadComponents }) => {
setHeadComponents([
  <script
    key="zenovay"
    defer
    data-tracking-code="YOUR_TRACKING_CODE"
    src="/api/_z/script.js"
  />
])
}

Hugo

static/_redirectsTEXT
/api/_z/*  https://api.zenovay.com/fp/:splat  200
layouts/partials/head.htmlHTML
<script defer data-tracking-code="YOUR_TRACKING_CODE" src="/api/_z/script.js"></script>

11ty (Eleventy)

src/_redirectsTEXT
/api/_z/*  https://api.zenovay.com/fp/:splat  200

Make sure _redirects is copied to output by adding to your .eleventy.js:

.eleventy.jsJavaScript
module.exports = function(eleventyConfig) {
eleventyConfig.addPassthroughCopy("src/_redirects");
// ... rest of config
}

Verify It's Working

Check in Netlify Dashboard

  1. Go to your site in Netlify Dashboard
  2. Click Site configurationRedirects
  3. You should see your /api/_z/* redirect listed

Check the Network Tab

  1. Visit your deployed site
  2. Open DevTools (F12)
  3. Go to the Network tab
  4. Reload the page
  5. Look for /api/_z/script.js

You should see:

  • Status: 200
  • Domain: Your Netlify domain
  • Response: JavaScript code

Test in Firefox Strict Mode

  1. Open Firefox
  2. Settings → Privacy & Security → Enhanced Tracking Protection: Strict
  3. Visit your site
  4. Verify the script loads successfully

Troubleshooting

Redirect Returns 404

Cause: The _redirects file isn't being published or is in the wrong location.

Solution:

  1. Make sure _redirects is in your publish directory (usually public/ or dist/)
  2. For build tools, ensure the file is copied during build
  3. Check Netlify Dashboard → Redirects to see if it's recognized

Redirect Causes a Loop

Cause: Another redirect is interfering.

Solution:

  1. Use force = true in netlify.toml to override other rules
  2. Make sure the Zenovay redirect comes BEFORE catch-all rules
  3. Check for conflicting _redirects and netlify.toml rules

Script Loads But Returns HTML

Cause: A catch-all SPA redirect is intercepting the request.

Solution: Put the Zenovay redirect BEFORE your SPA fallback:

netlify.tomlTOML
# This MUST come first
[[redirects]]
from = "/api/_z/*"
to = "https://api.zenovay.com/fp/:splat"
status = 200
force = true

# SPA fallback comes after
[[redirects]]
from = "/*"
to = "/index.html"
status = 200

Geolocation Shows Wrong Location

Cause: Netlify's proxy doesn't automatically forward client IP.

Solution: Unfortunately, Netlify's simple redirects don't support custom headers. The geolocation will be based on Netlify's edge server location. For accurate geolocation, consider:

  1. Using Netlify Functions (Edge Functions) - more complex setup
  2. Using Cloudflare Workers in front of Netlify

Advanced: Using Netlify Edge Functions

For more control (including IP forwarding), you can use Netlify Edge Functions:

netlify/edge-functions/zenovay-proxy.tsTypeScript
import type { Context } from '@netlify/edge-functions'

export default async (request: Request, context: Context) => {
const url = new URL(request.url)
const path = url.pathname.replace('/api/_z/', '')
const targetUrl = `https://api.zenovay.com/fp/${path}${url.search}`

// Get client IP
const clientIP = context.ip || ''

const headers = new Headers(request.headers)
headers.set('X-Zenovay-Real-IP', clientIP)
headers.delete('Host')

const response = await fetch(targetUrl, {
  method: request.method,
  headers: headers,
  body: request.body,
})

const responseHeaders = new Headers(response.headers)
responseHeaders.set('Access-Control-Allow-Origin', '*')

return new Response(response.body, {
  status: response.status,
  headers: responseHeaders,
})
}

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

Complete Example

Project StructureTEXT
my-netlify-site/
├── netlify.toml
├── public/
│   ├── _redirects
│   └── index.html
├── src/
│   └── ...
└── package.json
netlify.tomlTOML
[build]
command = "npm run build"
publish = "dist"

[[redirects]]
from = "/api/_z/*"
to = "https://api.zenovay.com/fp/:splat"
status = 200
force = true
public/index.htmlHTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>My Site</title>
  <script defer data-tracking-code="YOUR_TRACKING_CODE" src="/api/_z/script.js"></script>
</head>
<body>
  <div id="app"></div>
</body>
</html>

Final Checklist

Before you're done, verify ALL of these:

  • _redirects or netlify.toml has the Zenovay redirect rule
  • Redirect rule comes BEFORE any SPA catch-all rules
  • Script tag uses /api/_z/script.js (not the direct Zenovay URL)
  • data-tracking-code attribute contains your correct tracking code
  • Project is deployed (not just running locally)
  • Tested in Firefox with Enhanced Tracking Protection set to Strict
  • Visits appearing in Zenovay dashboard

Next Steps

Was this page helpful?