Skip to content

Commit f2941b6

Browse files
committed
feat: add fastapi integration
1 parent d45c046 commit f2941b6

1 file changed

Lines changed: 56 additions & 0 deletions

File tree

posthog/integrations/fastapi.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
from typing import TYPE_CHECKING
2+
import posthog
3+
from posthog import contexts
4+
5+
if TYPE_CHECKING:
6+
from starlette.requests import Request
7+
8+
9+
async def inject_posthog_tags(request: Request):
10+
"""
11+
Inject some common tags into posthog events for this request. This is helpful for linking frontend events to backend events.
12+
13+
The Django implementation pulls a lot of data from the request. However, this data should already be in place from the frontend
14+
library. If it's not, something else is wrong and we shouldn't hack around it by including more data here.
15+
16+
Instead, let's primary just tag the distinct_id and session_id from the request headers. These are injected in all HeyAPI
17+
requests, but are *not* guaranteed to be present on all requests.
18+
19+
https://github.com/PostHog/posthog-python/blob/master/posthog/integrations/django.py
20+
"""
21+
22+
# by default, there is not a context, so we must define one
23+
# `capture_exceptions=False` https://github.com/PostHog/posthog-python/issues/353
24+
with posthog.new_context(capture_exceptions=False):
25+
# intentionally overwrite any other session or distinct id set previously
26+
# it's up to the user to add dependencies in the correct order
27+
if distinct_id := request.headers.get("X-Posthog-Distinct-Id"):
28+
contexts.identify_context(distinct_id)
29+
30+
if session_id := request.headers.get("X-Posthog-Session-Id"):
31+
contexts.set_context_session(session_id)
32+
33+
tags = {}
34+
35+
if absolute_url := str(request.url):
36+
tags["$current_url"] = absolute_url
37+
38+
if request.method:
39+
tags["$request_method"] = request.method
40+
41+
if request.url.path:
42+
tags["$request_path"] = request.url.path
43+
44+
# TODO adding another dependency for IP extraction seems heavy-handed, but using the default IP is mostly useless
45+
# if request_ip := fastapi_access_logger.client_ip_from_request(request):
46+
# # django uses $ip_address, but posthog web library uses $ip
47+
# tags["$ip"] = request_ip
48+
49+
# although absolute_url contains the host, we must set it separately
50+
if request.url.hostname:
51+
tags["$host"] = request.url.hostname
52+
53+
for k, v in tags.items():
54+
contexts.tag(k, v)
55+
56+
yield

0 commit comments

Comments
 (0)