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.1.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.1-py3-none-any.whl (9.1 kB view details)

Uploaded Python 3

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

Hashes for growth_loop_sdk-0.1.1.tar.gz
Algorithm Hash digest
SHA256 4c4e6961d2b68513405b44e2fd859c5e6f48e22a5beb2979ed9f07d607bc22bd
MD5 b0fe31b31ffa19c0a146b5f3587cd4c5
BLAKE2b-256 b5f4c244f7700047ea5c2ec83edfc4c8b2ab99c94ae7f2a5946e313b8a2d1845

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for growth_loop_sdk-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 504ce66922be3d3420aeeba39463b33b8dcf43dc36511fcdb6f8df8b66975a08
MD5 85acf2a07bade3cef532d60c86de4c1f
BLAKE2b-256 c4147c869c2d5cb163a117f4fe298dba4cda610c0d70dd86eee216843a97e580

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