Skip to content

feat: implement tracking plugins for Flutter SDK#148

Open
vazarkevych wants to merge 10 commits into
mainfrom
feature/tracking-plugins
Open

feat: implement tracking plugins for Flutter SDK#148
vazarkevych wants to merge 10 commits into
mainfrom
feature/tracking-plugins

Conversation

@vazarkevych

@vazarkevych vazarkevych commented May 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

Implements a plugin system for the Flutter SDK, mirroring the Swift SDK implementation.

Changes

  • GrowthBookPlugin — abstract class with lifecycle hooks: initialize, onExperimentViewed,
    onFeatureEvaluated, close
  • PluginRegistry — manages registered plugins with per-plugin error isolation
  • GrowthBookTrackingPlugin — built-in plugin that batches events and sends them to the GrowthBook ingest endpoint
    (POST /track?client_key=...)
  • GrowthBookTrackingPluginConfig — configuration class for GrowthBookTrackingPlugin (ingestorHost, batchSize,
    batchTimeout)
  • GBSDKBuilderApp.addPlugin() — fluent builder method for registering plugins
  • GrowthBookSDK.dispose() — async, flushes and closes all registered plugins

Usage

final gb = await GBSDKBuilderApp(
  apiKey: 'sdk-xxx',                                                                                                
  hostURL: 'https://cdn.growthbook.io',                   
  growthBookTrackingCallBack: (_) {},
)                                           
  .addPlugin(GrowthBookTrackingPlugin())
  .initialize();
                                                                                                                    
// Custom config
.addPlugin(GrowthBookTrackingPlugin(                                                                                
  config: GrowthBookTrackingPluginConfig(batchSize: 50),  
))                                      

// Dispose when done                                                                                                
await gb.dispose();

@madhuchavva madhuchavva left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline review comments on plugin lifecycle, event delivery semantics, and documentation gaps.


@override
void initialize(String clientKey) {
if (clientKey.isEmpty) return;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding the plugin foundation here. I think the overall direction makes sense, but this timer lifecycle needs to be explicit before the API lands. initialize() starts a periodic timer and the only cleanup path is user-called dispose(), which is easy to miss in Flutter app/session lifecycles, tests, and hot reload scenarios. Can we document dispose() prominently in the README/API docs and make the expected lifecycle clear?

_flushTimer = null;
}

void _flushAsync() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_flushAsync() drains the queue before _post(). If the request fails, the batch is permanently dropped. That may be acceptable for best-effort analytics, but it should be intentional and documented. If we expect stronger delivery, we should retry or requeue with bounds.

@@ -96,6 +99,12 @@ class GBSDKBuilderApp {
this.featureUsageCallback = featureUsageCallback;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this PR adds public exports plus addPlugin()/dispose(), can we add README coverage for setup, custom ingest host, batching, dispose requirements, what attributes are sent, and failure/drop behavior? This gives users enough context to use the new API without lifecycle or privacy surprises.

@madhuchavva madhuchavva left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes based on the inline review comments. The notes call out functional gaps or compatibility/documentation risks that should be addressed before merge.

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