Skip to main content

Server Locations

Fetching Locations​

Fetch the list of available VPN servers after authentication:

val locations = vpnManager.createLocationService()
locations.fetchLocations() // suspend

Only locations serving the user's selected VPN protocol come back — a location that serves only Lightway is not offered while OpenVPN is selected. The selection is read once per call and nothing observes it, so call fetchLocations() again after setSelectedProtocol(...). A consumer without KapeVPN supplies the protocol directly; see VPN Locations.

Locations are exposed as StateFlows either as a flat list or as a grouping by continent:

// All locations
locations.allLocations // StateFlow<List<KapeServerLocation>>

// Grouped by continent
locations.locationsByContinent // StateFlow<Map<Continent, List<KapeServerLocation>>>
// e.g. {Continent.Europe: [...], Continent.Americas: [...]}

viewModelScope.launch {
locations.allLocations.collect { servers -> /* update UI */ }
}

Each KapeServerLocation provides:

PropertyTypeDescription
idStringLocation ID (pass to connect(...))
nameStringHuman-readable name (e.g. "Frankfurt")
countryStringISO 3166-1 alpha-2 country code
continentStringContinent or region name
latitudeDoubleLatitude coordinate
longitudeDoubleLongitude coordinate
ratingKapeLocationRating?Quality rating (smart locations only)

KapeLocationRating values: Excellent, Good, Ok, Degraded, Poor, Unknown. The enum is Comparable which means that higher ratings sort greater.

Smart Locations​

Smart locations are the SDK's recommended servers for the current user. The rating combines several signals: ping latency (min, avg, median, p90), short HTTP download and upload measurements, and geographic distance. Results are cached per network. When the user reconnects to a known WiFi network, cached results are returned immediately without re-running the full measurement.

Fetch smart locations after fetchLocations():

locations.fetchSmartLocations()
locations.smartLocations // StateFlow<List<KapeServerLocation>> — sorted by best rating

To disable HTTP tests (recommended on cellular to save data and reduce measurement time):

locations.fetchSmartLocations(extendedTest = false)

extendedTest applies to this path only — a progress-tracked scan (below) measures latency and never runs the HTTP tests.

To receive per-location progress updates while the measurement runs:

locations.fetchSmartLocations { progress ->
println("${progress.locationId}: ${progress.pingMs ?: 0} ms")
}
info

Call fetchLocations() before fetchSmartLocations(). Smart locations are resolved by matching against allLocations, which is scoped to the selected protocol — so a highly-rated location that does not serve that protocol is not recommended. With a narrow protocol selection smartLocations can come back empty even though the rating ran.

Network Monitoring​

KapeNetworkHelper (part of KapeCore) keeps the SDK aware of the current network and exposes the WiFi identity for display in your UI. It also enables per-network SmartLocation caching. When the user reconnects to a known network, cached results are returned immediately.

Setup​

Create one instance and call start() once after the SDK handle is ready. Typically in your Application class or a top-level view model:

import com.kape.platformsdk.core.KapeNetworkHelper

val networkHelper = KapeNetworkHelper(handle)
networkHelper.start()

KapeNetworkHelper uses ConnectivityManager to detect network changes. On each change it reads the current SSID and BSSID (via WifiManager), pushes them into the SDK configuration, and signals a network change so the SDK can invalidate or restore cached SmartLocation results for that network.

Call stop() when the helper is no longer needed:

networkHelper.stop()

Observing network info​

KapeNetworkHelper exposes two StateFlows:

PropertyTypeDescription
ssidStateFlow<String?>WiFi network name. null on cellular or when the location permission is missing.
bssidStateFlow<String?>WiFi access point MAC address. null on cellular or when the location permission is missing.
viewModelScope.launch {
networkHelper.ssid.collect { ssid -> /* show ssid ?: "–" */ }
}

Runtime permission​

On Android, reading the SSID and BSSID requires the ACCESS_FINE_LOCATION runtime permission (and NEARBY_WIFI_DEVICES on API 33+). These are declared and requested by your app, not by the SDK — the SDK does not bundle a location permission in its library manifest, to avoid forcing a sensitive permission on every integrator.

<!-- In your app's AndroidManifest.xml -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" />

Request the permission at runtime before calling start(). Without it, ssid and bssid are always null. The helper still functions — network-change signals are sent to the SDK — but per-network caching has no benefit since all networks appear identical.

warning

Do not instantiate KapeNetworkHelper inside KapeVpnService. The service does not need SmartLocation caching and runs under a tighter resource budget.