5151 get_context_device_id ,
5252 get_context_distinct_id ,
5353 get_context_session_id ,
54+ get_context_options as _context_get_context_options ,
5455 get_tags as _context_get_tags ,
5556 identify_context as _context_identify_context ,
5657 _scoped as _context_scoped ,
5758 new_context ,
5859 set_context_device_id as _context_set_context_device_id ,
60+ set_context_option as _context_set_context_option ,
5961 set_context_session as _context_set_context_session ,
6062 tag as _context_tag ,
6163)
@@ -270,6 +272,11 @@ def _stringify_event_uuid(value) -> str:
270272 return canonical
271273
272274
275+ def _personless_options (personless : bool ) -> dict [str , Any ]:
276+ """The lowest option layer: no person profile for a generated distinct ID."""
277+ return {"process_person_profile" : False } if personless else {}
278+
279+
273280def add_context_tags (properties ):
274281 properties = properties or {}
275282 current_context = _get_current_context ()
@@ -706,6 +713,7 @@ def __init__(
706713 feature_flags_request_timeout_seconds = 3 ,
707714 feature_flags_request_max_retries = 1 ,
708715 super_properties = None ,
716+ super_options = None ,
709717 enable_exception_autocapture = False ,
710718 log_captured_exceptions = False ,
711719 project_root = None ,
@@ -791,7 +799,11 @@ def __init__(
791799 feature_flags_request_max_retries: Number of retries for feature flag
792800 requests after network, transport, or timeout failures. Defaults
793801 to 1. Set to 0 to disable retries.
794- super_properties: Properties merged into every captured event.
802+ super_properties: Properties for every captured event. Context
803+ tags and an event's own properties override them.
804+ super_options: Capture options for every captured event, such as
805+ ``{"cookieless_mode": True}``. Context options and an event's
806+ own ``options`` override them.
795807 enable_exception_autocapture: Automatically capture uncaught
796808 exceptions.
797809 log_captured_exceptions: Also log exceptions captured by error
@@ -999,6 +1011,7 @@ def __init__(
9991011 maximum = AI_MAX_MSG_SIZE ,
10001012 )
10011013 self .super_properties = super_properties
1014+ self .super_options = super_options
10021015 # Release id from POSTHOG_RELEASE_ID, attached to every event. Resolved
10031016 # here so the env var is read once per client.
10041017 self ._release_id = _resolve_release_id ()
@@ -1311,6 +1324,31 @@ def get_tags(self) -> Dict[str, Any]:
13111324 """
13121325 return _context_get_tags ()
13131326
1327+ def set_context_option (self , key : str , value : Any ) -> None :
1328+ """
1329+ Set a capture option for every event captured within the current context.
1330+
1331+ Args:
1332+ key: The option name, such as ``"process_person_profile"``.
1333+ value: The option value, sent as given.
1334+
1335+ Category:
1336+ Contexts
1337+ """
1338+ _context_set_context_option (key , value )
1339+
1340+ def get_context_options (self ) -> Dict [str , Any ]:
1341+ """
1342+ Get all capture options from the current context.
1343+
1344+ Returns:
1345+ Dict of all capture options in the current context.
1346+
1347+ Category:
1348+ Contexts
1349+ """
1350+ return _context_get_context_options ()
1351+
13141352 def identify_context (self , distinct_id : str ) -> None :
13151353 """
13161354 Identify the current context with a distinct ID.
@@ -1707,7 +1745,10 @@ def _capture(
17071745 flags_snapshot = kwargs .get ("flags" , None )
17081746 send_feature_flags = kwargs .get ("send_feature_flags" , False )
17091747 disable_geoip = kwargs .get ("disable_geoip" , None )
1710- options = _event_options (kwargs .get ("options" , None ))
1748+ options = {
1749+ ** _context_get_context_options (),
1750+ ** _event_options (kwargs .get ("options" , None )),
1751+ }
17111752 # Internal, set for minimal $feature_flag_called events: a strict allowlist
17121753 # applied to the fully-enriched properties dict just before enqueueing.
17131754 property_allowlist = kwargs .get ("_property_allowlist" , None )
@@ -1722,9 +1763,6 @@ def _capture(
17221763
17231764 (distinct_id , personless ) = get_identity_state (distinct_id )
17241765
1725- if personless and "$process_person_profile" not in properties :
1726- properties ["$process_person_profile" ] = False
1727-
17281766 msg = {
17291767 "properties" : properties ,
17301768 "timestamp" : timestamp ,
@@ -1829,7 +1867,11 @@ def _capture(
18291867 msg ["properties" ] = properties
18301868
18311869 return self ._enqueue (
1832- msg , disable_geoip , lane , property_allowlist = property_allowlist
1870+ msg ,
1871+ disable_geoip ,
1872+ lane ,
1873+ property_allowlist = property_allowlist ,
1874+ derived_options = _personless_options (personless ),
18331875 )
18341876
18351877 def _parse_send_feature_flags (self , send_feature_flags ) -> SendFeatureFlagsOptions :
@@ -1917,7 +1959,10 @@ def set(self, **kwargs: Unpack[OptionalSetArgs]) -> Optional[str]:
19171959 "$set" : properties ,
19181960 "event" : "$set" ,
19191961 "uuid" : uuid ,
1920- "options" : _event_options (kwargs .get ("options" , None )),
1962+ "options" : {
1963+ ** _context_get_context_options (),
1964+ ** _event_options (kwargs .get ("options" , None )),
1965+ },
19211966 }
19221967
19231968 return self ._enqueue (msg , disable_geoip )
@@ -1967,7 +2012,10 @@ def set_once(self, **kwargs: Unpack[OptionalSetArgs]) -> Optional[str]:
19672012 "$set_once" : properties ,
19682013 "event" : "$set_once" ,
19692014 "uuid" : uuid ,
1970- "options" : _event_options (kwargs .get ("options" , None )),
2015+ "options" : {
2016+ ** _context_get_context_options (),
2017+ ** _event_options (kwargs .get ("options" , None )),
2018+ },
19712019 }
19722020
19732021 return self ._enqueue (msg , disable_geoip )
@@ -2408,7 +2456,14 @@ def _report_capture_failure(
24082456 finally :
24092457 _on_error_state .active = False
24102458
2411- def _enqueue (self , msg , disable_geoip , lane = None , property_allowlist = None ):
2459+ def _enqueue (
2460+ self ,
2461+ msg ,
2462+ disable_geoip ,
2463+ lane = None ,
2464+ property_allowlist = None ,
2465+ derived_options = None ,
2466+ ):
24122467 # type: (...) -> Optional[str]
24132468 """Push a new `msg` onto a lane's queue (analytics when unspecified), return the event uuid or None."""
24142469
@@ -2445,7 +2500,15 @@ def _enqueue(self, msg, disable_geoip, lane=None, property_allowlist=None):
24452500 msg ["properties" ]["$geoip_disable" ] = True
24462501
24472502 if self .super_properties :
2448- msg ["properties" ] = {** msg ["properties" ], ** self .super_properties }
2503+ msg ["properties" ] = {** self .super_properties , ** msg ["properties" ]}
2504+
2505+ # Each layer overrides the one before it: values the SDK derives, such
2506+ # as personless, then super options, then context and event options.
2507+ msg ["options" ] = {
2508+ ** (derived_options or {}),
2509+ ** _event_options (self .super_options ),
2510+ ** (msg .get ("options" ) or {}),
2511+ }
24492512
24502513 # Set after the super_properties merge so an explicit `$release_id` from
24512514 # the caller's properties or the super properties wins over the env var.
0 commit comments