Proxy guides
FastAPI
Serve the ProductLense script from a FastAPI app and forward events asynchronously with httpx, keeping visitor counts and countries correct.
Two async routes serve the script from your domain and, on the Scale plan, forward events. Read the proxy overview first for what each one fixes.
The routes
import json
import os
import time
import httpx
from fastapi import APIRouter, Request, Response
router = APIRouter()
client = httpx.AsyncClient(timeout=5)
_script = {"body": b"", "at": 0.0}
@router.get("/js/a.js")
async def script() -> Response:
if time.time() - _script["at"] > 3600:
r = await client.get("https://api.productlense.app/a.js")
if r.is_success:
_script.update(body=r.content, at=time.time())
if not _script["body"]:
return Response(status_code=502)
return Response(_script["body"], media_type="application/javascript",
headers={"Cache-Control": "public, max-age=86400"})
@router.post("/m/api/e")
async def events(request: Request) -> Response:
raw = await request.body()
if len(raw) > 8192:
return Response(status_code=413)
try:
body = json.loads(raw)
except ValueError:
return Response(status_code=400)
if not isinstance(body, dict):
return Response(status_code=400)
extra = {"ip": request.client.host if request.client else "", "ua": request.headers.get("user-agent", "")}
if isinstance(body.get("b"), list):
body["b"] = [{**e, **extra} for e in body["b"] if isinstance(e, dict)]
else:
body.update(extra)
r = await client.post("https://api.productlense.app/api/v1/events", json=body,
headers={"Authorization": f"Bearer {os.environ['PL_API_KEY']}"})
return Response(status_code=r.status_code)from fastapi import FastAPI
from pl_proxy import router as productlense
app = FastAPI()
app.include_router(productlense)The route reads the raw body because the browser sends it as text/plain. Behind a reverse proxy, run Uvicorn with --proxy-headers --forwarded-allow-ips=<proxy ip> so request.client.host is the visitor's address and not the proxy's.
Use it
Serve only the script on any plan:
<script defer data-site="SITE_ID" data-api="https://api.productlense.app" src="/js/a.js"></script>On the Scale plan, set PL_API_KEY to a key with the events scope and change the tag to data-api="https://example.com/m".
Check it works
- Open
https://example.com/js/a.js: it returns JavaScript. - 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.