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 \
  -e GROWTH_API_KEY=pk_live_<your-key> \
  -e GROWTH_HOST=https://api.growth-loop.dev \
  -- npx -y @growth-loop/mcp-server

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.2.tar.gz (10.7 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.2-py3-none-any.whl (9.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: growth_loop_sdk-0.1.2.tar.gz
  • Upload date:
  • Size: 10.7 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.2.tar.gz
Algorithm Hash digest
SHA256 adbc8fca578077874d003ca7aaac5e71a92ebf5ca1440b84c8800dca41e0addc
MD5 6203e78e57f663486b663591413c8e2d
BLAKE2b-256 602718069b8c610856752e83040f9bdca556564b5395837bcecbf47deccfbeb5

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for growth_loop_sdk-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 d6394b6256e4ef86b9d5785e15829d7a4891be0f67472992213906e9c42a757a
MD5 5881497f932da724ae7869cae23cd81f
BLAKE2b-256 1d4c711257092754fbac969114b21e1fdc0997908a8fc70e95bb3a183cd2da4e

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