Applies to Somewhere for Android, package
eu.nodepass.somewhere. Last reviewed 2026-10-24, against the source at that date.
This app sends nothing to its authors. There is no analytics, no crash
reporting and no telemetry of any kind — not disabled by default, not
opt-out: absent. The dependency list in
gradle/libs.versions.toml contains no
analytics or reporting library, and a reader can check that in one pass, which
is the point of saying it this way rather than promising it.
Everything the app stores stays on the device. What it sends goes to a server you configured, or — for one request, to find out whether a newer version exists — to GitHub, where this project publishes its releases. Every address the app itself contacts is listed below, with what it sends. None of them receives anything that identifies you, this device or this installation.
The rule this document holds the app to is simple: it does not collect anything about you, and it does not send anything anywhere you could not read about here first.
All of it in the app's private storage, which no other app can read, and all of it removed when the app is uninstalled.
| What | Why | Where |
|---|---|---|
| Nodes, including their shared keys | A node is unusable without its key | NodeStore |
| Which node you chose, or that you left it automatic | So Home, the tile and shortcuts connect to it | NodeRepository |
| Your subscription URLs, their titles, and the quota, expiry and fetch time each last reported | To refresh the node list and show what the dashboard said | SubscriptionStore |
| Routing rules you imported | To decide what goes through the tunnel | RuleStore |
| Which applications the tunnel carries | Applied when the tunnel is built | AppSelectionStore |
| How the tunnel is built: excluded ranges, MTU, DNS servers you named | Applied when the tunnel is built | NetworkSettingsStore |
| Settings | Preferences | RoutingPreferences, AppSettingsStore, RefreshPreferences |
| A count of automatic connects that did not survive | So a crash on connect cannot lock you out | LaunchGuard |
A shared key and a subscription URL are credentials. They are stored in plain text in private storage, which is the same protection the platform gives every app's own files. On a rooted device, or one with an unlocked bootloader, that protection is weaker than it sounds — this is stated because it is true, not because it is unusual.
To the Portal you configured. Your tunnelled traffic, plus a 16-byte authentication frame per connection, and over TLS with Morph on a 64-byte prelude whose last bytes carry a random number this app chose and a counter, so that the Portal can refuse a recorded connection played back to it. The number is new each time the app starts and means nothing outside that Portal. The Portal necessarily sees the addresses and names you connect to — that is what a tunnel is. What it does with them is its operator's policy, not this app's, and this app has no way to constrain it.
To the subscription URL you entered, when you add or refresh a
subscription. An ordinary HTTPS GET, carrying three query parameters that
describe this client so a dashboard can generate a node list it can actually
use:
type— that this is a Somewhere clientver— the client versioncaps— which protocol features this build supports
No identifier of you, your device or your installation is sent. There is none to send: this app generates no installation id.
To the addresses you connect to, for traffic your routing rules send direct rather than through the tunnel, and for ranges you keep out of the tunnel in Network settings. That traffic does not reach the Portal at all, which is the point, and it is not otherwise treated differently.
To a DNS server you named, if you named one in Network settings, for the queries the tunnel does not answer itself (PTR, SRV, TXT and the like). They travel through the Portal to it. Without one, they go to the resolver your network gave the device, as before.
To a file you choose, if you export a backup. The app writes it only through the system's file picker, to the place you pick. The file is not encrypted and holds everything in the table above except the crash count: every node's key, every subscription URL, your rules, settings and per-app list. The app says so before it writes one. On Android 9 and older, shared folders such as Downloads can be read by other apps.
To GitHub, to check for a newer version. Once a day when the app is opened, while Settings → About → Check automatically is on (it is on by default, and one tap turns it off), and whenever you tap Check for updates:
GET https://api.github.com/repos/NodePassProject/Somewhere-Android/releases/latest
User-Agent: Somewhere/<this version>
Accept: application/vnd.github+json
Nothing else is in the request: no identifier, no list of anything, no
statistics. GitHub sees the request and the address it came from, as it does
for anyone who opens a GitHub page; what GitHub does with that is its own
policy. If a newer release exists, Download opens its page on
github.com in your browser. The app never downloads or installs anything by
itself.
The request goes over your ordinary network connection, not through the tunnel: the app's own traffic is always kept out of its own tunnel.
That is the whole list. The app does not look up your outbound IP address, does not test which services are reachable, and contacts no address that is not named in this section. A new kind of request is added to this list in the same change that adds it to the app.
Named individually, because for an app of this kind the absences are the part worth reading:
- no advertising identifier, and no advertising
- no installation id, device id, IMEI, MAC address or serial number
- no location, coarse or fine
- no contacts, calendar or files
- the camera is used only while the QR scanner is open, and frames are read on the device and discarded; a picture you choose to scan is read the same way
- the clipboard is read only when you tap something that pastes (a link, an app list), and written only when you tap something that copies (a node link, an app list); a copied node link is marked sensitive so the system's clipboard preview does not show it
- no list of installed applications leaves the device — the per-app screen reads one to draw itself and it is never transmitted. The packages you chose leave only if you copy them or export a backup
- no browsing history on disk. The Activity screen shows what the tunnel is doing — see below — from memory only, and nothing of it is written to storage or sent anywhere unless you export it
- no crash reports, no usage statistics, no "improve the product" data
The Activity tab shows three things, all held in memory and never written to storage:
- Connections: what the tunnel is carrying now — destination as host and port, the app that opened it (asked of Android, which answers only the active VPN app), whether it went through the Portal or direct, and its byte counts. Each disappears when its connection closes, and all of them when the tunnel stops.
- DNS: the names the device looked up while the tunnel was up, with the record type and what became of the query. At most 300, and cleared when a new session starts.
- Portal answers: what the Portal answered for recent flows — the result, the time, a destination as host and port, a flow id, the carrier, and how long the answer took. At most 200, gone when the app's process ends.
Together these are a record of where the device went while you watched. That is what makes them useful for diagnosis, and it is why they stay in memory and why Export, which turns them into text you can share, says what it contains before it runs.
They are built so that a credential cannot appear in them. No field can hold a shared key, a subscription URL or a token — there is no room for one — and a test asserts the Portal log's field list so an entry that grew one fails rather than shipping. Destinations and names are reduced to the characters a host name can have before they are stored. This matters because people paste logs into public issue trackers, and helpfulness is how credentials get published.
| Permission | Why |
|---|---|
INTERNET |
To reach the Portal, the subscription URL and, for the update check, GitHub |
ACCESS_NETWORK_STATE |
To notice when the network changes under a live tunnel |
BIND_VPN_SERVICE |
To establish the tunnel. Android shows its own consent dialog and the tunnel cannot start without it |
FOREGROUND_SERVICE, FOREGROUND_SERVICE_SPECIAL_USE |
A tunnel must survive the app being backgrounded, which is the normal case: nobody watches a VPN |
POST_NOTIFICATIONS |
To show the ongoing notification that says a tunnel is running, with its rates and a Disconnect button. Without it the tunnel runs with nothing on screen saying so; it is asked for once a tunnel is up |
CAMERA |
To scan a node's QR code. Asked for when the scanner opens, not at install; refusing it leaves scanning a picture |
RECEIVE_BOOT_COMPLETED |
So a scheduled subscription refresh survives a reboot. Nothing starts at boot; Android's always-on VPN does that |
Other apps can start or stop the tunnel only if you turn on Allow other apps to connect and disconnect in Settings. It is off by default: when on, any installed app can turn the tunnel off without asking you, and the switch says so.
The app declares a <queries> entry for applications with a launcher icon so
the per-app screen can list them. It does not request
QUERY_ALL_PACKAGES, and the screen says its list is partial rather than
pretending otherwise.
This app is not directed at children and collects nothing from anyone.
This document lives in the repository and changes with it. Its history is the
change log: git log docs/privacy.md.
Security reports: see SECURITY.md. Anything else: the issue
tracker of this repository.