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

# Feature Flags

> Toggle features remotely with environment-aware flags

Feature flags let you control feature rollout from the Grantiva dashboard without app updates. Access them via `grantiva.flags`.

<Note>
  Flag endpoints require authentication: run `validateAttestation()` once before reading flags (the SDK then attaches the attestation JWT automatically). In the Simulator, initialize the SDK with an API key — see [Simulator Setup](/simulator-setup). Requests without either receive a 401.
</Note>

## Get all flags

```swift theme={null}
let flags = try await grantiva.flags.getFlags()

if flags["dark_mode"]?.boolValue == true {
    enableDarkMode()
}
```

Flags are cached in memory for 5 minutes by default. See [Cache control](#cache-control) to configure the TTL.

## Typed accessors

```swift theme={null}
// Boolean (default: false)
let enabled = try await grantiva.flags.boolValue(for: "dark_mode", default: false)

// String (default: "")
let theme = try await grantiva.flags.stringValue(for: "theme", default: "light")

// Integer (default: 0)
let limit = try await grantiva.flags.intValue(for: "upload_limit", default: 10)

// Double (default: 0.0)
let threshold = try await grantiva.flags.doubleValue(for: "risk_threshold", default: 0.5)
```

Default values are returned when the flag doesn't exist or can't be parsed to the requested type.

## Get a single flag

```swift theme={null}
if let value = try await grantiva.flags.value(for: "feature_x") {
    print(value.rawValue)       // Raw string from server
    print(value.valueType)      // FlagValueType: boolean, integer, double, string, json
    print(value.boolValue)      // Bool?
    print(value.intValue)       // Int?
    print(value.stringValue)    // String (always succeeds)
    print(value.jsonValue)      // Any? (parsed JSON)
}
```

## Environments

Flags can be scoped to different environments:

```swift theme={null}
grantiva.flags.environment = .staging  // .development, .staging, .production
let flags = try await grantiva.flags.getFlags(forceRefresh: true)
```

Default is `.production`.

## Cache control

Flags are cached for 5 minutes by default. Adjust the TTL at any point after initialization:

```swift theme={null}
// 30-second TTL — fast propagation for kill-switches
grantiva.flags.cacheTTL = 30

// Disable caching entirely — always fetch fresh values
grantiva.flags.cacheTTL = 0

// Force refresh on next fetch
await grantiva.flags.refresh()

// Clear all cached flag data
await grantiva.flags.clearCache()
```

The cache is automatically cleared when user identity changes via `grantiva.identify()`.

## Live updates (SSE)

The SDK can hold a Server-Sent Events stream open against `GET /api/v1/flags/stream` so flag changes propagate to devices in seconds instead of waiting for the cache TTL.

A few behaviors worth knowing (SDK 2.0.6+):

* The server emits a `: keepalive` comment every 20 seconds; the SDK's idle timeout is 75 seconds (\~3 missed keepalives), so dead connections are detected and reconnected without churning on healthy quiet streams.
* Reconnect backoff resets after a healthy connection (60s+ uptime) drops, so devices on flaky networks don't accumulate permanent delays.
* The stream is scoped to the current `environment`.

## Tier limits

| Tier       | Max flags |
| ---------- | --------- |
| Free       | 10        |
| Pro        | 50/app    |
| Business   | 200/app   |
| Enterprise | Unlimited |
