Python SDK
Track revenue, signups, product usage, and user identity from your Python backend using the official Ripples SDK.
Server-side tracking. Use the Python SDK to send events from your backend — ideal for tracking payments processed server-side, webhooks, or any event that shouldn't go through the browser.
Install
pip install ripples
Add your secret key to your environment:
RIPPLES_SECRET_KEY=priv_your_secret_key
Your secret key can be found in your Ripples dashboard under Settings → API Keys.
Quick start
from ripples import Ripples
ripples = Ripples()
# Track a payment
ripples.revenue(49.99, "user_123")
# Track a signup
ripples.signup("user_123", email="[email protected]")
# Track product usage
ripples.track("created a budget", "user_123", area="budgets")
# Identify / update a user
ripples.identify("user_123", email="[email protected]")
Events are batched in memory and sent automatically when the process exits.
Track revenue
Call revenue() whenever a payment is processed on your server:
ripples.revenue(49.99, "user_123")
Pass extra context as keyword arguments. Any key that isn't a known field becomes a custom property automatically:
ripples.revenue(49.99, "user_123",
email="[email protected]",
currency="EUR",
transaction_id="txn_abc123",
name="Pro Plan",
plan="annual", # custom property
coupon="WELCOME20", # custom property
)
Refunds are negative revenue:
ripples.revenue(-29.99, "user_123", transaction_id="txn_abc123")
Parameters
| Parameter | Type | Description |
|---|---|---|
amount required |
float |
Revenue amount in your default currency. Use negative values for refunds. |
user_id required |
str |
Your internal user ID. |
**attributes optional |
Any |
Additional properties: email, currency, transaction_id, name, plus any custom keys. |
Track product usage
Call track() when a user does something meaningful in your product. This powers the Activation dashboard — showing which product areas drive engagement and conversion.
# User did something meaningful
ripples.track("created a budget", "user_123", area="budgets")
# User added their 10th transaction — we consider this their activation moment
ripples.track("added transaction", "user_123",
area="transactions",
activated=True, # marks THIS occurrence as the activation moment
)
How it works. Ripples auto-detects activation moments (first occurrence per user per action), computes adoption rates by product area, and correlates usage patterns with retention and payment.
Parameters
| Parameter | Type | Description |
|---|---|---|
action_name required |
str |
What the user did. Be specific: 'created a budget', not 'budgets'. |
user_id required |
str |
Your internal user ID. |
area optional |
str |
Product area this action belongs to (e.g. 'budgets', 'reports'). Groups actions in the dashboard. |
activated optional |
bool |
Set to True on the specific occurrence when activation happens for this user. This does not mark the event type as an activation event — it marks this particular moment as when the user activated. For example, 'sent message' is a regular event, but when a user sends their 10th message you may consider that their activation moment and send that occurrence with activated=True. |
Track signups
Call signup() when a new user registers:
ripples.signup("user_123",
email="[email protected]",
name="Jane Smith",
referral="twitter", # custom property
plan="free", # custom property
)
Django example
from ripples import Ripples
def register(request):
user = User.objects.create_user(...)
ripples = Ripples()
ripples.signup(str(user.id),
email=user.email,
name=user.get_full_name(),
ripples_visitor_id=request.COOKIES.get("_rpl_vid"),
)
ripples.flush()
return JsonResponse({"id": user.id})
Flask example
from ripples import Ripples
@app.route("/register", methods=["POST"])
def register():
user = create_user(...)
ripples = Ripples()
ripples.signup(str(user.id),
email=user.email,
name=user.name,
ripples_visitor_id=request.cookies.get("_rpl_vid"),
)
ripples.flush()
return jsonify({"id": user.id})
Tip: pass the visitor ID. Include ripples_visitor_id with the value from the _rpl_vid cookie to link this signup back to the anonymous browsing session and correct traffic source attribution.
Identify users
Call identify() to update user traits at any time — on login, plan change, profile update, etc.:
ripples.identify("user_123",
email="[email protected]",
name="Jane Smith",
avatar_url="https://example.com/avatars/jane.jpg",
company="Acme Inc", # custom property
role="admin", # custom property
)
Properties
| Key | Type | Description |
|---|---|---|
email optional |
str |
User's email address. Shown in the visitor profile and used for Stripe revenue attribution. |
name optional |
str |
Display name shown in the visitor profile. |
avatar_url optional |
str |
URL to the user's avatar image. Displayed in the visitor profile. Also accepted as avatar. |
[custom] optional |
str | int | float |
Any additional traits you want to attach to the user (e.g. plan, company, role). |
Error handling
By default, errors during flush are swallowed so your app is never disrupted by a Ripples outage. Use on_error to log them:
import logging
ripples = Ripples(on_error=lambda e: logging.warning(f"Ripples error: {e}"))
You can also catch errors explicitly:
from ripples import RipplesError
try:
ripples.revenue(49.99, "user_123")
ripples.flush()
except RipplesError as e:
# Log or handle gracefully — never block the user flow
logging.warning(f"Ripples error: {e}")
Configuration
The SDK reads RIPPLES_SECRET_KEY from your environment automatically. You can also pass it explicitly:
ripples = Ripples("priv_explicit_key",
base_url="https://your-domain.com/api", # self-hosted
timeout=10, # seconds (default: 3)
)
The self-hosted URL can also be set via env:
RIPPLES_URL=https://your-domain.com/api
Configuration options
| Option | Default | Description |
|---|---|---|
base_url |
https://api.ripples.sh |
API endpoint. Override for self-hosted deployments. |
timeout |
3 |
HTTP read timeout in seconds. |
connect_timeout |
2 |
HTTP connection timeout in seconds. |
max_queue_size |
100 |
Auto-flush when the queue reaches this size. |
Flush manually
Events are batched and sent automatically when the Python process exits (via atexit). For long-running processes, web servers, or CLI scripts, call flush() explicitly:
ripples.flush()
Web frameworks. In Django or Flask, call flush() at the end of each request (or use middleware) to ensure events are delivered promptly. The auto-flush on exit works best for CLI scripts and short-lived processes.
Custom HTTP client
Subclass and override _post() to use httpx, aiohttp, or any other HTTP library:
class MyRipples(Ripples):
def _post(self, path: str, data: dict) -> None:
# your custom implementation using httpx, etc.
pass
Requirements
- Python 3.9+
requests