Skip to content

fix: bugs in example apps#101

Open
sarahxsanders wants to merge 2 commits intomainfrom
v2-eval-bugs
Open

fix: bugs in example apps#101
sarahxsanders wants to merge 2 commits intomainfrom
v2-eval-bugs

Conversation

@sarahxsanders
Copy link
Copy Markdown
Collaborator

fixes for some 🐛 found with v2 evaluator testing over the past few days

PII leaking as distinct_id in Laravel, FastAPI, Flask

  • Email was used as distinct_id in capture(), identify(), identify_context(),
    and feature_enabled() calls. Changed to str(user.id) everywhere.
  • PII like email is now only in $set person properties or tag() calls where it belongs.
  • this was somehow overriding security scans too, so need to dig there

Docs: https://posthog.com/docs/libraries/python

Removed calls to identify() that don't exist in FastAPI, Next.js

  • Python SDK v6 removed posthog.identify(). Replaced with $set/$set_once
    inside capture() properties.
  • Node SDK never had identify(). Same fix.

Docs:

Undocumented module-level Python config in FastAPI, Flask

  • Both apps used posthog.api_key = ... / posthog.host = ....
  • Docs say to use the Posthog() constructor.
  • Refactored to a shared posthog_client.py with posthog = Posthog(token, host=...).
  • Shutdown changed to posthog.shutdown().

Docs: https://posthog.com/docs/libraries/python

PHP operator precedence bug in captureException in Laravel

  • $distinctId ?? (string) Auth::user()?->id ?? 'anonymous': (string) has higher
    precedence than ??, so (string) null evaluates to "", and "" ?? 'anonymous'
    returns "" since empty string isn't null.
  • Fixed with explicit null check.

Next.js server routes used hardcoded distinct_id

  • Server-side login routes passed username as distinctId instead of extracting
    the actual distinct_id from the PostHog cookie.
  • Added cookie parsing so server events link to the same person as client-side events.

Docs: https://posthog.com/docs/libraries/next-js

Missing error tracking in Flask, React Router 7

  • Flask: added @app.errorhandler(Exception) with posthog.capture_exception(e).
  • React Router 7: added capture_exceptions: true to posthog.init() and
    wrapped app in PostHogErrorBoundary.

Docs:

Rails error tracking missing Current.user support

  • Added detection for Rails' CurrentAttributes pattern.
  • Falls back safely to :current_user if Current isn't defined.

Docs: https://posthog.com/docs/libraries/ruby-on-rails

Python SDK version constraint too loose in FastAPI, Flask, Python

  • Bumped posthog>=3.0.0 to posthog>=3.7.0. capture_exception was added in
    v3.6.4, enable_exception_autocapture in v3.6.0.

React Native identify() signature confirmed correct

  • Formatting-only change.
  • Confirmed the existing $set/$set_once nesting pattern is correct per docs.

Docs: https://posthog.com/docs/libraries/react-native

@sarahxsanders sarahxsanders requested a review from a team March 17, 2026 18:50
@github-actions
Copy link
Copy Markdown

🧙 Wizard CI

Run the Wizard CI and test your changes against wizard-workbench example apps by replying with a GitHub comment using one of the following commands:

Test all apps:

  • /wizard-ci all

Test all apps in a directory:

  • /wizard-ci android
  • /wizard-ci angular
  • /wizard-ci astro
  • /wizard-ci django
  • /wizard-ci fastapi
  • /wizard-ci flask
  • /wizard-ci javascript-node
  • /wizard-ci javascript-web
  • /wizard-ci laravel
  • /wizard-ci next-js
  • /wizard-ci nuxt
  • /wizard-ci python
  • /wizard-ci rails
  • /wizard-ci react-native
  • /wizard-ci react-router
  • /wizard-ci sveltekit
  • /wizard-ci swift
  • /wizard-ci tanstack-router
  • /wizard-ci tanstack-start
  • /wizard-ci vue

