Session-grouped queries treat every sessionless event as one session (wrong results, ClickHouse OOM)
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 52/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- clickhouse, sql, typescript
Direzione di ricerca
Start with funnel.sql.ts, conversion.sql.ts, sankey.sql.ts, overview.sql.ts and pages.sql.ts, following the query names listed in the issue. Add the empty-session guard to per-session query paths and make sessionless view duration zero; leave profile grouping and the listed follow-ups out of scope. Done means sessionless events no longer join into shared paths or conversions, while profile-grouped results and view and visitor counts remain unaffected.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Problem
Events tracked from a backend are stored with session_id = '' by design. This covers secret-authenticated /track calls with a server user agent when the profile has no live browser session (incoming-event-handler.ts falls back to the '' that getDeviceId returns), and events whose timestamp is in the past.
The queries that group, partition or join by session_id don't exclude ''. Every sessionless event in the project and date range therefore lands in one group, which the query treats as a single session:
| Surface | Query | Effect |
|---|---|---|
| Funnel, grouped by session (the default) | funnel.sql.ts funnelBase (GROUP BY session_id + windowFunnel) |
Step 1 from user A and step 2 from user B count as one completed funnel |
| Conversion, grouped by session | conversion.sql.ts conversionQuery |
Same as the funnel: conversions that never happened |
| Flows (sankey) | sankey.sql.ts (GROUP BY session_id + groupArray) |
One path stitched together from every server-side user's events. The start_event_sessions / end_event_sessions anchors match '' too |
| Overview → User Journey | overview.sql.ts topEntriesQuery / transitionsQuery (GROUP BY session_id + groupArray(path)) |
Fake entry pages and transitions, plus one array holding every sessionless screen view in the range |
| Page-filtered overview metrics, Pages table | overview.sql.ts metricsWithPageFilterQuery, pages.sql.ts topPagesQuery (lead() OVER (PARTITION BY session_id …)) |
A sessionless view's "duration" is the gap to the next sessionless view by anyone |
Profile-grouped funnels and conversions are not affected, since they group by profile_id.
OpenPanel already treats '' as "no session" elsewhere. The import pipeline only builds sessions from session_id != '' (and never for device = 'server'), and code migration 4-add-sessions filters session_id != ''. The analytics queries just never got the same guard.
Reproduction
-
Track two server-side events for two different profiles with a client secret and a non-browser user agent. Neither profile has a browser session:
for p in user-a:screen_view user-b:sign_up; do curl -sS -X POST "$API_URL/track" -H 'content-type: application/json' \ -H "openpanel-client-id: $CLIENT_ID" -H "openpanel-client-secret: $CLIENT_SECRET" \ -H 'user-agent: my-backend/1.0' \ -d "{\"type\":\"track\",\"payload\":{\"name\":\"${p#*:}\",\"profileId\":\"${p%%:*}\",\"properties\":{\"__path\":\"/x\"}}}" done -
SELECT profile_id, session_id, name FROM events WHERE project_id = '<project>' ORDER BY created_atshows both rows withsession_id = ''. -
Create a funnel
screen_view → sign_upgrouped by session. It shows 1 conversion, although no user did both steps. Grouped by profile it correctly shows 0. -
Open Flows starting at
screen_view. It drawsscreen_view → sign_up, a path nobody took. -
Send more sessionless
screen_views with different paths, then open Overview → User Journey. The paths are stitched together across users.
On a project that sends a lot of server-side screen_views, step 5 also shows the memory problem. All of those rows go into a single groupArray, which can't be split across threads or shards.
Impact
- Wrong numbers. Per-session funnels and conversions are inflated, and flows and user journeys show paths that don't exist. Nothing in the UI shows it, so the numbers look fine.
- Memory blow-up. The combined "session" grows with all sessionless traffic in the range. On 2026-10-20 a self-hosted ClickHouse was OOM-killed by the Overview User Journey query grouping about 97k sessionless
screen_viewrows into one session. A local reproduction with 1M sessionless rows: the user-journey grouping peaked at about 92 MB for one 1,000,000-element path. With the guard it peaked at about 9 MB, and the longest path was 5.
Proposed fix
Add session_id != '' wherever a query builds per-session state, and leave profile grouping alone:
- Funnel and conversion: add the filter to the scan only when the group is
session_id. - Sankey: add it to the path scan and to the start/end anchor CTEs.
- Overview user journey: add it to
ordered_events. - The
lead() OVER (PARTITION BY session_id)screen-view duration: give a sessionless view 0, the same as a session's last view, rather than the gap to someone else's event. View and visitor counts stay as they are.
Out of scope for this issue, possible follow-ups:
uniq(session_id)/countDistinct(session_id)session counts (the overview, realtime, widgets, the chart "sessions" segment) count''as one extra session. That's off by at most one and doesn't blow up memory.- The realtime map's "latest event per session" list can show one
''row. - The
session.performed_eventfilter'ssession_id IN (SELECT DISTINCT session_id …)matches every sessionless event once any sessionless event performed the step.
- Lingua principale
- TypeScript
- Stelle
- 7.1k
- Fork
- 516
- Merge medio
- 21h 36m
- PR unite (30g)
- 22
Preparare l'ambiente
- Include un Dockerfile o un file Docker Compose
- Nessun modello di pull request
- Nessuna guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di Openpanel-dev/openpanel
-
ClickHouse retry logs print CLICKHOUSE_URL with its passwordForse già presa @ppjsw l’ha presa 1 giorno fa. Aperta
Difficoltà 1/5 1-3 ore Idoneità per principianti 92/100
Openpanel-dev/openpanel#551 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Self-hosted missing op1-replay.jsForse di nuovo libera Una pull request per questa issue è stata chiusa senza essere unita. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
Openpanel-dev/openpanel#512 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
login page needs refinementForse di nuovo libera Una pull request per questa issue è stata chiusa senza essere unita. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
Openpanel-dev/openpanel#495 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 35/100
Openpanel-dev/openpanel#563 ·
I maintainer di solito rispondono entro 1 giorno
-
Session replay: early chunks saved under the wrong sessionForse di nuovo libera Una pull request per questa issue è stata chiusa senza essere unita. Aperta
Difficoltà 4/5 3-5 giorni Idoneità per principianti 35/100
Openpanel-dev/openpanel#537 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di Openpanel-dev/openpanel
Issue simili
-
frontend
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 86/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
ranxianglei/billion-context#4172 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
awslabs/threat-composer#362 ·
I maintainer di solito rispondono entro 1 giorno
-
Area/Cloud Needs Triage Type/Bug
Difficoltà 1/5 1-3 ore Idoneità per principianti 86/100
wso2/product-integrator#2847 ·
I maintainer di solito rispondono entro 1 giorno