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

# NotGrantedReason

> Reasons why an entitlement was not granted

Represents why an entitlement was **not** granted when presenting an offer. These are **business outcomes, not errors** — a user dismissing the sheet or having no eligible offers is a valid result. Genuine failures (network, decoding, SDK not configured) are *thrown* as an [`EncoreError`](./errors) from `try await show()`, never delivered here.

`NotGrantedReason` is a `String`-backed enum, so each case has a stable `rawValue` you can log.

## Definition

```swift theme={null}
public enum NotGrantedReason: String, Equatable, Sendable {
    // User-initiated
    case userTappedClose   = "user_tapped_close"
    case userSwipedDown    = "user_swiped_down"
    case userTappedOutside = "user_tapped_outside"
    case userCancelled     = "user_cancelled"
    case lastOfferDeclined = "last_offer_declined"
    case dismissed         = "dismissed"

    // System-initiated
    case noOffersAvailable = "no_offer_available"
    case unsupportedOS     = "unsupported_ios"

    // Experiment-initiated
    case experimentControl = "experiment_control"
}
```

## Cases

| Case                 | Category   | Description                                                                                                                                                                                                                           |
| -------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `.userTappedClose`   | User       | User tapped the close / "No thanks" button on the sheet.                                                                                                                                                                              |
| `.userSwipedDown`    | User       | User swiped down to dismiss the sheet.                                                                                                                                                                                                |
| `.userTappedOutside` | User       | User tapped the backdrop outside the sheet.                                                                                                                                                                                           |
| `.userCancelled`     | User       | User cancelled mid-flow.                                                                                                                                                                                                              |
| `.lastOfferDeclined` | User       | User declined the last available offer in the carousel.                                                                                                                                                                               |
| `.dismissed`         | User       | Generic dismissal when the specific gesture is unknown.                                                                                                                                                                               |
| `.noOffersAvailable` | System     | No offers matched this user (targeting, caps reached, or already claimed).                                                                                                                                                            |
| `.unsupportedOS`     | System     | The device's iOS version can't present the SwiftUI offer sheet. Returned immediately on **iOS 15–16** (the sheet UI requires iOS 17+); no UI is shown.                                                                                |
| `.experimentControl` | Experiment | The user is in the **Control** cohort of a Net Conversion Lift experiment. A "ghost trigger" exposure was logged for measurement, but no UI was shown. Treat this exactly like a normal not-granted outcome — run your original flow. |

## Usage

The supported path is the `PresentationResult` returned by `try await show()`. Branch on the reason when you need analytics or special handling; otherwise just proceed with the user's original action (your `onPassthrough` handler already does this).

```swift theme={null}
let result = try await Encore.placement("cancel_flow").show()

if case .notGranted(let reason) = result {
    switch reason {
    case .userTappedClose, .userSwipedDown, .userTappedOutside,
         .userCancelled, .lastOfferDeclined, .dismissed:
        analytics.track("offer_user_declined", ["reason": reason.rawValue])

    case .noOffersAvailable:
        analytics.track("offer_none_available")

    case .unsupportedOS:
        // iOS 15–16: the offer sheet can't render. Fall straight through.
        break

    case .experimentControl:
        // NCL Control cohort: exposure logged, no UI. Behave as if no offer ran.
        break
    }

    // In every case, let the user continue.
    proceedWithCancellation()
}
```

<Tip>
  For most apps you can treat *all* not-granted reasons identically — just resume the original action. Distinguish cases only for analytics or experiment reporting.
</Tip>

## Related Types

* [PresentationResult](./presentation-result) — the result returned by `try await show()`.
* [Errors](./errors) — genuine failures are thrown as `EncoreError`, not surfaced as a `NotGrantedReason`.
