Growth Python SDK — drop-in product analytics for vibe-coded SaaS. Pairs with the Growth MCP server to give Claude Code an AI growth engineer for your Python app.
Project description
growth-loop-sdk
Python SDK for growth-loop.dev — Claude
Code-native product analytics for vibe-coded SaaS. The Python module name
is growth; the PyPI distribution is growth-loop-sdk.
Pairs with @growth-loop/mcp-server
so Claude Code can ask your funnels, retention, and revenue questions
directly with citations.
Install
pip install growth-loop-sdk
# or
uv add growth-loop-sdk
Requires Python 3.10+.
Quick start
import os
from growth import Growth, GrowthOptions
growth = Growth(GrowthOptions(
api_key=os.environ["GROWTH_KEY"],
host=os.environ.get("GROWTH_HOST", "https://api.growth-loop.dev"),
environment=os.environ.get("APP_ENV", "production"),
release=os.environ.get("GIT_COMMIT_SHA"),
))
# Anywhere in your app:
growth.track("signup_completed", {"plan": "pro"})
The SDK runs a background worker thread; on atexit it flushes pending
events automatically. On serverless platforms (Lambda, Cloud Run) call
growth.flush() before the request handler returns.
FastAPI
from fastapi import APIRouter
from growth import growth_span, growth_step
from growth_setup import growth # the singleton from above
router = APIRouter()
@router.post("/checkout")
@growth_span(growth, "checkout", distinct_id=lambda body: body.user_id)
async def checkout(body: CheckoutBody):
# automatically emits checkout.started / .completed / .failed
# with duration_ms and error metadata
return await stripe.charge(body)
@router.post("/signup")
@growth_step(growth, "signup_completed", distinct_id=lambda body: body.user_id)
async def signup(body: SignupBody):
return await create_user(body)
Flask
from flask import Blueprint
from growth import growth_span
from growth_setup import growth
bp = Blueprint("checkout", __name__)
@bp.route("/checkout", methods=["POST"])
@growth_span(growth, "checkout", distinct_id=lambda: g.user.id)
def checkout():
return stripe.charge(request.json)
Core API
Growth(options: GrowthOptions)
@dataclass
class GrowthOptions:
api_key: str # required
host: str = "https://api.growth-loop.dev"
flush_interval: float = 5.0 # seconds
batch_size: int = 50
environment: str | None = None # "production" | "preview" | "development"
release: str | None = None # git SHA — used by /diagnose for commit-level attribution
timeout: float = 5.0 # HTTP timeout
| Method | What it does |
|---|---|
track(name, properties=None, options=None) |
Enqueue one event. Non-blocking. |
identify(IdentifyOptions(distinct_id=..., properties=...)) |
Set the current distinct ID + emit $identify. |
set_distinct_id(id) |
Set the ID without emitting $identify. |
flush() |
Force-send queued events. Always call before request returns on serverless. |
shutdown() |
Flush + stop the worker. Called automatically on process exit. |
TrackOptions
@dataclass
class TrackOptions:
distinct_id: str | None = None # override the client's default
timestamp: datetime | None = None # override the auto-set UTC now
context: EventContext | None = None
Decorators
The three decorators auto-applied by claude /init (the MCP slash-prompt).
Each preserves your function signature; types and docs flow through @functools.wraps.
@growth_span(client, name, *, properties=None, distinct_id=None)
Emits <name>.started, <name>.completed (with duration_ms), or
<name>.failed (with error_message, error_name). Works on sync and
async functions automatically. Use on anything > 500ms or with non-trivial
failure rate.
@growth_span(growth, "ai.generate", distinct_id=lambda req: req.user_id)
async def generate(req: GenerateRequest):
return await anthropic.messages.create(...)
distinct_id may be a literal string or a callable that receives the
wrapped function's args/kwargs and returns the ID.
@growth_step(client, funnel_step, *, properties=None, distinct_id=None)
Single-event funnel marker. Drop on whatever step represents progress through your activation.
@growth_step(growth, "onboarding.invited_team")
def invite_team(team_id: str):
...
growth_track(client, name, properties=None)
Imperative one-off track. Equivalent to client.track(name, properties),
provided for symmetry with the decorator helpers.
growth_track(growth, "pricing_viewed", {"tier": "pro"})
Recommended event taxonomy
The MCP server's /diagnose, /weekly, and /pmf prompts know these names natively:
| Stage | Events |
|---|---|
| Identity | signup_completed, login_completed, $identify |
| Activation | onboarding.started, onboarding.completed, first_<thing>_created |
| Revenue | checkout_started, checkout_completed, subscription_created, subscription_canceled, payment_failed |
| Performance | growth_span(growth, "checkout", ...), growth_span(growth, "ai.generate", ...) |
Privacy
- Never put PII (email, raw IP, full address, payment details) in
properties. Usedistinct_idfor identity. Backend ClickHouse never decrypts or displayspropertiesas identity. - ClickHouse TTL is 12 months by default — events older than that are dropped automatically.
Going deeper
The SDK is the ingest layer. The agent layer (Claude Code + MCP) is what makes growth-loop different — install the MCP server too:
claude mcp add growth-loop -- npx -y @growth-loop/mcp-server \
-e GROWTH_API_KEY=pk_live_<your-key>
Then in Claude Code: /init (auto-instrument), /diagnose <metric>,
/weekly, /pmf, /icp, /strategy, /pivot.
License
MIT
Project details
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 growth_loop_sdk-0.1.1.tar.gz.
File metadata
- Download URL: growth_loop_sdk-0.1.1.tar.gz
- Upload date:
- Size: 7.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4c4e6961d2b68513405b44e2fd859c5e6f48e22a5beb2979ed9f07d607bc22bd
|
|
| MD5 |
b0fe31b31ffa19c0a146b5f3587cd4c5
|
|
| BLAKE2b-256 |
b5f4c244f7700047ea5c2ec83edfc4c8b2ab99c94ae7f2a5946e313b8a2d1845
|
File details
Details for the file growth_loop_sdk-0.1.1-py3-none-any.whl.
File metadata
- Download URL: growth_loop_sdk-0.1.1-py3-none-any.whl
- Upload date:
- Size: 9.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
504ce66922be3d3420aeeba39463b33b8dcf43dc36511fcdb6f8df8b66975a08
|
|
| MD5 |
85acf2a07bade3cef532d60c86de4c1f
|
|
| BLAKE2b-256 |
c4147c869c2d5cb163a117f4fe298dba4cda610c0d70dd86eee216843a97e580
|