MenuFlask

Proxy guides

Flask

Serve the ProductLense script from your Flask app and forward events with the visitor's real IP address on the Scale plan.

Two routes in your Flask app 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

pl_proxy.py
import os
import time

import requests
from flask import Blueprint, Response, request

productlense = Blueprint("productlense", __name__)
_script = {"body": b"", "at": 0.0}


@productlense.get("/js/a.js")
def script():
    if time.time() - _script["at"] > 3600:
        r = requests.get("https://api.productlense.app/a.js", timeout=5)
        if r.ok:
            _script.update(body=r.content, at=time.time())
    if not _script["body"]:
        return Response(status=502)
    return Response(_script["body"], mimetype="application/javascript",
                    headers={"Cache-Control": "public, max-age=86400"})


@productlense.post("/m/api/e")
def events():
    if request.content_length and request.content_length > 8192:
        return Response(status=413)
    body = request.get_json(force=True, silent=True)
    if not isinstance(body, dict):
        return Response(status=400)
    extra = {"ip": request.remote_addr or "", "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 = requests.post("https://api.productlense.app/api/v1/events", json=body, timeout=5,
                      headers={"Authorization": f"Bearer {os.environ['PL_API_KEY']}"})
    return Response(status=r.status_code)
app.py
from flask import Flask
from werkzeug.middleware.proxy_fix import ProxyFix

from pl_proxy import productlense

app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1)  # behind one proxy: Nginx, a load balancer
app.register_blueprint(productlense)

get_json(force=True) reads the body even though the browser sends it as text/plain. ProxyFix makes request.remote_addr the visitor's address when the app runs behind a reverse proxy; without a proxy, leave it out.

Use it

Serve only the script on any plan:

HTML
<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

  1. Open https://example.com/js/a.js: it returns JavaScript.
  2. Load a page with the developer tools open. The Network tab shows a POST to api/e with status 204.
  3. Open the Live page in the ProductLense dashboard. Your visit appears within a few seconds.

    ↑ ↓ to move, Enter to open