Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions CHANGELOG.md
Copy link
Contributor

Choose a reason for hiding this comment

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

Might be worth adding a migration guide somewhere telling people the main things needed to migrate from v4 / v5 to v6

Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
# 6.0.0

This release contains a number of major breaking changes:
- feat: make distinct_id an optional parameter in posthog.capture and related functions
- feat: make capture and related functions return `Optional[str]`, which is the UUID of the sent event, if it was sent
- fix: remove `identify` (prefer `posthog.set()`), and `page` and `screen` (prefer `posthog.capture()`)
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the thinking behind removing these methods?

  • I get identify is pretty pointless because it doesn't actually persist across captures in the same way it does for the JS Web SDK. Can't you set the user id with contexts now? I'm guess that's the better way than setting the distcint_id on every capture
  • Worth keeping the page method so that people don't have to familiarize themselves with the $pageview property? Screen I'm less concerned with because it doesn't really make sense on the web and is only used in the mobile SDKs afaik

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, identify is removed because it's semantically confusing - we should push people towards identifying at the context level always.

Re: page, my impression is pageview is generally captured by the frontend?

Copy link
Member

@lricoy lricoy Jun 24, 2025

Choose a reason for hiding this comment

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

Several people prefer to use a backend-only instrumentation, this being a framework integration for a non-SPA website (e.g: only django/flask views - not using our utilities) or doing it all themselves on their backend.

I think that using context + capture is enough for them; it is also a more focused API, so I personally prefer it.

- fix: delete exception-capture specific integrations module. Prefer the general-purpose django middleware as a replacement for the django `Integration`.

To migrate to this version, you'll mostly just need to switch to using named keyword arguments, rather than positional ones. For example:
```python
# Old calling convention
posthog.capture("user123", "button_clicked", {"button_id": "123"})
# New calling convention
posthog.capture(distinct_id="user123", event="button_clicked", properties={"button_id": "123"})

# Better pattern
with posthog.new_context():
posthog.identify_context("user123")

# The event name is the first argument, and can be passed positionally, or as a keyword argument in a later position
posthog.capture("button_pressed")
```

Generally, arguments are now appropriately typed, and docstrings have been updated. If something is unclear, please open an issue, or submit a PR!

# 5.4.0 - 2025-06-20

- feat: add support to session_id context on page method
Expand Down
24 changes: 14 additions & 10 deletions example.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@

# Capture an event
posthog.capture(
"distinct_id",
"event",
{"property1": "value", "property2": "value"},
distinct_id="distinct_id",
properties={"property1": "value", "property2": "value"},
send_feature_flags=True,
)

Expand All @@ -65,31 +65,35 @@
posthog.alias("distinct_id", "new_distinct_id")

posthog.capture(
"new_distinct_id", "event2", {"property1": "value", "property2": "value"}
"event2",
distinct_id="new_distinct_id",
properties={"property1": "value", "property2": "value"},
)
posthog.capture(
"new_distinct_id",
"event-with-groups",
{"property1": "value", "property2": "value"},
distinct_id="new_distinct_id",
properties={"property1": "value", "property2": "value"},
groups={"company": "id:5"},
)

# # Add properties to the person
posthog.identify("new_distinct_id", {"email": "[email protected]"})
posthog.set(
distinct_id="new_distinct_id", properties={"email": "[email protected]"}
)

# Add properties to a group
posthog.group_identify("company", "id:5", {"employees": 11})

# properties set only once to the person
posthog.set_once("new_distinct_id", {"self_serve_signup": True})
posthog.set_once(distinct_id="new_distinct_id", properties={"self_serve_signup": True})


posthog.set_once(
"new_distinct_id", {"self_serve_signup": False}
distinct_id="new_distinct_id", properties={"self_serve_signup": False}
) # this will not change the property (because it was already set)

posthog.set("new_distinct_id", {"current_browser": "Chrome"})
posthog.set("new_distinct_id", {"current_browser": "Firefox"})
posthog.set(distinct_id="new_distinct_id", properties={"current_browser": "Chrome"})
posthog.set(distinct_id="new_distinct_id", properties={"current_browser": "Firefox"})


# #############################################################################
Expand Down
21 changes: 14 additions & 7 deletions mypy-baseline.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,20 @@ posthog/client.py:0: error: Library stubs not installed for "six" [import-untyp
posthog/client.py:0: note: Hint: "python3 -m pip install types-six"
posthog/client.py:0: error: Name "queue" already defined (by an import) [no-redef]
posthog/client.py:0: error: Need type annotation for "queue" [var-annotated]
posthog/client.py:0: error: Item "None" of "Any | None" has no attribute "get" [union-attr]
simulator.py:0: error: Unexpected keyword argument "anonymous_id" for "capture" [call-arg]
posthog/__init__.py:0: note: "capture" defined here
simulator.py:0: error: Unexpected keyword argument "anonymous_id" for "identify" [call-arg]
posthog/__init__.py:0: note: "identify" defined here
simulator.py:0: error: Unexpected keyword argument "traits" for "identify" [call-arg]
posthog/__init__.py:0: note: "identify" defined here
posthog/client.py:0: error: Incompatible types in assignment (expression has type "Any | list[Any]", variable has type "None") [assignment]
posthog/client.py:0: error: Incompatible types in assignment (expression has type "dict[Any, Any]", variable has type "None") [assignment]
posthog/client.py:0: error: "None" has no attribute "__iter__" (not iterable) [attr-defined]
posthog/client.py:0: error: Statement is unreachable [unreachable]
posthog/client.py:0: error: Incompatible types in assignment (expression has type "Any | dict[Any, Any]", variable has type "None") [assignment]
posthog/client.py:0: error: Incompatible types in assignment (expression has type "Any | dict[Any, Any]", variable has type "None") [assignment]
posthog/client.py:0: error: Incompatible types in assignment (expression has type "dict[Never, Never]", variable has type "None") [assignment]
posthog/client.py:0: error: Incompatible types in assignment (expression has type "dict[Never, Never]", variable has type "None") [assignment]
posthog/client.py:0: error: Right operand of "and" is never evaluated [unreachable]
posthog/client.py:0: error: Incompatible types in assignment (expression has type "Poller", variable has type "None") [assignment]
posthog/client.py:0: error: "None" has no attribute "start" [attr-defined]
posthog/client.py:0: error: "None" has no attribute "get" [attr-defined]
posthog/client.py:0: error: Statement is unreachable [unreachable]
posthog/client.py:0: error: Statement is unreachable [unreachable]
example.py:0: error: Statement is unreachable [unreachable]
posthog/ai/utils.py:0: error: Need type annotation for "output" (hint: "output: list[<type>] = ...") [var-annotated]
posthog/ai/utils.py:0: error: Function "builtins.any" is not valid as a type [valid-type]
Expand Down
Loading
Loading