Skip to main content

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. Use distinct_id for identity. Backend ClickHouse never decrypts or displays properties as 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

growth_loop_sdk-0.1.0.tar.gz (7.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

growth_loop_sdk-0.1.0-py3-none-any.whl (9.1 kB view details)

Uploaded Python 3

File details

Details for the file growth_loop_sdk-0.1.0.tar.gz.

File metadata

  • Download URL: growth_loop_sdk-0.1.0.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

Hashes for growth_loop_sdk-0.1.0.tar.gz
Algorithm Hash digest
SHA256 934bcdde815c1db9254a72babac4563574cb497231ddc7a245239f8375900238
MD5 faee9d5b65a7cc6c7dbf3dc5e54c8c38
BLAKE2b-256 79e230525ee08e849b1efb8ea26d51007aca4e0436fc7041de90efad09aad8ca

See more details on using hashes here.

File details

Details for the file growth_loop_sdk-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for growth_loop_sdk-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d724fac280c96b35d439223f56ecca71f03596694fc6905a3f5db97cb805e8d5
MD5 e463ab939b0308256745a8eede759e7c
BLAKE2b-256 7a04d2d2286f86367ce9b149cb7363eb6856b451bdffc90e45f5b599b4468269

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page