fix(analytics): declare the script build arg and send the Track API's real envelope
Two blockers found while wiring OpenPanel for real:
- frontend/Dockerfile declared ARG for VITE_OPENPANEL_URL/CLIENT_ID/SENTRY_DSN but not
VITE_OPENPANEL_SCRIPT_URL, so passing it as a build arg was silently ignored and the
loader compiled out (import.meta.env value undefined).
- backend/app/services/analytics.py posted a flat {type, event, properties} body; the
Track API expects {type, payload:{event, properties, profileId}} (verified against the
SDK source in packages/sdks/sdk). The API answered 400 and the module swallows every
error by design, so all server-side events were being dropped without a trace.
Verified after deploy: the bundle carries the client id + op1.js URL + the queueing shim,
op1.js serves 200, and a track event posted with the real envelope lands in OpenPanel.
This commit is contained in:
@@ -37,13 +37,12 @@ async def track(event: str, properties: dict[str, Any] | None = None, profile_id
|
|||||||
"""Record a named event; swallows every error."""
|
"""Record a named event; swallows every error."""
|
||||||
if not _configured():
|
if not _configured():
|
||||||
return
|
return
|
||||||
body = {
|
# OpenPanel's Track API takes {type, payload:{…}} (same envelope the browser SDK
|
||||||
"type": "track",
|
# sends) — a flat body is rejected with 400, which this module swallows by design.
|
||||||
"event": event,
|
inner: dict[str, Any] = {"event": event, "properties": properties or {}}
|
||||||
"properties": properties or {},
|
|
||||||
}
|
|
||||||
if profile_id:
|
if profile_id:
|
||||||
body["profileId"] = profile_id
|
inner["profileId"] = profile_id
|
||||||
|
body = {"type": "track", "payload": inner}
|
||||||
try:
|
try:
|
||||||
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
||||||
await client.post(
|
await client.post(
|
||||||
@@ -66,7 +65,7 @@ async def identify(profile_id: str, properties: dict[str, Any] | None = None) ->
|
|||||||
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
||||||
await client.post(
|
await client.post(
|
||||||
f"{settings.OPENPANEL_API_URL.rstrip('/')}/track",
|
f"{settings.OPENPANEL_API_URL.rstrip('/')}/track",
|
||||||
json={"type": "identify", "profileId": profile_id, "properties": properties or {}},
|
json={"type": "identify", "payload": {"profileId": profile_id, "properties": properties or {}}},
|
||||||
headers={
|
headers={
|
||||||
"openpanel-client-id": settings.OPENPANEL_CLIENT_ID,
|
"openpanel-client-id": settings.OPENPANEL_CLIENT_ID,
|
||||||
"openpanel-client-secret": settings.OPENPANEL_CLIENT_SECRET,
|
"openpanel-client-secret": settings.OPENPANEL_CLIENT_SECRET,
|
||||||
|
|||||||
@@ -23,9 +23,13 @@ ENV VITE_ENABLE_DEV_LOGIN=${DEV_LOGIN_ENABLED}
|
|||||||
# Empty values disable the feature (analytics.ts is a no-op then).
|
# Empty values disable the feature (analytics.ts is a no-op then).
|
||||||
ARG VITE_OPENPANEL_URL=""
|
ARG VITE_OPENPANEL_URL=""
|
||||||
ARG VITE_OPENPANEL_CLIENT_ID=""
|
ARG VITE_OPENPANEL_CLIENT_ID=""
|
||||||
|
# The browser script (op1.js) lives on the dashboard origin, not under the API path,
|
||||||
|
# so it needs its own arg — defined here or the value never reaches the bundle.
|
||||||
|
ARG VITE_OPENPANEL_SCRIPT_URL=""
|
||||||
ARG VITE_SENTRY_DSN=""
|
ARG VITE_SENTRY_DSN=""
|
||||||
ENV VITE_OPENPANEL_URL=${VITE_OPENPANEL_URL} \
|
ENV VITE_OPENPANEL_URL=${VITE_OPENPANEL_URL} \
|
||||||
VITE_OPENPANEL_CLIENT_ID=${VITE_OPENPANEL_CLIENT_ID} \
|
VITE_OPENPANEL_CLIENT_ID=${VITE_OPENPANEL_CLIENT_ID} \
|
||||||
|
VITE_OPENPANEL_SCRIPT_URL=${VITE_OPENPANEL_SCRIPT_URL} \
|
||||||
VITE_SENTRY_DSN=${VITE_SENTRY_DSN}
|
VITE_SENTRY_DSN=${VITE_SENTRY_DSN}
|
||||||
|
|
||||||
# Source code + build
|
# Source code + build
|
||||||
|
|||||||
Reference in New Issue
Block a user