> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reelevant.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Flutter SDK

> Reelevant analytics and personalization SDK for Flutter (Dart)

## Request flow

```mermaid theme={"theme":{"light":"github-light","dark":"github-dark"}}
sequenceDiagram
    participant App as Flutter App
    participant SDK as ReelevantAnalytics
    participant Runner as Reelevant Runner

    App->>SDK: ReelevantAnalytics(companyId, datasourceId)
    App->>SDK: await rlvt.setUser("user@example.com")
    SDK->>SDK: Store userId in SharedPreferences

    App->>SDK: await rlvt.run(RunOptions(...))
    SDK->>SDK: Resolve userId (explicit → stored → tmpId)
    SDK->>Runner: GET /{workflowId}/{entrypoint}?rlvt-u={userId}
    Runner-->>SDK: JSON / HTML / Image + headers
    SDK-->>App: RunResult { body, metadata, redirectionUrl }
    App->>App: Render content with Flutter Widgets

    App->>SDK: await result.trackClick()
    SDK->>Runner: GET /{workflowId}/{entrypoint}?mode=click (no redirect follow)
```

## Installation

Add the dependency to your `pubspec.yaml`:

```yaml theme={"theme":{"light":"github-light","dark":"github-dark"}}
dependencies:
  reelevant_analytics:
    git:
      url: https://github.com/reelevant-tech/reelevant-sdk-flutter.git
      ref: main
```

Then run:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
flutter pub get
```

## Initialization

```dart theme={"theme":{"light":"github-light","dark":"github-dark"}}
import 'package:reelevant_analytics/reelevant_analytics.dart';

final rlvt = ReelevantAnalytics(
  companyId: 'your-company-id',
  datasourceId: 'your-datasource-id',
  // Optional personalization config
  runnerUrl: 'https://reelevant.run',          // default
  runnerTimeout: Duration(seconds: 5),          // default
  fallback: FallbackStrategy.empty,             // default
);

// Set user identity (shared between analytics and personalization)
await rlvt.setUser('user@example.com');
```

## Analytics (event tracking)

```dart theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Page view
await rlvt.send(rlvt.pageView(labels: {'lang': 'en'}));

// Product page
await rlvt.send(rlvt.productPage('product-123', labels: {'category': 'shoes'}));

// Purchase
await rlvt.send(rlvt.purchase(
  ids: ['p1', 'p2'],
  totalAmount: 99.99,
  labels: {},
  transId: 'order-456',
));

// Add to cart
await rlvt.send(rlvt.addCart(ids: ['p1'], labels: {}));
```

## Personalization

### Single workflow run

```dart theme={"theme":{"light":"github-light","dark":"github-dark"}}
final result = await rlvt.run(RunOptions(
  workflowId: 'wf-hero',
  entrypoint: '43a490a0',
));

if (result.body is JsonRunContent) {
  final data = (result.body as JsonRunContent).content;
  renderCard(data);
} else if (result.body is HtmlRunContent) {
  final html = (result.body as HtmlRunContent).content;
  renderWebView(html);
} else if (result.body is ImageRunContent) {
  final bytes = (result.body as ImageRunContent).content;
  renderImage(bytes);
} else {
  showDefault();
}
```

### Multiple workflows in parallel

```dart theme={"theme":{"light":"github-light","dark":"github-dark"}}
final results = await rlvt.runAll([
  RunOptions(workflowId: 'wf-hero', entrypoint: 'entry1'),
  RunOptions(workflowId: 'wf-reco', entrypoint: 'entry2'),
]);
// results[0] corresponds to wf-hero, results[1] to wf-reco
```

### Click tracking

```dart theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Fire-and-forget — registers the click without following redirects
await result.trackClick();
```

### RunOptions

| Parameter    | Type                   | Required | Description                                                             |
| ------------ | ---------------------- | -------- | ----------------------------------------------------------------------- |
| `workflowId` | `String`               | Yes      | Workflow ID from the platform                                           |
| `entrypoint` | `String`               | Yes      | Entrypoint ID within the workflow                                       |
| `userId`     | `String?`              | No       | Override identity (default: auto-resolved from `setUser()` / device ID) |
| `params`     | `Map<String, String>?` | No       | Additional URL parameters forwarded to the runner                       |
| `locale`     | `String?`              | No       | Locale for content resolution                                           |
| `timeout`    | `Duration?`            | No       | Per-call timeout override                                               |

### RunResult

| Field            | Type                   | Description                                                                                        |
| ---------------- | ---------------------- | -------------------------------------------------------------------------------------------------- |
| `status`         | `int`                  | HTTP status code (0 for fallback)                                                                  |
| `source`         | `RunSource`            | `.runner` or `.fallback`                                                                           |
| `body`           | `RunContent`           | Discriminated content: `JsonRunContent`, `HtmlRunContent`, `ImageRunContent`, or `EmptyRunContent` |
| `metadata`       | `Map<String, dynamic>` | Metadata from `x-rlvt-output-node-metadata` header                                                 |
| `properties`     | `Map<String, dynamic>` | Properties from `x-rlvt-output-properties` header                                                  |
| `runId`          | `String?`              | Workflow run ID for tracking correlation                                                           |
| `executionPath`  | `List<String>`         | Branch IDs taken during execution                                                                  |
| `redirectionUrl` | `String`               | Pre-built click-through URL                                                                        |

### Fallback strategies

```dart theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Return empty result on error (default)
FallbackStrategy.empty

// Re-throw the error
FallbackStrategy.error

// Custom handler
ReelevantAnalytics(
  // ...
  fallbackHandler: (options, error) async {
    return RunResult(/* your fallback result */);
  },
);
```
