Skip to main content

altissimo-mixpanel

Reusable, typed Mixpanel analytics client for Altissimo projects.

Features

  • Typed API — full type annotations for all operations
  • Lazy SDK import — mixpanel is imported only when needed, zero import-time side effects
  • Disabled mode — no-op all calls when analytics is turned off or isn't configured
  • Error handling — swallow-and-log by default, configurable via on_error
  • Protocol for DI — MixpanelClientProtocol for dependency injection
  • Test helpers — FakeMixpanelClient records all calls in-memory
  • Optional dependency — works without mixpanel installed (fails gracefully)

Installation

Published on PyPI as altissimo-mixpanel; the import name is altissimo.mixpanel.

# With the Mixpanel SDK (recommended)
pip install "altissimo-mixpanel[mixpanel]"

# Without the SDK (for type checking / protocol-only usage)
pip install altissimo-mixpanel

Quick Start

Using from_env()

from altissimo.mixpanel import MixpanelClient

# Reads MIXPANEL_TOKEN from environment
# Missing token → disabled mode, with a warning (see Disabled Mode)
client = MixpanelClient.from_env()

# Track an event
client.track("user-123", "Page Viewed", properties={"page": "/home"})

# Set user profile properties
client.people_set("user-123", {"$name": "Jane Doe", "$email": "jane@example.com"})

Direct Construction

client = MixpanelClient(
    token="your-project-token",
    enabled=True,
    on_error="log",  # "log" | "raise" | "ignore"
)

Disabled Mode

# Explicitly disabled
client = MixpanelClient(token="...", enabled=False)
client.track("user-123", "Page Viewed")  # silently does nothing

# Via environment variable
# MIXPANEL_ENABLED=false → disabled
client = MixpanelClient.from_env()

# Missing token → automatically disabled, and a warning names the variable
# (no MIXPANEL_TOKEN set)
client = MixpanelClient.from_env()
assert not client.enabled

When the token is missing, from_env() behaves according to how tracking was turned on:

enabled Missing or empty token
True (passed explicitly) Raises ValueError naming the variable
None (default; MIXPANEL_ENABLED unset or truthy) Disabled, one warning naming the variable
False, or MIXPANEL_ENABLED falsey Disabled, no warning

Pass enabled=True where a deployment must send events, so a missing secret fails at startup instead of looking like Mixpanel going quiet. An app that only sends events when deployed can pass that condition, e.g. MixpanelClient.from_env(enabled=IS_DEPLOYED): quiet locally, an error on a deployment missing its token.

Error Handling

# Default: catch and log errors (analytics never crashes your app)
client = MixpanelClient(token="...", on_error="log")

# Raise errors (useful for debugging)
client = MixpanelClient(token="...", on_error="raise")

# Silently ignore errors
client = MixpanelClient(token="...", on_error="ignore")

Custom Consumer

from mixpanel import BufferedConsumer

# Use a buffered consumer for high-throughput
client = MixpanelClient(token="...", consumer=BufferedConsumer())

A BufferedConsumer only sends when its buffer fills, so flush it before the process exits (a Cloud Run instance shutting down, a job or CLI command finishing), or the buffered events are lost:

client.flush()

# Or flush automatically when the block ends, even if it raises:
with MixpanelClient(token="...", consumer=BufferedConsumer()) as client:
    client.track("user-123", "Job Finished")

With the default consumer, which sends each message immediately, flush() does nothing. A failing flush follows on_error like every other call.

Any object with send(endpoint, json_message) works as a consumer; the MixpanelConsumer protocol describes it for type checking.

Threads

One MixpanelClient can be shared across threads, such as a module-level client in a web app. Each thread gets its own Mixpanel SDK instance and, with the default consumer, its own HTTP session: the SDK's Consumer and BufferedConsumer aren't safe to share between threads.

A consumer= is a single object every thread shares, so in a threaded app pass a consumer_factory instead; it's called once per thread:

from mixpanel import BufferedConsumer, Consumer

# A shorter request timeout, one consumer per thread
client = MixpanelClient.from_env(consumer_factory=lambda: Consumer(request_timeout=5))

# Buffered, one buffer per thread
client = MixpanelClient(token="...", consumer_factory=BufferedConsumer)

flush() flushes every thread's consumer. Call it when no other thread is tracking, such as at shutdown.

Testing with FakeMixpanelClient

from altissimo.mixpanel import FakeMixpanelClient

def test_order_tracking():
    fake = FakeMixpanelClient()
    service = OrderService(mixpanel=fake)

    service.create_order(user_id="user-123", total=99.99)

    assert len(fake.tracked) == 1
    assert fake.tracked[0][1] == "Order Created"
    assert fake.tracked[0][2]["total"] == 99.99

Protocol-Based Dependency Injection

from altissimo.mixpanel import MixpanelClientProtocol

class OrderService:
    def __init__(self, mixpanel: MixpanelClientProtocol) -> None:
        self._mp = mixpanel

    def create_order(self, user_id: str, total: float) -> None:
        # ... business logic ...
        self._mp.track(user_id, "Order Created", properties={"total": total})

API Reference

MixpanelClient

Method Description
track(distinct_id, event_name, *, properties?, meta?) Track an event
people_set(distinct_id, properties, *, meta?) Set user profile properties
people_set_once(distinct_id, properties, *, meta?) Set properties only if not set
people_increment(distinct_id, properties, *, meta?) Increment numeric properties
people_union(distinct_id, properties, *, meta?) Append to list properties
people_unset(distinct_id, property_names, *, meta?) Remove properties
alias(alias_id, original_id, *, meta?) Create an identity alias

Environment Variables

Variable Default Description
MIXPANEL_TOKEN — Mixpanel project token
MIXPANEL_ENABLED true Set to false/0/no to disable

Development

# Install dependencies
poetry sync

# Run tests
poetry run pytest

# Run tests with coverage
poetry run pytest --cov=altissimo --cov-report=term-missing

# Lint
poetry run ruff check .

# Format
poetry run ruff format .

License

Apache-2.0

Metadata

Release files for altissimo-mixpanel 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for altissimo-mixpanel 0.1.1
File Size Uploaded Provenance Actions
altissimo_mixpanel-0.1.1.tar.gz 14.7 kB With provenance Details for altissimo_mixpanel-0.1.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for altissimo-mixpanel 0.1.1
File Interpreter ABI Platform Actions
altissimo_mixpanel-0.1.1-py3-none-any.whl Python 3 none any Details for altissimo_mixpanel-0.1.1-py3-none-any.whl

Total release size: 29.9 kB

Release files / altissimo_mixpanel-0.1.1.tar.gz

Download URL altissimo_mixpanel-0.1.1.tar.gz
Size 14.7 kB
Tags Source
SHA-256 checksum
How to use checksums
c00212eca2e5c18def8bb6f84824f668c08ceeed287a0bd85e8b02b666589663
BLAKE2b-256 checksum
How to use checksums
c84d2115887bf48fdabade28f1ea7b80768d6a3059aa9a182428c39e9978de5d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

Release files / altissimo_mixpanel-0.1.1-py3-none-any.whl

Download URL altissimo_mixpanel-0.1.1-py3-none-any.whl
Size 15.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4afb58c9d14fe2230a1852ff8dc4f9f4e3590889effbd0eea3e8f113698f985b
BLAKE2b-256 checksum
How to use checksums
bb63714881b9f14749a6a9fabc6d81e83741932581eec62ab70f9aac0de2819b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

Security for altissimo-mixpanel 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for altissimo_mixpanel-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page