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: /growth-init (auto-instrument), /growth-diagnose <metric>, /growth-weekly, /growth-pmf, /growth-icp, /growth-strategy, /growth-pivot.

(The growth- prefix is intentional — it keeps our prompts out of the way of Claude Code's built-in /init and any other editor's defaults.)

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.4.tar.gz (10.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.4-py3-none-any.whl (9.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: growth_loop_sdk-0.1.4.tar.gz
  • Upload date:
  • Size: 10.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.4.tar.gz
Algorithm Hash digest
SHA256 a67bab8e252c0624ec6f3f4ec1ae67bb44dd5491363a5928ad90f2c4f2480420
MD5 ad8acfa8ba32b42aeb5fbd3df792c6f2
BLAKE2b-256 5e616fb86aacd8bf63121ab28419d9393bad418428ec6c58c1069681d5329b55

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for growth_loop_sdk-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 e8e7f18f39bf28a3416154e5a35dbfe7498110c0649cd49b17d08dfb9d701b98
MD5 ce7dcbcf5fc345964d2f73efd9dec081
BLAKE2b-256 ebe17d127a7fcd918654b8b98daf97aeb95a4dd41592f1504b5118c26473cde8

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