Revclust
DocsBlogPricing
Log inStart free
DocsBlogPricingLog inStart free

Start Here

  • Overview
  • Access and Setup
  • Getting Started

Integration

  • Integrate the SDK
  • Trigger Your First Incident

Verification

  • Verify and Observe

Viewer

  • Viewer Workflow

Help

  • Troubleshooting

Reference

  • SDK Reference

Documentation

Integrate the SDK

Initialize the SDK once, add a small state snapshot, and wire the app for the first flow.

Use The SDK Entrypoint

Import package:revclust_flutter/revclust_flutter.dart. Initialize with RevclustConfig(...). Keep the returned Revclust client and reuse it later for capture, status, and upload checks.

Read The Runtime Values

Do not hardcode the SDK key in app code. Read it from the build and fail fast if it is missing.

import "package:revclust_flutter/revclust_flutter.dart";

const String revclustProjectKey = String.fromEnvironment(
  "REVCLUST_PROJECT_KEY",
);

String requireRevclustProjectKey() {
  if (revclustProjectKey.isEmpty) {
    throw StateError("Missing REVCLUST_PROJECT_KEY");
  }

  return revclustProjectKey;
}

For a first local check, the simplest run command is:

flutter run \
  --dart-define=REVCLUST_PROJECT_KEY=rpk_...

If your app already has flavors or CI-managed build injection, keep using that system. The important part is that the app passes the right SDK key into the projectKey field in RevclustConfig(...).

Initialize Once

Call Revclust.initialize(...) once during app startup and keep the returned client. Pass the rpk_... SDK key copied from Apps as projectKey. Do not initialize the SDK again with a different config in the same app process.

After initialization returns, check revclust.status. ready means the SDK can capture and upload. degraded or uploadBlocked can still queue local captures, but upload is not ready. misconfigured or notProvisioned means setup must be corrected before you continue.

import "package:flutter/widgets.dart";
import "package:revclust_flutter/revclust_flutter.dart";

Future<Revclust> configureRevclust() async {
  WidgetsFlutterBinding.ensureInitialized();

  final Revclust revclust = await Revclust.initialize(
    RevclustConfig(
      projectKey: requireRevclustProjectKey(),
    ),
  );

  revclust.setStateSnapshotProvider(
    () => const RevclustStateSnapshot(
      appState: <String, Object?>{
        "screen": "checkout_confirmation",
      },
      dataState: <String, Object?>{
        "order_ref": "ord_ref_7d82b1",
      },
    ),
  );

  return revclust;
}

Add Optional Build Metadata

Once the first capture works, pass release/build metadata from your existing build or CI system so captured incidents identify the release that produced them.

const String revclustAppVersion = String.fromEnvironment(
  "REVCLUST_APP_VERSION",
);
const String revclustBuild = String.fromEnvironment("REVCLUST_BUILD");
const String revclustGitSha = String.fromEnvironment("REVCLUST_GIT_SHA");

String? optionalBuildValue(String value) {
  if (value.isEmpty) {
    return null;
  }

  return value;
}

final Revclust revclust = await Revclust.initialize(
  RevclustConfig(
    projectKey: requireRevclustProjectKey(),
    appVersion: optionalBuildValue(revclustAppVersion),
    build: optionalBuildValue(revclustBuild),
    gitSha: optionalBuildValue(revclustGitSha),
    releaseStage: RevclustAppReleaseStage.production,
  ),
);

releaseStage, appVersion, build, and gitSha are reproduction metadata. They do not route the SDK to Revclust staging or local infrastructure.

Keep One Shared Client

Do not scatter initialization and capture calls across unrelated widgets. Put the client in one shared startup or service layer, initialize it there, and pass it wherever captures can happen.

final class RevclustRuntime {
  Revclust? _client;

  Revclust get client => _client!;

  Future<void> initialize() async {
    if (_client != null) {
      return;
    }

    final Revclust revclust = await configureRevclust();
    _client = revclust;
  }
}

In a Flutter app, that usually means main(), a top-level startup layer, or your DI container. Later code should receive this runtime or the Revclust client it owns.

Add A Small State Snapshot

setStateSnapshotProvider(...) takes a synchronous callback that returns RevclustStateSnapshot. Keep appState and dataState small, non-sensitive, and useful for one incident. Screen name, step name, and a few app-selected reference values are usually enough.

Add Dio Capture When Your App Uses Dio

Register your app's shared Dio client once:

revclust.enableDioCapture(dio);

Revclust then records bounded request outcomes and best-effort normalized paths. Query strings and error messages are omitted. If a path can contain sensitive text, provide an app-selected template on the request:

Options(extra: <String, Object?>{
  "routeTemplate": "/orders/{id}",
})

Do not include customer identifiers or other sensitive values in route templates.

Stop If Initialization Fails

Revclust.initialize(...) can throw if local capture setup fails. Catch that failure at app startup, log it clearly, and stop there until the runtime is healthy.

try {
  await revclustRuntime.initialize();
} on StateError catch (error, stackTrace) {
  debugPrint("Revclust initialization failed: $error");
  FlutterError.reportError(
    FlutterErrorDetails(exception: error, stack: stackTrace),
  );
  rethrow;
}

Integration Checklist

Before you move on, confirm that Revclust.initialize(...) returns a client, the build is injecting the right SDK key, revclust.status is ready, one state snapshot provider is registered, and one explicit capture point is ready for the first incident. Then move on to the first incident.

Continue to Trigger Your First Incident.

On this page

  1. Use The SDK Entrypoint
  2. Read The Runtime Values
  3. Initialize Once
  4. Add Optional Build Metadata
  5. Keep One Shared Client
  6. Add A Small State Snapshot
  7. Add Dio Capture When Your App Uses Dio
  8. Stop If Initialization Fails
  9. Integration Checklist
PrivacyTermsDPA
BlogDocumentationGitHub