Proxy guides
Cloudflare Worker
One Cloudflare Worker serves the ProductLense script from your domain and, on the Scale plan, forwards events with the visitor's real IP address.
If your domain is on Cloudflare, one Worker handles both requests. It caches the script at the edge and reads the visitor's address from CF-Connecting-IP, which Cloudflare sets and visitors cannot forge.
The Worker
interface Env {
PL_API_KEY?: string;
}
type Event = Record<string, unknown>;
export default {
async fetch(req: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const url = new URL(req.url);
if (url.pathname === '/js/a.js') {
const cache = caches.default;
const hit = await cache.match(req);
if (hit) return hit;
const res = await fetch('https://api.productlense.app/a.js');
if (res.ok) ctx.waitUntil(cache.put(req, res.clone()));
return res;
}
if (url.pathname === '/m/api/e' && req.method === 'POST' && env.PL_API_KEY) {
const text = await req.text();
if (text.length > 8192) return new Response(null, { status: 413 });
let body: { b?: Event[] } & Event;
try {
body = JSON.parse(text);
} catch {
return new Response(null, { status: 400 });
}
const extra = { ip: req.headers.get('CF-Connecting-IP') ?? '', ua: req.headers.get('User-Agent') ?? '' };
const out = body.b ? { ...body, b: body.b.map((e) => ({ ...e, ...extra })) } : { ...body, ...extra };
const r = await fetch('https://api.productlense.app/api/v1/events', {
method: 'POST',
headers: { Authorization: `Bearer ${env.PL_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify(out),
});
return new Response(null, { status: r.status });
}
return new Response('Not found', { status: 404 });
},
};name = "productlense-proxy"
main = "src/index.ts"
compatibility_date = "2026-10-01"
routes = [
{ pattern = "example.com/js/a.js", zone_name = "example.com" },
{ pattern = "example.com/m/api/e", zone_name = "example.com" },
]The script response keeps ProductLense's Cache-Control: public, max-age=86400, so the edge cache refreshes at least once a day.
Use only the script part (any plan)
Without PL_API_KEY the Worker serves only the script. Point the tag at it and send events straight to ProductLense:
<script defer data-site="SITE_ID" data-api="https://api.productlense.app" src="/js/a.js"></script>Forward events too (Scale plan)
- Create an API key with the
eventsscope (see Authentication and API keys). - Store it as a secret:
npx wrangler secret put PL_API_KEY, thennpx wrangler deploy. - Change the tag to
data-api="https://example.com/m".
Check it works
- Open
https://example.com/js/a.js: it returns JavaScript, and a second load showscf-cache-status: HIT. - Load a page with the developer tools open. The Network tab shows a
POSTtoapi/ewith status204. - Open the Live page in the ProductLense dashboard. Your visit appears within a few seconds, with your real country.