# SDK configuration

> Point the Grovs SDKs at your self-hosted backend and set up Universal Links and App Links.

Source: https://docs.grovs.io/docs/self-hosting/configure/sdk-configuration

The SDKs connect to the managed Grovs cloud by default. To use your server, pass your **SDK host** as `baseURL` when you configure the SDK. You need a deployed [stack](https://docs.grovs.io/docs/self-hosting/get-started/deployment) and a project **API key**, one per environment (test and production).

## The base URL is your SDK host

Pass `baseURL = https://<SDK_HOST>`, for example `https://sdk.acme.com`. This is the `sdk.` host under your **app domain** (`SERVER_HOST`). It is not the bare domain and not your links domain.

> **Warning:** **Pass `baseURL` in every `configure(...)` call, including release builds.** If you omit it (a common mistake in an `#else` or release branch), the SDK falls back to the hosted Grovs cloud (`sqd.link`) and your links won't resolve. Also match `useTestEnvironment` (`testEnvironment` on the web) to the API key: **test key → `true`**, **production key → `false`**. A production link opened by a test-mode app, or the reverse, won't resolve its payload.

## iOS

```swift
import Grovs

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    Grovs.configure(
        APIKey: "your-api-key",
        useTestEnvironment: false,
        baseURL: "https://sdk.example.com",   // your SDK_HOST
        delegate: self
    )
    return true
}
```

## Android

```kotlin
class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        Grovs.configure(this, "your-api-key", useTestEnvironment = false, baseURL = "https://sdk.example.com")
    }
}
```

## Flutter

The Flutter plugin has no `configure` call in Dart. It reads the base URL from the native config files at launch. Set `grovs_base_url` and `GrovsBaseURL` in every build variant you ship, including release.

If your links use copy-to-clipboard deferred deep linking, also list your link hosts under `grovs_clipboard_domains` and `GrovsClipboardDomains` so the SDK recognizes them.

**Android (AndroidManifest.xml)**

```xml
<application>
    <meta-data android:name="grovs_api_key" android:value="YOUR_API_KEY" />
    <meta-data android:name="grovs_use_test_environment" android:value="false" />
    <meta-data android:name="grovs_base_url" android:value="https://sdk.example.com" />
    <!-- Optional: comma-separated link hosts for clipboard deferred deep linking -->
    <meta-data android:name="grovs_clipboard_domains" android:value="a1b2c3d4.acme.link" />
</application>
```

**iOS (Info.plist)**

```xml
<key>GrovsApiKey</key>
<string>YOUR_API_KEY</string>
<key>GrovsUseTestEnvironment</key>
<false/>
<key>GrovsBaseURL</key>
<string>https://sdk.example.com</string>
<!-- Optional: link hosts for clipboard deferred deep linking -->
<key>GrovsClipboardDomains</key>
<array>
    <string>a1b2c3d4.acme.link</string>
</array>
```

The full key table is in the [Flutter Quick Start](https://docs.grovs.io/docs/sdk/flutter/quick-start#configuration).

## React Native

**iOS (AppDelegate.swift)**

```swift
Grovs.configure(
    APIKey: "your-api-key",
    useTestEnvironment: false,
    baseURL: "https://sdk.example.com",
    autoTrackScreenViews: false,
    clipboardDomains: nil,
    enabled: GrovsWrapperSwift.isSDKEnabled(),
    delegate: nil   // the wrapper registers itself as the delegate
)
```

**Android (MainApplication)**

```kotlin
Grovs.configure(
    this, "your-api-key", useTestEnvironment = false,
    baseURL = "https://sdk.example.com",
    autoTrackScreenViews = false, clipboardDomains = null,
    enabled = GrovsConsent.isEnabled(this)
)
```

**Expo (app.json)**

```json
["react-native-grovs-wrapper", {
  "apiKey": "your-api-key",
  "scheme": "your_app_scheme",
  "baseURL": "https://sdk.example.com"
}]
```

The other parameters are explained in the [React Native Quick Start](https://docs.grovs.io/docs/sdk/react-native/quick-start).

## Web

```javascript
import Grovs from 'grovs';

await Grovs.configure({
    apiKey: 'your-api-key',
    baseURL: 'https://sdk.example.com',   // your SDK_HOST
    onDeeplink: (payload) => {
        console.log('Link payload:', payload);
    },
});
```

## Server-to-server

Use the same host with header authentication:

```
POST https://sdk.example.com/...
PROJECT-KEY: your-api-key
ENVIRONMENT: production        # or "test"
```

## Universal Links and App Links

Links live on random **per-project subdomains** of your links and test links domains, such as `a1b2c3d4.acme.link` and `a1b2c3d4.test.acme.link`. Your app must associate with the **wildcards**, not a single subdomain.

### Associated Domains (iOS)

In Xcode, open **Signing & Capabilities → Associated Domains** and add the wildcard for **both** domains:

```
applinks:*.<DOMAIN_LIVE>
applinks:*.<DOMAIN_TEST>
```

With the defaults, that is `applinks:*.acme.com` and `applinks:*.test.acme.com`. iOS caches the association at install time, so delete and reinstall the app when you change Associated Domains.

### App Links (Android)

Android verifies App Links per concrete host. Add an intent filter in `AndroidManifest.xml` for each of the project's link subdomains, one per environment. The project's Domain page in the dashboard shows them.

```xml
<intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="https" android:host="a1b2c3d4.acme.link" />
</intent-filter>
```

### Association files

The backend serves `/.well-known/apple-app-site-association` and `/.well-known/assetlinks.json` on each link host, including verified custom domains. You don't host them yourself.

They return `404` until the project has the platform configured (bundle ID and Team ID, or package name and fingerprint) **and** the platform's redirect rule is enabled in the dashboard. Open the URL in a browser to check; the response names the missing piece.

> **Warning:** **Pre-issue wildcard certificates in production.** Link subdomains get a TLS certificate on demand on the first request, which takes a few seconds. Apple's association CDN can time out on that cold start and cache the failure for about an hour, so the app won't open the link. Pre-issue `*.<DOMAIN_LIVE>` and `*.<DOMAIN_TEST>` through your DNS provider's API. For development, append `?mode=developer` to an `applinks:` entry and enable **Settings → Developer → Associated Domains Development** to fetch the association from your server directly.

## Verify the connection

Check that the SDK host answers:

```bash
curl -sS https://<SDK_HOST>/up    # -> 200
```

Then enable debug logging in the app and confirm the SDK authenticates against your host.

**iOS**

```swift
Grovs.setDebug(level: .info)
```

**Android**

```kotlin
Grovs.setDebug(LogLevel.INFO)   // import io.grovs.model.LogLevel
```

**Flutter**

```dart
final grovs = Grovs();
await grovs.setDebugLevel('info');
```
