SDK configuration
Point the Grovs SDKs at your self-hosted backend and set up Universal Links and App Links.
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 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.
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
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
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.
<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><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.
React Native
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
)Grovs.configure(
this, "your-api-key", useTestEnvironment = false,
baseURL = "https://sdk.example.com",
autoTrackScreenViews = false, clipboardDomains = null,
enabled = GrovsConsent.isEnabled(this)
)["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.
Web
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.
<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.
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:
curl -sS https://<SDK_HOST>/up # -> 200Then enable debug logging in the app and confirm the SDK authenticates against your host.
Grovs.setDebug(level: .info)Grovs.setDebug(LogLevel.INFO) // import io.grovs.model.LogLevelfinal grovs = Grovs();
await grovs.setDebugLevel('info');