# SDK configuration issues

> Fix SDK initialization failures, wrong API keys, test/production environment mismatches, and links that come back nil or null.

Source: https://docs.grovs.io/docs/troubleshooting/sdk-configuration-issues

Fix an SDK that isn't talking to the Grovs backend as expected. Work top to bottom: an initialization failure causes everything below it.

## SDK not initializing

**Cause:** a wrong or missing API key, or no network on the device. On iOS, the `Grovs.configure` completion receives `success == false`.

**Fix:** copy the API key from **Developers → API Key** in the dashboard. Pass it as shown in your platform's quick start: [iOS](https://docs.grovs.io/docs/sdk/ios/quick-start), [Android](https://docs.grovs.io/docs/sdk/android/quick-start), [Flutter](https://docs.grovs.io/docs/sdk/flutter/quick-start), [React Native](https://docs.grovs.io/docs/sdk/react-native/quick-start), [Web](https://docs.grovs.io/docs/sdk/web/quick-start). On iOS, check the completion:

```swift
Grovs.configure(APIKey: "your-api-key", useTestEnvironment: false, delegate: self) { success in
    if !success {
        print("Grovs failed to initialize — check the API key and network")
    }
}
```

Also check:

- **Where you configure.** Use `application(_:didFinishLaunchingWithOptions:)` on iOS and `Application.onCreate()` on Android, not later. On Flutter the key lives in `AndroidManifest.xml` (`grovs_api_key`) and `Info.plist` (`GrovsApiKey`). A typo in those key names leaves the SDK with no configuration, silently.
- **The SDK isn't disabled.** After `setSDK(enabled: false)`, for example in a consent flow, nothing works until you re-enable it. On iOS, configuring with `enabled: false` makes the completion report `false` without authenticating. That means "not started", not a bad key. See [Privacy & Consent](https://docs.grovs.io/docs/sdk/ios/privacy).
- **Self-hosted backends.** Pass `baseURL` with the domain only. The SDK appends the API path.

## Test vs production environment mismatch

**Cause:** each project has two environments, each with its **own domain and URL scheme**. The SDK targets one at configure time through `useTestEnvironment` (`true` = test, `false` = production). Links fail if a test build opens production links, or the app registers only one environment's domain and scheme.

**Fix:**

- Set `useTestEnvironment` per build: `true` for development, `false` for release.

  | Platform                   | Where                                                                                 |
  | -------------------------- | ------------------------------------------------------------------------------------- |
  | iOS, Android, React Native | `configure` parameter                                                                 |
  | Flutter                    | `grovs_use_test_environment` meta-data (Android), `GrovsUseTestEnvironment` key (iOS) |
  | Expo config plugin         | `useTestEnvironment` property                                                         |

- Register **both** environments in your app: both `applinks:` domains ([iOS](https://docs.grovs.io/docs/how-to-guides/ios/associated-domain)), both URL schemes ([iOS](https://docs.grovs.io/docs/how-to-guides/ios/url-scheme), [Android](https://docs.grovs.io/docs/how-to-guides/android/intent-filter)), and both hosts in your Android intent filters ([quick start](https://docs.grovs.io/docs/sdk/android/quick-start#3-add-intent-filters)).

- Test with links from the environment the build targets.

> **Note:** The REST API has the same split: the `ENVIRONMENT` header takes `production` or `test`. See [Authentication](https://docs.grovs.io/docs/api-reference/authentication#project-key).

## Links not generating (nil/null in the callback)

**Cause:** the SDK couldn't create the link. `generateLink` returned `nil`/`null` (iOS, React Native), threw a `GrovsException` (Flutter, Android coroutine form), or passed an error to Android's `(link, error)` listener. Usually initialization failed earlier, the device is offline, or the request was rejected.

**Fix:**

1. Confirm the SDK initialized (see [SDK not initializing](#sdk-not-initializing)). A failed `configure` is the most common cause.
2. On Android, log the listener's `error`, or catch `GrovsException` in the coroutine variant:

```kotlin
Grovs.generateLink(
    title = "Check out this product",
    data = mapOf("productId" to "12345"),
    lifecycleOwner = this,
    listener = { link, error ->
        link?.let { Log.d("Grovs", "Generated: $it") }
        error?.let { Log.e("Grovs", "Error: $it") }
    }
)
```

3. Turn on debug logging and retry. The SDK logs the failing request.

## Enable debug logging

Raise the SDK's log level and read the device logs: the Xcode console on iOS, Logcat on Android.

```swift
// iOS — levels: .info, .warn, .error
Grovs.setDebug(level: .info)
```

```kotlin
// Android — levels: INFO, ERROR
Grovs.setDebug(LogLevel.INFO)
```

```dart
// Flutter
await grovs.setDebugLevel('info');
```

On React Native, call the native `Grovs.setDebug` in your `AppDelegate`/`MainApplication`, as in the [React Native Quick Start](https://docs.grovs.io/docs/sdk/react-native/quick-start).

Use `info` while integrating and lower it before release. The initialization and link-generation lines usually name the problem: bad key, network failure or rejected request.
