Skip to main content

Cloudflare Workers Proxy

Use Cloudflare Workers to proxy Ovyxa requests through your own domain, bypassing adblockers while maintaining privacy standards.

Why Use a Proxy?

Adblockers may block requests to api.ovyxa.com. Proxying through your domain:

  • Improves coverage: More visitors counted (adblockers allow first-party requests)
  • Maintains privacy: Still cookie-less, still GDPR-compliant
  • Respects choice: Visitors using strict blockers still blocked (as intended)

Prerequisites

  • Cloudflare account (free tier works)
  • Your domain managed by Cloudflare
  • Ovyxa account

Setup Steps

1. Create Cloudflare Worker

Go to Workers & Pages in your Cloudflare dashboard and create a new Worker:

// ovyxa-proxy worker
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
const url = new URL(request.url)

// Only proxy /stats/* paths
if (!url.pathname.startsWith('/stats')) {
return new Response('Not Found', { status: 404 })
}

// Remove /stats prefix and forward to Ovyxa
const targetPath = url.pathname.replace(/^\/stats/, '')
const targetUrl = `https://api.ovyxa.com${targetPath}${url.search}`

// Create new request with original method and headers
const modifiedRequest = new Request(targetUrl, {
method: request.method,
headers: request.headers,
body: request.body,
redirect: 'follow'
})

// Forward request to Ovyxa
const response = await fetch(modifiedRequest)

// Return response with CORS headers
const modifiedResponse = new Response(response.body, response)
modifiedResponse.headers.set('Access-Control-Allow-Origin', '*')
modifiedResponse.headers.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
modifiedResponse.headers.set('Access-Control-Allow-Headers', 'Content-Type')

return modifiedResponse
}

Save and Deploy the worker.

2. Configure Worker Route

Add a route to trigger the worker:

  1. Go to Workers Routes in your domain settings
  2. Click Add Route
  3. Route: yourdomain.com/stats/*
  4. Worker: Select your ovyxa-proxy worker
  5. Save

3. Update Your Tracking Script

Update your Ovyxa script tag to use the proxy:

<!-- Before (direct) -->
<script async
src="https://ingest.ovyxa.com/js/script.js"
data-domain="YOUR_DOMAIN">
</script>

<!-- After (proxied) -->
<script async
src="https://ingest.ovyxa.com/js/script.js"
data-domain="YOUR_DOMAIN"
data-api="https://yourdomain.com/stats">
</script>

The data-api attribute tells the script to send events to your proxy instead of directly to Ovyxa.

4. Test the Setup

  1. Visit your website with the updated script
  2. Open browser DevTools → Network tab
  3. Filter for requests to /stats
  4. You should see POST requests to yourdomain.com/stats/e (instead of api.ovyxa.com/e)
  5. Check your Ovyxa dashboard—events should appear within 5 minutes

Advanced Configuration

Custom Subdomain

For cleaner URLs, use a subdomain:

// Worker stays the same, but route becomes:
// stats.yourdomain.com/*

// Script tag:
<script async
src="https://ingest.ovyxa.com/js/script.js"
data-domain="YOUR_DOMAIN"
data-api="https://stats.yourdomain.com">
</script>

Rate Limiting (Abuse Protection)

Add simple rate limiting to prevent abuse:

const RATE_LIMIT = 100 // requests per minute per IP
const rateLimitMap = new Map()

async function handleRequest(request) {
const clientIP = request.headers.get('CF-Connecting-IP')

// Check rate limit
const now = Date.now()
const minute = Math.floor(now / 60000)
const key = `${clientIP}:${minute}`

const count = rateLimitMap.get(key) || 0
if (count >= RATE_LIMIT) {
return new Response('Rate limit exceeded', { status: 429 })
}

rateLimitMap.set(key, count + 1)

// Continue with proxy logic...
const url = new URL(request.url)
// ... rest of original code
}

Logging (for debugging)

Enable logging to debug issues:

async function handleRequest(request) {
try {
// ... proxy logic
const response = await fetch(modifiedRequest)

console.log(`Proxied: ${request.method} ${url.pathname}${response.status}`)

return modifiedResponse
} catch (error) {
console.error('Proxy error:', error)
return new Response('Proxy Error', { status: 500 })
}
}

View logs in Workers → Logs in Cloudflare dashboard.

Troubleshooting

Events Not Appearing in Dashboard

  1. Check worker logs for errors
  2. Verify route is configured correctly (yourdomain.com/stats/*)
  3. Test endpoint directly: curl -X POST https://yourdomain.com/stats/e -d '{"site":"test"}'
  4. Check CORS headers in browser DevTools

404 Errors

  • Ensure route pattern includes wildcard: /stats/* (not /stats)
  • Verify worker is deployed and active

CORS Errors

Add OPTIONS handling for preflight requests:

async function handleRequest(request) {
// Handle preflight
if (request.method === 'OPTIONS') {
return new Response(null, {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
}
})
}

// ... rest of proxy logic
}

Cost

  • Free tier: 100,000 requests/day (sufficient for most sites)
  • Paid: $0.50 per million requests beyond free tier

Average analytics events:

  • 1,000 pageviews/day = ~1,000 requests/day
  • 10,000 pageviews/day = ~10,000 requests/day

Free tier covers 100k+ daily pageviews easily.

Security Considerations

What This Proxy Does

  • Forwards analytics events to Ovyxa
  • Uses your domain (bypasses some adblockers)
  • Maintains same privacy standards

What This Proxy Doesn't Do

  • Doesn't store cookies (still cookie-less)
  • Doesn't track users (still privacy-first)
  • Doesn't circumvent strict blockers (respects visitor choice)
  • Doesn't log personal data (GDPR-compliant)

This is a transparent proxy, not a workaround to surveillance blockers.

Alternatives

Need Help?

Proxying is optional but can improve coverage by 10-30% depending on your audience.