piano_composer 1.0.1 copy "piano_composer: ^1.0.1" to clipboard
piano_composer: ^1.0.1 copied to clipboard

Piano Composer Flutter SDK.

Piano Composer SDK for Flutter #

Piano Composer Flutter SDK provides content personalization and A/B testing through Piano's experience management platform.

Installation #

Add the dependency to your pubspec.yaml:

dependencies:
  piano_composer: ^1.0.1

piano_composer depends on piano_common, so you need a Piano instance first:

import 'package:piano_common/piano_common.dart';
import 'package:piano_composer/piano_composer.dart';

final piano = await Piano.init(
  endpoint: PianoEndpoint.production,
  aid: '<AID>',
);

Getting Started #

Create a Piano Composer client via piano.composer(). Each call returns a new PianoComposerClient instance, so retain the reference when you need to share configuration or read back state (e.g. browserId, pageViewId) after a request.

final composer = piano.composer();

final request = PianoComposerRequest(
  url: 'https://piano.io/article',
  title: 'Article Title',
  tags: ['technology', 'news'],
);

final response = await composer.execute(request);

Configuration #

Configure Piano Composer with optional settings:

User Token #

Set the user's authentication token for personalized experiences:

final composer = piano.composer()
  ..userToken('<access_token>');

Google Analytics Client ID #

Link experiences to Google Analytics:

final composer = piano.composer()
  ..gaClientId('<ga_client_id>');

Browser ID Provider #

Provide a custom browser identifier:

final composer = piano.composer()
  ..browserIdProvider(() => '<browser_id>');

Experience Interceptors #

Add interceptors to modify requests or responses:

class CustomInterceptor implements PianoComposerInterceptor {
  @override
  void beforeExecute(PianoComposerRequest request) {
    // Modify request before sending
  }

  @override
  void afterExecute(
    PianoComposerRequest request,
    PianoComposerResponse response,
  ) {
    // Handle response
  }
}

final composer = piano.composer()
  ..addExperienceInterceptor(CustomInterceptor());

Making Requests #

Basic Request #

final composer = piano.composer();

final request = PianoComposerRequest(
  url: 'https://piano.io/page',
  title: 'Page Title',
  tags: ['category1', 'category2'],
  keywords: ['keyword1', 'keyword2'],
);

final response = await composer.execute(request);

Request with Content Metadata #

final composer = piano.composer();

final request = PianoComposerRequest(
  url: 'https://piano.io/article/123',
  title: 'Breaking News Article',
  description: 'Latest updates on technology',
  contentId: '123',
  contentType: 'article',
  contentCreated: PianoComposerRequest.formatDate(DateTime.now()),
  contentAuthor: 'John Doe',
  contentSection: 'Technology',
  zone: 'homepage',
  contentIsNative: false,
);

final response = await composer.execute(request);

Custom Variables #

Pass custom variables for advanced targeting:

final composer = piano.composer();

final request = PianoComposerRequest(
  url: 'https://piano.io',
  customVariables: {
    'user_type': ['premium'],
    'region': ['us-west'],
    'device': ['mobile'],
  },
);

final response = await composer.execute(request);

Debug Mode #

Enable verbose API responses for debugging:

final composer = piano.composer();

final request = PianoComposerRequest(
  url: 'https://piano.io',
  isDebug: true,
);

final response = await composer.execute(request);

Event Listeners #

Listen for specific event types from the response:

final composer = piano.composer();
final response = await composer.execute(
  request,
  listeners: [
    PianoComposerEventTypeListener<PianoComposerExperienceExecute>(
      onEvent: (event) {
        print('Experience executed: ${event.eventData}');
      },
    ),
    PianoComposerEventTypeListener<PianoComposerMeterEvent>(
      onEvent: (event) {
        print('Meter event received');
      },
    ),
  ],
);

Raw Event Handler #

Handle all events with a callback:

final composer = piano.composer();
final response = await composer.execute(
  request,
  onEvents: (events) {
    for (final event in events) {
      print('Event: ${event.eventData}');
    }
  },
);

Data Access #

Retrieve data from the response:

// Retain the same instance to read back state after execute()
final composer = piano.composer();
final response = await composer.execute(request);

// Get cookies for tracking
final tbCookie = response.tbCookie;      // Tracking cookie
final xbCookie = response.xbCookie;      // Experience cookie
final taCookie = response.taCookie;      // Analytics cookie

// Get identifiers
final browserId = composer.browserId;
final pageViewId = composer.pageViewId;

// Get edge cookies (if enabled)
final edgeCookies = composer.edgeCookies;

// Parse events
for (final event in response.result.events) {
  print('Event type: ${event.eventData.runtimeType}');
  print('User segments: ${event.eventExecutionContext.userSegments}');
}

Data Management #

Clear all stored data:

piano.composer().clearStoredData();

Error Handling #

Handle exceptions from Piano Composer:

try {
  final response = await piano.composer().execute(request);
} on PianoException catch (e) {
  print('Piano error: ${e.message}');
} catch (e) {
  print('Unexpected error: $e');
}