Piano C1X SDK for Flutter

Joins Piano Composer and Piano Cxense: every experience the integration is enabled for is reported to Cxense as a page view carrying the state of the Composer user, and Composer receives the Cxense user as its browser id — so the segments of a user reach the experiences of that same user, without your application wiring the two SDKs together itself.

Installation

Add the dependencies to your pubspec.yaml:

dependencies:
  piano_common: ^1.0.4
  piano_composer: ^1.0.4
  piano_cxense: ^1.0.4
  piano_c1x: ^1.0.4

Supported Platforms

The platforms piano_cxense supports, since the page views this integration reports are queued in its database: Android, iOS and macOS out of the box, and Windows and Linux when your application installs a sqflite_common_ffi factory before Piano.init. See piano_cxense.

Getting Started

C1X is a module of the Piano SDK: pass a PianoC1xConfiguration to Piano.init next to the PianoCxenseConfiguration the page views are queued through, and reach the integration through piano.c1x. Composer needs no configuration of its own — the integration enables itself for the instance.

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

final piano = await Piano.init(
  endpoint: PianoEndpoint.production,
  aid: '<AID>',
  configurations: [
    PianoCxenseConfiguration(
      // Recommended for C1X: a page view reported for an experience stays open
      // for merging with the next one for half a minute.
      eventsMergePeriod: const Duration(seconds: 30),
    ),
    const PianoC1xConfiguration(),
  ],
);

// Enabled once, for every Composer client of the instance.
piano.c1x.enable(siteId: '<CXENSE_SITE_ID>');

final response = await piano.composer().execute(
  PianoComposerRequest(url: 'https://piano.io/article'),
);

Reaching piano.c1x without PianoC1xConfiguration — or after piano.close() — throws a StateError. The integration is off until enable is called, so the order the configurations are passed in does not matter.

The page views are queued through the Cxense module of the same instance, so enable throws a StateError when the instance was created without a PianoCxenseConfiguration.

Enabling

piano.c1x.enable(
  // The Cxense site id of the application.
  siteId: '<CXENSE_SITE_ID>',
  // The Cxense user (`ckp`) the page views are reported for, which Composer
  // also receives as its browser id. Defaults to the device id of the instance.
  userId: '<CXENSE_USER_ID>',
);

Call it once, after Piano.init: the integration enables itself for the instance rather than for one client, so every client piano.composer() hands out reports its experiences from there on — the clients created before enable as well as the ones created after it. Calling it again re-enables the integration with the passed settings, which is how the reported user is changed when a reader signs in.

The Composer requests of the instance have to carry a contentId or a url that is a valid http/https address while the integration is enabled, because a Cxense page view is identified by one of them: a request that carries neither is refused by PianoComposerClient.execute with an ArgumentError before it is sent, rather than after the experience was executed successfully.

Re-enabling applies to the requests that are sent from there on. An experience that is already on its way is reported for the settings it was executed with, so the page view of the article a reader was looking at before signing in is not attributed to the user who signed in halfway through it.

isEnabled, siteId and userId report what the integration is doing at the moment; the last two are null while it is disabled.

Disabling

piano.c1x.disable();

The Composer clients of the instance keep working: they stop reporting page views to Cxense and stop sending the Cxense user as their browser id — a client that carries a browserIdProvider of its own keeps reporting that one, and an interceptor your application enabled itself is left alone. Disabling twice does nothing twice, and piano.close() disables the integration together with the rest of the instance.

Unlike re-enabling, this applies to the experiences that are already on their way: an experience that is executed while disable is called reports no page view.

What Is Reported

Every experience a Composer client of the instance executes is reported as a PianoCxensePageViewEvent, queued through piano.cxense and sent by its dispatch loop:

  • userId (ckp) is the user enable was called with, and siteId the site;
  • location, contentId and referrer are the url, contentId and referer of the Composer request;
  • the userState custom parameter is the state of the Composer user: anon for a user Composer knows no id of, registered for one it knows an id of but no access for, and hasActiveAccess for one with at least one access;
  • the external user id is the Composer user id under your Cxense customer prefix, which the experience response carries — this is what joins the Composer user and the Cxense user;
  • rnd is the page view id Composer reported the experience under, so the experience and the page view reported for it carry the same one.

Do not track a page view of your own for a screen that executes an experience, since this is what reports it — a second page view of the same page would count that page twice.

Nothing here fails an experience that was executed successfully: whatever cannot be reported is logged through the logger of the Piano instance instead. The cases that report no page view at all are:

  • the response carries no Cxense customer prefix, which means C1X is not configured for your application — ask Piano support to turn it on;
  • the response holds no ExperienceExecute event to read the state of the user from;
  • the page view cannot be built, or cannot be queued in the Cxense database.

The cases that report the page view without a part of it are:

  • a referer Cxense would refuse is dropped, since it is metadata of the page view rather than what identifies it;
  • a Composer user id or customer prefix Cxense would refuse leaves the page view without its external user id, so the page view is still counted even though it is not joined with the Composer user.

Set eventsMergePeriod on the Cxense configuration to let a page view stay open for the events that follow it. Note that a merged event joins the queued page view under that one's rnd: a second experience executed for the same URL within the period is merged into the first record instead of being reported under its own page view id.

Merging stops at the Composer user, though. An experience executed for another user — after a login, say, which is what makes the same URL worth executing again — is reported as a page view of its own, so a record never joins the rnd of one user with the identity of another.

Recommendations

The recommendations of the Cxense Content API are not part of this package: query them with piano.cxense.content and display them with the widgets of piano_templates.

Several Instances

An application that reports to more than one Piano account runs one Piano instance per account, and the integration belongs to the instance it was configured on: piano.c1x reports the page views of that instance through the Cxense module of that same instance, so enabling or disabling one instance leaves the other one alone.

Libraries

piano_c1x