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

# outcomes

> Broadcast stream of every placement resolution, plus late strict-unlock verifications

`Encore.shared.outcomes` is the passive observation channel. It mirrors Swift's `AsyncStream` and Kotlin's `SharedFlow` of placement outcomes.

Use it for anything that watches results without owning a call site: analytics forwarding, app-owned state, a debug overlay. Control flow belongs at the call site, on the value [`show()`](./placement) returns.

## Signature

```dart theme={null}
Stream<EncorePlacementOutcome> get outcomes

sealed class EncorePlacementOutcome {}

final class EncorePlacementPresentation extends EncorePlacementOutcome {
  final String placementId;
  final EncorePresentationResult result;
}

final class EncoreStrictUnlockVerified extends EncorePlacementOutcome {
  final String transactionId;
}
```

## Usage

```dart theme={null}
final subscription = Encore.shared.outcomes.listen((outcome) {
  switch (outcome) {
    case EncorePlacementPresentation(:final placementId, :final result):
      analytics.log('encore_presentation', placementId, result);
    case EncoreStrictUnlockVerified(:final transactionId):
      // A claim the server confirmed after its flow ended.
      entitlements.refresh(transactionId);
  }
});

// When the observer goes away:
await subscription.cancel();
```

`EncorePlacementOutcome` is sealed, so the `switch` is exhaustive.

## Behavior

* **It is a broadcast stream.** Several listeners can subscribe at once, matching the multicast streams both native SDKs expose.
* **There is no replay.** Nothing is buffered for late listeners, by design, since outcomes can carry user-scoped claim data. Subscribe at startup if you want all of them.
* **Every `show()` the SDK resolves emits**, including the ones that presented nothing. An `EncoreNotPresented` result still arrives as an `EncorePlacementPresentation`, carrying the same [`EncorePresentationResult`](./presentation-result) the call site received.
* **Events the plugin doesn't recognize are dropped**, so a newer native SDK can't emit something this version would misread.

## Late strict-unlock verification

`EncoreStrictUnlockVerified` is the stream's reason for existing. It has no `show()` equivalent, because it resolves *after* its flow ended, possibly on a later launch.

With `unlock: EncoreUnlockMode.strict` on [`configure()`](./configure), a claim that ends unverified persists across process death and is re-checked on later launches. When verification completes, the event is emitted. On iOS the native SDK refreshes its entitlement cache first; Android keeps no such cache, so refresh your own access state when the event arrives. Its `transactionId` matches the [`EncoreClaimedOffer.transactionId`](./presentation-result#encoreclaimedoffer) recorded on the original result, so you can join the two.

Under the default `EncoreUnlockMode.optimistic`, this event never fires.

## Related

* [EncorePresentationResult](./presentation-result): the payload of `EncorePlacementPresentation`
* [configure()](./configure): the `unlock` option that makes `EncoreStrictUnlockVerified` reachable
