Skip to main content

Server Locations

Fetching Locations

Fetch the list of available VPN servers after authentication:

import KapeVPN

let locations = KapeLocationService(handle: handle)
try await locations.fetchLocations()

Locations are available as a flat list or grouped by continent:

// All locations
locations.allLocations // [KapeServerLocation]

// Grouped by continent
locations.locationsByContinent // [String: [KapeServerLocation]]
// e.g. ["Europe": [...], "North America": [...]]

Each KapeServerLocation provides:

PropertyTypeDescription
idStringLocation ID (pass to connect(to:))
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 — 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():

try await locations.fetchSmartLocations()
locations.smartLocations // [KapeServerLocation] — sorted by best rating

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

try await locations.fetchSmartLocations(extendedTest: false)

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

try await locations.fetchSmartLocations { progress in
Task { @MainActor in
print("\(progress.locationId): \(progress.pingMs ?? 0) ms")
}
}
info

Call fetchLocations() before fetchSmartLocations(). Smart locations are resolved by matching against the full location list.

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 app's root object or view model:

import KapeCore

let networkHelper = KapeNetworkHelper(handle: handle)
networkHelper.start()

KapeNetworkHelper uses NWPathMonitor to detect network changes. On each change it reads the current SSID and BSSID, pushes them into the SDK configuration, and calls networkChanged() 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 in SwiftUI

KapeNetworkHelper is an ObservableObject with two published properties:

PropertyTypeDescription
ssidString?WiFi network name. nil on cellular or when entitlement is missing.
bssidString?WiFi access point MAC address. nil on cellular or when entitlement is missing.
// In your view model
@Published private(set) var wifiSSID: String?

networkHelper.$ssid.assign(to: &$wifiSSID)
// In your SwiftUI view
Section("Network") {
LabeledContent("SSID") { Text(viewModel.wifiSSID ?? "–") }
}

iOS entitlement

On iOS, reading the SSID and BSSID requires the com.apple.developer.networking.wifi-info entitlement. Add it to your app target's .entitlements file:

<key>com.apple.developer.networking.wifi-info</key>
<true/>

Without this entitlement, ssid and bssid are always nil. The helper still functions — network-change signals are sent to the SDK — but per-network caching has no benefit since all networks appear identical.

info

On macOS, no entitlement is required. WiFi info is read via CoreWLAN.

warning

Do not instantiate KapeNetworkHelper in the PacketTunnel extension. The extension does not need SmartLocation caching and has a strict memory budget.