Skip to content

Commit e752a60

Browse files
committed
docs: centralize SDK examples in official docs
1 parent 84a4ee4 commit e752a60

4 files changed

Lines changed: 20 additions & 279 deletions

File tree

BEFORE_SEND.md

Lines changed: 2 additions & 234 deletions
Original file line numberDiff line numberDiff line change
@@ -1,237 +1,5 @@
11
# Before Send Hook
22

3-
The `before_send` parameter allows you to modify or filter events before they are sent to PostHog. This is useful for:
3+
Please see the official [Python library docs](https://posthog.com/docs/libraries/python#filtering-or-modifying-events-before-sending).
44

5-
- **Privacy**: Removing or masking sensitive data (PII)
6-
- **Filtering**: Dropping unwanted events (test events, internal users, etc.)
7-
- **Enhancement**: Adding custom properties to all events
8-
- **Transformation**: Modifying event names or property formats
9-
10-
## Basic Usage
11-
12-
```python
13-
import posthog
14-
from typing import Optional, Dict, Any
15-
16-
def my_before_send(event: Dict[str, Any]) -> Optional[Dict[str, Any]]:
17-
"""
18-
Process event before sending to PostHog.
19-
20-
Args:
21-
event: The event dictionary containing 'event', 'distinct_id', 'properties', etc.
22-
23-
Returns:
24-
Modified event dictionary to send, or None to drop the event
25-
"""
26-
# Your processing logic here
27-
return event
28-
29-
# Initialize client with before_send hook
30-
client = posthog.Client(
31-
api_key="your-project-api-key",
32-
before_send=my_before_send
33-
)
34-
```
35-
36-
## Common Use Cases
37-
38-
### 1. Filter Out Events
39-
40-
```python
41-
from typing import Optional, Any
42-
43-
def filter_events_by_property_or_event_name(event: dict[str, Any]) -> Optional[dict[str, Any]]:
44-
"""Drop events from internal users or test environments."""
45-
properties = event.get("properties", {})
46-
47-
# Choose some property from your events
48-
event_source = properties.get("event_source", "")
49-
if event_source.endswith("internal"):
50-
return None # Drop the event
51-
52-
# Filter out test events
53-
if event.get("event") == "test_event":
54-
return None
55-
56-
return event
57-
```
58-
59-
### 2. Remove/Mask PII Data
60-
61-
```python
62-
from typing import Optional, Any
63-
64-
def scrub_pii(event: dict[str, Any]) -> Optional[dict[str, Any]]:
65-
"""Remove or mask personally identifiable information."""
66-
properties = event.get("properties", {})
67-
68-
# Mask email but keep domain for analytics
69-
if "email" in properties:
70-
email = properties["email"]
71-
if "@" in email:
72-
domain = email.split("@")[1]
73-
properties["email"] = f"***@{domain}"
74-
else:
75-
properties["email"] = "***"
76-
77-
# Remove sensitive fields entirely
78-
sensitive_fields = ["my_business_info", "secret_things"]
79-
for field in sensitive_fields:
80-
properties.pop(field, None)
81-
82-
return event
83-
```
84-
85-
### 3. Add Custom Properties
86-
87-
```python
88-
from typing import Optional, Any
89-
90-
from datetime import datetime
91-
from typing import Optional, Any
92-
93-
def add_context(event: dict[str, Any]) -> Optional[dict[str, Any]]:
94-
"""Add custom properties to all events."""
95-
if "properties" not in event:
96-
event["properties"] = {}
97-
98-
event["properties"].update({
99-
"app_version": "2.1.0",
100-
"environment": "production",
101-
"processed_at": datetime.now().isoformat()
102-
})
103-
104-
return event
105-
```
106-
107-
### 4. Transform Event Names
108-
109-
```python
110-
from typing import Optional, Any
111-
112-
def normalize_event_names(event: dict[str, Any]) -> Optional[dict[str, Any]]:
113-
"""Convert event names to a consistent format."""
114-
original_event = event.get("event")
115-
if original_event:
116-
# Convert to snake_case
117-
normalized = original_event.lower().replace(" ", "_").replace("-", "_")
118-
event["event"] = f"app_{normalized}"
119-
120-
return event
121-
```
122-
123-
### 5. Log and drop in "dev" mode
124-
125-
When running in local dev often, you want to log but drop all events
126-
127-
128-
```python
129-
from typing import Optional, Any
130-
131-
def log_and_drop_all(event: dict[str, Any]) -> Optional[dict[str, Any]]:
132-
"""Convert event names to a consistent format."""
133-
print(event)
134-
135-
return None
136-
```
137-
138-
### 6. Combined Processing
139-
140-
```python
141-
from typing import Optional, Any
142-
143-
def comprehensive_processor(event: dict[str, Any]) -> Optional[dict[str, Any]]:
144-
"""Apply multiple transformations in sequence."""
145-
146-
# Step 1: Filter unwanted events
147-
if should_drop_event(event):
148-
return None
149-
150-
# Step 2: Scrub PII
151-
event = scrub_pii(event)
152-
153-
# Step 3: Add context
154-
event = add_context(event)
155-
156-
# Step 4: Normalize names
157-
event = normalize_event_names(event)
158-
159-
return event
160-
161-
def should_drop_event(event: dict[str, Any]) -> bool:
162-
"""Determine if event should be dropped."""
163-
# Your filtering logic
164-
return False
165-
```
166-
167-
## Error Handling
168-
169-
If your `before_send` function raises an exception, PostHog will:
170-
171-
1. Log the error
172-
2. Continue with the original, unmodified event
173-
3. Not crash your application
174-
175-
```python
176-
from typing import Optional, Any
177-
178-
def risky_before_send(event: dict[str, Any]) -> Optional[dict[str, Any]]:
179-
# If this raises an exception, the original event will be sent
180-
risky_operation()
181-
return event
182-
```
183-
184-
## Complete Example
185-
186-
```python
187-
import posthog
188-
from typing import Optional, Any
189-
import re
190-
191-
def production_before_send(event: dict[str, Any]) -> Optional[dict[str, Any]]:
192-
try:
193-
properties = event.get("properties", {})
194-
195-
# 1. Filter out bot traffic
196-
user_agent = properties.get("$user_agent", "")
197-
if re.search(r'bot|crawler|spider', user_agent, re.I):
198-
return None
199-
200-
# 2. Filter out internal traffic
201-
ip = properties.get("$ip", "")
202-
if ip.startswith("192.168.") or ip.startswith("10."):
203-
return None
204-
205-
# 3. Scrub email PII but keep domain
206-
if "email" in properties:
207-
email = properties["email"]
208-
if "@" in email:
209-
domain = email.split("@")[1]
210-
properties["email"] = f"***@{domain}"
211-
212-
# 4. Add custom context
213-
properties.update({
214-
"app_version": "1.0.0",
215-
"build_number": "123"
216-
})
217-
218-
# 5. Normalize event name
219-
if event.get("event"):
220-
event["event"] = event["event"].lower().replace(" ", "_")
221-
222-
return event
223-
224-
except Exception as e:
225-
# Log error but don't crash
226-
print(f"Error in before_send: {e}")
227-
return event # Return original event on error
228-
229-
# Usage
230-
client = posthog.Client(
231-
api_key="your-api-key",
232-
before_send=production_before_send
233-
)
234-
235-
# All events will now be processed by your before_send function
236-
client.capture("user_123", "Page View", {"url": "/home"})
237-
```
5+
SDK usage examples and code snippets live in the official documentation so they stay up to date.

README.md

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,18 @@
11
# PostHog Python
22

3-
<p align="center">
4-
<img alt="posthoglogo" src="https://user-images.githubusercontent.com/65415371/205059737-c8a4f836-4889-4654-902e-f302b187b6a0.png">
5-
</p>
6-
<p align="center">
7-
<a href="https://pypi.org/project/posthog/"><img alt="pypi installs" src="https://img.shields.io/pypi/v/posthog"/></a>
8-
<img alt="GitHub contributors" src="https://img.shields.io/github/contributors/posthog/posthog-python">
9-
<img alt="GitHub commit activity" src="https://img.shields.io/github/commit-activity/m/posthog/posthog-python"/>
10-
<img alt="GitHub closed issues" src="https://img.shields.io/github/issues-closed/posthog/posthog-python"/>
11-
</p>
12-
13-
Please see the [Python integration docs](https://posthog.com/docs/integrations/python-integration) for details.
14-
15-
## Python Version Support
16-
17-
| SDK Version | Python Versions Supported | Notes |
18-
| ------------- | ---------------------------- | -------------------------- |
19-
| 7.3.1+ | 3.10, 3.11, 3.12, 3.13, 3.14 | Added Python 3.14 support |
20-
| 7.0.0 - 7.0.1 | 3.10, 3.11, 3.12, 3.13 | Dropped Python 3.9 support |
21-
| 4.0.1 - 6.x | 3.9, 3.10, 3.11, 3.12, 3.13 | Python 3.9+ required |
3+
Please see the main [PostHog docs](https://posthog.com/docs).
4+
5+
SDK usage examples and code snippets live in the official documentation so they stay up to date.
6+
7+
## Documentation
8+
9+
- [Python library docs](https://posthog.com/docs/libraries/python)
10+
- [AI observability installation docs](https://posthog.com/docs/ai-observability/installation)
2211

2312
## Contributing
2413

25-
See [CONTRIBUTING.md](CONTRIBUTING.md) for local setup, test, and development workflow instructions.
14+
See [CONTRIBUTING.md](CONTRIBUTING.md) for local setup and test instructions.
15+
16+
## Releasing
17+
18+
See [RELEASING.md](RELEASING.md).

README_ANALYTICS.md

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
# posthoganalytics
1+
# PostHog Python analytics
22

3-
> **Do not use this package.** Use [`posthog`](https://pypi.org/project/posthog/) instead.
3+
Please see the main [PostHog docs](https://posthog.com/docs).
44

5-
```bash
6-
pip install posthog
7-
```
5+
SDK usage examples and code snippets live in the official documentation so they stay up to date.
86

9-
This package exists solely for internal use by [posthog/posthog](https://github.com/posthog/posthog) to avoid import conflicts with the local `posthog` package in that repository. It is an automatically generated mirror of `posthog` — same code, same versions, just published under a different name.
7+
## Documentation
108

11-
If you are not working on the PostHog main repository, you should never need this package. All documentation, issues, and development happen in [`posthog-python`](https://github.com/posthog/posthog-python).
9+
- [Python library docs](https://posthog.com/docs/libraries/python)

playgrounds/fastapi-exception-capture/USAGE.md

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)