Test an individual app:

  • /wizard-ci android/Jetchat
  • /wizard-ci angular/angular-saas
  • /wizard-ci astro/astro-hybrid-marketing
Show more apps
  • /wizard-ci astro/astro-ssr-docs
  • /wizard-ci astro/astro-static-marketing
  • /wizard-ci astro/astro-view-transitions-marketing
  • /wizard-ci django/django3-saas
  • /wizard-ci fastapi/fastapi3-ai-saas
  • /wizard-ci flask/flask3-social-media
  • /wizard-ci javascript-node/express-todo
  • /wizard-ci javascript-node/fastify-blog
  • /wizard-ci javascript-node/hono-links
  • /wizard-ci javascript-node/koa-notes
  • /wizard-ci javascript-node/native-http-contacts
  • /wizard-ci javascript-web/saas-dashboard
  • /wizard-ci laravel/laravel12-saas
  • /wizard-ci next-js/15-app-router-saas
  • /wizard-ci next-js/15-app-router-todo
  • /wizard-ci next-js/15-pages-router-saas
  • /wizard-ci next-js/15-pages-router-todo
  • /wizard-ci nuxt/movies-nuxt-3-6
  • /wizard-ci nuxt/movies-nuxt-4
  • /wizard-ci python/meeting-summarizer
  • /wizard-ci rails/fizzy
  • /wizard-ci react-native/expo-react-native-hacker-news
  • /wizard-ci react-native/react-native-saas
  • /wizard-ci react-router/react-router-v7-project
  • /wizard-ci react-router/rrv7-starter
  • /wizard-ci react-router/saas-template
  • /wizard-ci react-router/shopper
  • /wizard-ci sveltekit/CMSaasStarter
  • /wizard-ci swift/hackers-ios
  • /wizard-ci tanstack-router/tanstack-router-code-based-saas
  • /wizard-ci tanstack-router/tanstack-router-file-based-saas
  • /wizard-ci tanstack-start/tanstack-start-saas
  • /wizard-ci vue/movies

Results will be posted here when complete.

Copy link
Copy Markdown
Collaborator

@gewenyu99 gewenyu99 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wild ✨

Have some things worth double checking

from fastapi.responses import JSONResponse
from posthog import capture

from app.posthog_client import posthog
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this new? Used to no be like this yah?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the old code was actually off. it should use the shared posthog_client.py using the Posthog() constructor as documented

https://posthog.com/docs/libraries/python#installation

new_count = safe_count + 1

capture("burrito_considered", properties={"total_considerations": new_count})
posthog.capture("burrito_considered", properties={"total_considerations": new_count})
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would check with Olly, I think he was really pushing for using just the plain capture pattern. I know it's changing lots with python these days tho

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a required consequence of the previous change above - the functional import proxies through posthog.api_key, and removing that raises an error

this also lists as it being deprecated atm:
https://github.com/PostHog/posthog-python/blob/795ee410682d3c28ffad759c95ccdbc5dcd9fd39/posthog/__init__.py#L867

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh.... that's super weird. I remember we recommended the opposite. Do everything without a client instance and use the shared client instance.

posthog.capture(
user.email,
"user_signed_up",
distinct_id=str(user.id),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be setting context no?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gewenyu99 could you clarify what you mean by context here? $set/@set_once person properties or the new_context()/identify_context() pattern?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new_context()/identify_context() pattern?

using this pattern instead of explicitly passing in distinct ID. Basically like if you imagine a route controller:

func handle_request(req, res):
	{distinct_id, session_id} = parse(req.headers)
	Identify_context(...):
		handle() # actual logic

I believe this is the preferred logic.

const phCookieName = Object.keys(req.cookies || {}).find(
name => name.startsWith('ph_') && name.endsWith('_posthog')
);
if (phCookieName && req.cookies[phCookieName]) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be sent through the headers instead of a cookie tbh. Should also be parsing session ID yah?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants