Python port of formation-res/formation-web-analytics-client.
This package keeps the same low-surprise event API and collector wire format as the JavaScript client, so Python services and scripts can send compatible analytics events to a Formation analytics endpoint.
pip install formation-web-analytics-clientFor local development:
python -m pip install -e .from formation_web_analytics_client import create_analytics
analytics = create_analytics(
endpoint="https://analytics.example.com/collect",
site_id="marketing-site",
)
analytics.page()
analytics.event("cta_click", {"label": "hero-demo-button"})If you want page metadata on every event, provide a context callback:
from formation_web_analytics_client import create_analytics
analytics = create_analytics(
endpoint="https://analytics.example.com/collect",
site_id="marketing-site",
page_context_provider=lambda: {
"url": "https://example.com/pricing?plan=pro",
"path": "/pricing?plan=pro",
"title": "Pricing",
"referrer": "https://google.com",
},
on_error=lambda error: print("analytics delivery failed", error.kind, error.status),
)
analytics.identify("user-123", {"plan": "pro"})
analytics.event("checkout_started", {"step": "shipping"})- Validates
endpoint,site_id, event names, andidentify()user ids. - Sends the same top-level event shape as the JavaScript client:
type,site_id,timestamp,session_id,anonymous_id,user_id, optional page context, andpayload. - Merges payload in the same order as the reference client:
default_payload, thenset_context(), then per-call payload. - Sends events with JSON
POSTrequests. - Treats non-2xx responses and network failures as delivery errors.
- Reports failures through the optional
on_errorhook while keeping public tracking calls best-effort.
create_analytics(...)accepts either anAnalyticsConfiginstance or keyword arguments.createAnalytics(...)is exported as a compatibility alias for teams that want the JavaScript-style name.auto_pageviewsdefaults toTrue, matching the JavaScript client. In Python, this sends one immediatepage_viewwhen the client is created.- Browser-only SPA navigation tracking does not exist in Python. If you want more page views, call
page()explicitly. - Page context is optional. When you provide
page_context_provider, the client forwardsurl,path,title, andreferreras top-level event fields. - Transport uses the Python standard library, so there are no runtime dependencies.
create_analytics(...)page(payload=None)event(event_type, payload=None)identify(user_id, payload=None)set_context(payload)
{
"type": "checkout_started",
"site_id": "marketing-site",
"timestamp": "2026-06-01T12:34:56.000000Z",
"session_id": "6a03cdb8-7ef6-4ec3-9bc8-a078f2b4af9f",
"anonymous_id": "79ffbb5a-b4ca-4b89-a58d-c32014b0cf32",
"user_id": "user-123",
"url": "https://example.com/pricing?plan=pro",
"path": "/pricing?plan=pro",
"referrer": "https://google.com",
"title": "Pricing",
"payload": {
"step": "shipping"
}
}Run the test suite:
python -m unittest discover -s tests -vInstall locally and run the tests against the installed package:
python -m pip install -e .
python -m unittest discover -s tests -vThis repo intentionally tracks the behavior of the JavaScript reference client closely. When we need a Python-specific adaptation, we document it clearly instead of silently drifting the API.