Satellite: Android
Use an Android phone as a BirdNET-NG satellite for portable bird audio capture.
Platform: Android — a Capacitor-based mobile app with native AudioRecord plugin, background recording, and in-app registration.
Device Requirements
- Android 8.0 (Oreo) or newer
- Working microphone
- GPS (for location-aware species filtering)
- Network connectivity (Wi-Fi or mobile data)
Building the APK
The mobile app is built using Docker:
docker build -t birdnet-mobile -f packages/mobile/Dockerfile .
docker create --name birdnet-apk birdnet-mobile
docker cp birdnet-apk:/output/app-debug.apk ./birdnet-satellite.apk
docker rm birdnet-apk
Transfer the APK to your phone and install it. The debug keystore is persistent across builds so APK updates work without uninstalling.
Android Permissions
The app requests these permissions at startup:
| Permission | Why |
|---|---|
RECORD_AUDIO |
Capture audio from the microphone |
ACCESS_FINE_LOCATION |
GPS coordinates for geo-aware inference |
If permissions are denied, the app shows an "Open Settings" button to navigate to Android's app permission screen.
Setup Flow
1. Sign In
Enter your hub URL (default: https://birdnet.owndesign.net) and log in with your credentials. The app uses a JWT Bearer token for authentication.
2. Register Satellite
Choose a name for this satellite and select the tenant it belongs to. GPS location is acquired automatically after registration -- no need to enter coordinates during registration.
3. GPS Requirement
Before recording starts, the app requires a GPS fix or manually entered coordinates. This is needed because BirdNET uses location + date to filter its species list for regionally plausible species.
If GPS is unavailable:
- A yellow "GPS Location Required" prompt appears
- Retry GPS: attempt auto-acquisition again
- Open Settings: enter latitude/longitude manually
4. Record
Once GPS is set, the app connects to the hub via MQTT (WebSocket over TLS). The app starts in a paused state -- tap the recording status bar to begin capturing 3-second audio chunks. Audio is filtered on-device using adaptive noise floor + spectral peak SNR detection, with filter settings received from the hub.
Recording Screen
The recording screen features a tap-to-record status bar -- the large recording rectangle is the toggle for starting and stopping capture. The app starts in a paused state by default.
| Stat | Description |
|---|---|
| Chunks Sent | Audio chunks uploaded to hub |
| Filtered | Chunks rejected by adaptive filter |
| Last Sent | Time since last successful upload |
| Hub | Connection status (Connected / Connecting / Offline) |
| GPS | Fix status (Fixed / Acquiring / Not set) |
| Name | Satellite display name |
Settings Page
Settings is a full page (not a popup), accessible from the recording screen.
Satellite Name
Editable field that syncs to the hub. Visible on the Satellites page in the web UI.
Location
Clear toggle between GPS and manual location modes:
| Control | Description |
|---|---|
| GPS / Manual toggle | Switch between automatic GPS and manual coordinate entry |
| Latitude / Longitude | Manual coordinate entry (when in manual mode) |
| Use GPS | Acquire position from device GPS |
| Save | Apply manually entered coordinates |
| Auto-update GPS | Toggle periodic GPS updates (on by default) |
| Interval | Update frequency: 30s, 1min, 2min, 5min, 10min |
::: tip Battery Savings For a stationary phone, turn off GPS auto-update and set coordinates manually. GPS polling is the largest battery drain after screen-on. :::
Keep Screen On
Toggle to prevent the phone from locking. Uses the Capacitor keep-awake plugin.
Verbose Chunk Logging
Toggle to enable detailed per-chunk log entries for diagnostics (filter decisions, RMS values, SNR).
Recording Profile
Read-only display of the hub-assigned profile, with resolved sunrise/sunset times and active recording windows. Profiles are changed from the hub (Satellites page), not in-app.
Audio Filter Settings
All filter settings are received from the hub via MQTT and applied locally. The filter uses adaptive noise floor + spectral peak SNR detection. Settings displayed as read-only (configured in hub tenant settings).
Satellite Info
- Satellite ID -- UUID (read-only)
- Hub -- hub URL (read-only)
Unregister
Type UNREGISTER to confirm. This:
- Stops recording
- Disconnects from the hub
- Clears the saved configuration
- Does not delete the satellite record on the hub
To re-register: sign in again and register with the same name -- the device ID matching will reconnect to the existing satellite record.
Background Mode
The app uses the Capacitor background mode plugin to continue recording when minimized. A persistent notification shows "BirdNET Satellite -- Recording bird sounds..."
::: warning Battery Background recording with screen off is the most battery-efficient mode. Keep-screen-on with background mode will drain battery faster. :::
Heartbeat
The app sends a heartbeat at a configurable interval (default 30 seconds) via MQTT QoS 1. The interval is set from hub tenant settings. This keeps the satellite showing as "online" on the hub even when all audio chunks are filtered. The heartbeat reports the current state:
recording-- actively capturingpaused-- user pressed Pause
Telemetry
Reported every 60 seconds:
| Metric | Source |
|---|---|
| Battery level | Capacitor Device plugin |
| Storage free | navigator.storage.estimate() |
| GPS coordinates | Geolocation plugin (if auto-update is on) |
| Uptime | Elapsed time since app start |
CPU temperature is not available on mobile -- shown as "--" on the hub.
Log Viewer
Collapsible panel at the bottom of the recording screen. Captures:
- Audio capture events (chunk sent, filtered)
- MQTT connection changes
- GPS updates
- Errors and warnings
Logs are in-memory only (max 200 entries). Use "Copy All" to export, "Clear" to reset.
Troubleshooting
| Symptom | Solution |
|---|---|
| "Could not start audio source" | Another app is using the microphone. Close other audio apps. |
| "Microphone permission not granted" | Tap "Open Settings" and enable the microphone permission. |
| Satellite shows offline | Check hub connection status. Verify hub URL and credentials. |
| GPS unavailable | Enable location services. Try "Use GPS" in Settings. Some indoor locations have no GPS signal. |
| App not installed (update fails) | The APK was built with a different signing key. Uninstall first, then install the new APK. |
| Duplicate satellites | The device ID is preserved across reinstalls. If duplicates appear, delete the extra from the hub's Satellites page. |