Metadata-Version: 2.4
Name: clamp-analytics
Version: 0.2.0
Summary: Server-side analytics SDK for Clamp. Send tracked events from Python apps (Django, FastAPI, Flask, etc.).
Project-URL: Homepage, https://clamp.sh
Project-URL: Documentation, https://clamp.sh/docs/sdk/python
Project-URL: Repository, https://github.com/clamp-sh/analytics-python
Project-URL: Issues, https://github.com/clamp-sh/analytics-python/issues
Author-email: Clamp Analytics <sidney@mail.clamp.sh>
License: MIT
License-File: LICENSE
Keywords: analytics,clamp,events,tracking
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: WWW/HTTP :: Site Management
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Requires-Dist: httpx>=0.24
Provides-Extra: dev
Requires-Dist: mypy>=1.0; extra == 'dev'
Requires-Dist: pytest-httpx>=0.30; extra == 'dev'
Requires-Dist: pytest>=7; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Description-Content-Type: text/markdown

# clamp-analytics

Server-side analytics SDK for [Clamp Analytics](https://clamp.sh) in Python.

Send tracked events from any Python server runtime to Clamp. Works with Django, FastAPI, Flask, Celery workers, scheduled jobs, and anything else that runs Python and can make outbound HTTPS calls.

## Install

```bash
pip install clamp-analytics
```

Python 3.9+ supported.

## Quick start

```python
from clamp_analytics import init, track, Money

init(project_id="proj_xxx", api_key="sk_proj_xxx")

# Simple event
track("signup", properties={"plan": "pro", "method": "email"})

# Link a server event to a browser visitor (e.g. inside a Stripe webhook)
track(
    "subscription_started",
    anonymous_id="aid_xxx",
    properties={"plan": "pro", "total": Money(29.00, "USD")},
)
```

Get a server API key at <https://clamp.sh/dashboard> (Settings → API Keys, format `sk_proj_...`). Set it as an environment variable; never commit it.

## API

### `init(project_id, api_key, endpoint=None)`

Initializes the SDK. Call once at process startup (e.g. in your Django `settings.py`, FastAPI lifespan, Flask app factory). Stores config in module-level state; subsequent `track()` calls use it.

`endpoint` is optional and overrides the default `https://api.clamp.sh`. Use this for self-hosted Clamp deployments or integration testing.

### `track(name, properties=None, anonymous_id=None, timestamp=None)`

Sends a server event.

- **`name`**: event name string. Examples: `"signup"`, `"subscription_started"`, `"feature_used"`.
- **`properties`**: optional dict. Values may be `str`, `int`, `float`, `bool`, or `Money`. No nested dicts (other than `Money`) and no arrays.
- **`anonymous_id`**: optional string. Links the server event to a browser visitor. Read the browser's anonymous ID via the JS SDK's `getAnonymousId()` and pass it through your auth flow (e.g. Stripe's `client_reference_id`).
- **`timestamp`**: optional. Pass a `datetime` (timezone-aware preferred; naive datetimes are assumed UTC) or an ISO 8601 string. If omitted, the SDK uses the current UTC time.

Returns `True` on success. Raises `ClampHTTPError` on a non-2xx response or `ClampNotInitializedError` if `init()` wasn't called.

### `Money(amount, currency)`

A typed monetary value. Use it for revenue, refunds, taxes; anywhere a currency-denominated amount belongs.

```python
track("purchase", properties={
    "plan": "pro",
    "total": Money(29.00, "USD"),
    "tax": Money(4.35, "USD"),
})
```

`amount` is in major units (29.00, not 2900). `currency` is an ISO 4217 code (uppercase, three letters).

### `capture_error(exception, context=None, anonymous_id=None, timestamp=None)`

Sends an exception as a `$error` event. Convenience over `track()` that extracts message, type, and stack from the exception. The server adds a stable fingerprint at ingest so the same bug groups across occurrences.

```python
from clamp_analytics import capture_error

try:
    process_webhook(payload)
except Exception as e:
    capture_error(e, context={"webhook": "stripe"})
```

- **`exception`**: any exception instance. Stack trace is captured via `traceback.format_exception`.
- **`context`**: optional flat mapping of additional properties. Values must be primitives (`str`, `int`, `float`, `bool`); the reserved key `handled` is ignored.
- **`anonymous_id`**: optional. Links the error to a browser visitor via the same anonymous ID flow as `track`.
- **`timestamp`**: optional `datetime` or ISO 8601 string.

Same return value and exceptions as `track()`. Lengths are capped (`error.message` 1KB, `error.type` 64 chars, `error.stack` 16KB) to match server-side limits.

## Framework integrations

Per-framework integration patterns (Django middleware, FastAPI dependency, Flask `after_request`, Celery task hook) are documented at <https://clamp.sh/docs/sdk/python>.

## Errors

The SDK is synchronous and raises on failure. There are no automatic retries. If you want fire-and-forget behavior, wrap the call yourself:

```python
import logging

try:
    track("subscription_started", properties={...})
except Exception:
    logging.exception("failed to send to Clamp")
```

For high-throughput webhook handlers, consider sending events through a background task queue (Celery, RQ, Dramatiq).

## Links

- Dashboard: <https://clamp.sh/dashboard>
- Docs: <https://clamp.sh/docs/sdk/python>
- Source: <https://github.com/clamp-sh/analytics-python>
- Issues: <https://github.com/clamp-sh/analytics-python/issues>
