> ## 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.

# onOutcome()

> Subscribe to the outcomes stream: every placement resolution, plus late strict-unlock verifications

`Encore.onOutcome(handler)` subscribes to the outcomes stream, the passive observation channel. It mirrors Swift's `AsyncStream<PlacementOutcome>` and Kotlin's `SharedFlow<PlacementOutcome>`.

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

```tsx theme={null}
onOutcome(handler: (outcome: PlacementOutcome) => void): () => void
```

Returns an unsubscribe function.

```tsx theme={null}
type PlacementOutcome = PresentationOutcome | StrictUnlockVerifiedOutcome;

interface PresentationOutcome {
  type: 'presentation';
  placementId: string;
  result: PresentationResult;
}

interface StrictUnlockVerifiedOutcome {
  type: 'strict_unlock_verified';
  transactionId: string;
}
```

## Usage

```tsx theme={null}
import { useEffect } from 'react';
import Encore from '@encorekit/react-native';

useEffect(
  () =>
    Encore.onOutcome((outcome) => {
      if (outcome.type === 'presentation') {
        analytics.track('encore_presentation', {
          placementId: outcome.placementId,
          result: outcome.result,
        });
      } else {
        // Entitlements are already refreshed natively by the time this lands.
        refreshEntitlements();
      }
    }),
  [],
);
```

The effect returns the unsubscribe function directly, so React tears the listener down on unmount.

## Behavior

* **It appends.** Unlike the 1.x `on*` setters, which replaced the previous handler, this is a real subscription: several observers can listen at once, matching the multicast streams both native SDKs expose.
* **There is no replay.** The native streams buffer nothing for late subscribers, 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. A `not_presented` resolution is still a `presentation` event, carrying the same [`PresentationResult`](./presentation-result) the call site received. A call the bridge rejects before it reaches the SDK resolves at the call site without reaching the stream.

## Late strict-unlock verification

`strict_unlock_verified` 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: 'strict'` on [`configure()`](./configure), a claim that ends unverified persists across process death and is re-checked on subsequent launches. When verification completes, entitlements are refreshed natively first, then the event is emitted. Its `transactionId` matches the [`ClaimedOffer.transactionId`](./presentation-result#claimedoffer) recorded on the original result, so you can join the two.

Under the default `unlock: 'optimistic'`, this event never fires.

## Related

* [PresentationResult](./presentation-result), the payload of `presentation` events.
* [configure()](./configure) for the `unlock` option that makes `strict_unlock_verified` reachable.
