Official Cohorly server-side Python SDK (Mixpanel-style product analytics, self-hosted)
Project description
Cohorly Python SDK
The official server-side Python SDK for Cohorly, a
self-hosted Mixpanel-style product analytics platform. The API mirrors
mixpanel-python, so migrating existing code is mostly a matter of swapping
the import and pointing at your Cohorly server.
- Zero runtime dependencies (stdlib
urllibonly) - Python 3.8+, fully typed (
py.typed) - Synchronous
Consumerand batchingBufferedConsumerwith the Cohorly retry contract (exponential backoff,Retry-After, bounded queue)
Installation
pip install cohorly
Or from this repo:
pip install ./sdks/python
Quickstart
from cohorly import Cohorly
ch = Cohorly("YOUR_PROJECT_TOKEN", api_host="http://localhost:4000")
# Track an event
ch.track("user-1", "Signed Up", {"plan": "pro", "source": "landing"})
# Link an alias to an existing distinct_id
ch.alias("user-1", "anon-7f3a")
# Update a user profile
ch.people_set("user-1", {"$first_name": "Ada", "plan": "pro"})
The project token comes from your Cohorly dashboard (Settings -> Projects).
api_host is the base URL of your Cohorly server (default
http://localhost:4000).
Tracking events
track(distinct_id, event_name, properties=None, meta=None) stamps these
default properties before sending:
| Property | Value |
|---|---|
distinct_id |
the id you pass |
time |
current unix time in milliseconds |
$insert_id |
random uuid4 hex (server-side dedup) |
$lib |
"python" |
$lib_version |
SDK version |
token |
your project token (stripped by server) |
Your properties merge over the defaults, so you may supply a custom time
or $insert_id (e.g. for idempotent re-sends):
ch.track("user-1", "Order Completed", {
"amount": 42.5,
"$insert_id": f"order-{order.id}", # dedup key
})
Historical imports
Use import_data to record events with an explicit timestamp (unix
milliseconds - Cohorly's convention throughout):
ch.import_data("user-1", "Legacy Signup", 1600000000000, {"source": "csv"})
Unlike Mixpanel there is no separate import endpoint, API secret, or 5-day
cutoff - it is the same /track pipeline.
User profiles (people)
ch.people_set("user-1", {"plan": "pro"}) # set/overwrite
ch.people_set_once("user-1", {"created": "..."}) # only if unset
ch.people_increment("user-1", {"logins": 1}) # numeric add
ch.people_unset("user-1", ["plan"]) # remove properties
ch.people_delete("user-1") # delete the profile
ch.people_update({"distinct_id": "user-1", "$set": {"x": 1}}) # raw op
These map to the Cohorly /engage operations $set, $set_once, $add,
$unset, $delete.
Consumers
By default every call sends immediately via a synchronous Consumer. For
higher throughput use BufferedConsumer, which batches messages (default 50
per request, server max 500) and implements the Cohorly retry contract:
from cohorly import Cohorly, BufferedConsumer
consumer = BufferedConsumer(max_size=50, api_host="http://localhost:4000")
ch = Cohorly("YOUR_PROJECT_TOKEN", consumer=consumer)
for user in users:
ch.track(user.id, "Backfill Event", {"batch": True})
consumer.flush() # IMPORTANT: drain remaining messages before exit
Retry behavior (BufferedConsumer):
- 429 / 5xx / network error - the queue is kept and retried with
exponential backoff: base 2s, doubling per consecutive failure, capped at
10 minutes, +/-20% jitter. A
Retry-Afterheader is honored when present. - 413 - the flush batch size is halved (floor 1) and retried.
- 400 - the rejected batch is dropped and
CohorlyExceptionis raised. - 401 (invalid token) - the queue is kept; backoff at the maximum delay.
- The in-memory queue is capped at 1000 messages per endpoint; the oldest message is dropped on overflow.
Cohorly batch rejections are atomic (nothing partially inserted), so retrying the same payload is always safe.
The synchronous Consumer(api_host, request_timeout=10, retry_limit=4)
retries 429/5xx/network errors inline with the same backoff schedule up to
retry_limit times, then raises CohorlyException.
Because the token travels with each message, several Cohorly instances with
different project tokens can share one consumer.
Error handling
Delivery failures raise cohorly.CohorlyException:
from cohorly import Cohorly, CohorlyException
try:
ch.track("user-1", "event")
except CohorlyException as exc:
log.warning("cohorly delivery failed: %s", exc)
Serialization
Messages are JSON. datetime/date values are serialized to ISO-8601 by the
default DatetimeSerializer; pass your own json.JSONEncoder subclass via
Cohorly(..., serializer=MyEncoder) for custom types.
Development
cd sdks/python
python3 -m venv .venv
.venv/bin/pip install pytest
.venv/bin/pytest
Tests run against the source tree (no install needed) and use a mocked transport - no network required.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cohorly-0.1.0.tar.gz.
File metadata
- Download URL: cohorly-0.1.0.tar.gz
- Upload date:
- Size: 14.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3e846c49eee0f7eea1924eb0275a856d0176e29e5127021a2bbf777559f25b46
|
|
| MD5 |
16354c01e18aad71fbec9b8669f77722
|
|
| BLAKE2b-256 |
24f8e5a2111f208f92943b49d04e9bc26df196574b6723704ec7e4af005b21a3
|
File details
Details for the file cohorly-0.1.0-py3-none-any.whl.
File metadata
- Download URL: cohorly-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ae19b52767403210561cc7ff203f68e69c066a7a596cccead2c9488e1072a73a
|
|
| MD5 |
11ece90354d5702956f34bc2da74810d
|
|
| BLAKE2b-256 |
f80aa19438406f8eec58e1dfa055574c28b5e4f08a7386f8e37ffceac0f31b0f
|