Skip to content

Add support for custom events - log_event #107

Merged
madhuchavva merged 4 commits intomainfrom
feat/custom-log-event
Mar 23, 2026
Merged

Add support for custom events - log_event #107
madhuchavva merged 4 commits intomainfrom
feat/custom-log-event

Conversation

@madhuchavva
Copy link
Copy Markdown
Contributor

This PR adds the ability to log custom events using log_event supported by the existing GrowthBookTrackingPlugin.

Usage

Sync client (GrowthBook)

from growthbook import GrowthBook, growthbook_tracking_plugin
gb = GrowthBook(
    client_key="sdk-abc123",
    attributes={"id": "user-42", "user_id": "u42", "utmSource": "google"},
    plugins=[
        growthbook_tracking_plugin(
            ingestor_host="https://us1.gb-ingest.com",  # default, can omit
            batch_size=20,
            batch_timeout=5.0,
        )
    ],
)
# Anywhere in your request handler:
gb.log_event("checkout_started", {"cart_value": 99, "currency": "USD"})
gb.log_event("button_clicked", {"button_id": "cta-hero"})
# Flush + teardown (e.g. app shutdown)
gb.destroy()

Async client (GrowthBookClient)

import asyncio
from growthbook import GrowthBookClient, growthbook_tracking_plugin
from growthbook.common_types import Options, UserContext
client = GrowthBookClient(
    Options(
        client_key="sdk-abc123",
        tracking_plugins=[
            growthbook_tracking_plugin(
                ingestor_host="https://us1.gb-ingest.com",
                batch_size=20,
                batch_timeout=5.0,
            )
        ],
    )
)
async def handle_request(user_id: str):
    await client.initialize()
    user_ctx = UserContext(attributes={"id": user_id, "user_id": user_id})
    await client.log_event("page_view", {"path": "/dashboard"}, user_ctx)
    await client.log_event("button_clicked", {"button_id": "upgrade-cta"}, user_ctx)
asyncio.run(handle_request("user-42"))

How it works:

  • Without the plugin → log_event logs a WARNING (no-op for the user's app)
  • With the plugin → events are batched and flushed via background thread, exactly as now.
  • set_event_logger is a public API, just like the setEventLogger in JS SDK.

…Client

Adds a public log_event(event_name, properties) method to the sync GrowthBook
class and an async equivalent to GrowthBookClient. Both expose set_event_logger()
so plugins (or callers directly) can register the callable that handles dispatch.
Without a registered logger the call is a no-op with a WARNING.

Options.event_logger field is added to common_types to carry the logger on the
async client's options object.

Made-with: Cursor
@madhuchavva madhuchavva marked this pull request as ready for review March 23, 2026 22:51
set_attributes() replaces self._attributes with a new dict but does not
write back to _user_ctx.attributes — that sync only happened lazily inside
_get_eval_context() (called by eval_feature). If log_event was called after
set_attributes() without an intervening eval_feature call, it would pass
stale attribute values (from initialization time) to the ingestor.

Fix mirrors the same two-line sync that _get_eval_context already performs.
Adds a regression test that fails without the fix.

Made-with: Cursor
@madhuchavva madhuchavva merged commit 926299c into main Mar 23, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants