Ping graphs that redraw as fast as the replies come back.
Releases · Privacy · License
Not yet published to the App Store or Google Play.
Type a host. 1.1.1.1, google.com, your router, a game server. Pingy sends real
ICMP packets and paints each reply as a bar in a rolling graph. A bar that is still
waiting shifts color as the probe gets older, locks to its final shade when the reply
lands, and disappears the moment the probe times out.
- Many hosts at once: one panel per host, as many as you want side by side.
- Live sliders: packet size (16 to 480 bytes), time window (1 to 30 s), graph ceiling, graph height, zoom curve. Every change applies to the very next probe. Nothing restarts.
- Adaptive cadence: the next probe leaves as soon as the previous reply arrives, or when it times out at 3 s. A 10 ms floor stops a sub-millisecond LAN target from being hit a thousand times a second. Faster links give you more samples per second.
- Rolling stats: average, jitter, loss, dead-time share, and the low-to-high range, all on screen at once. Attempts that never left your device (no DNS answer, no route, no socket) are reported on their own and never counted as packet loss.
- Domain or IP: a name is resolved once per panel, not once per probe.
- Quick presets: Cloudflare, Google, Quad9, OpenDNS, your LAN gateway.
- No telemetry: no analytics, no crash reporter, no ads, no account.
| Target | Status |
|---|---|
| Android | 8.0 (API 26) and above |
| iOS | 16.0 and above |
| Desktop (JVM) | macOS and Linux. A Compose Desktop app builds and runs; packageDistributionForCurrentOS produces a DMG or DEB. Windows is out: Winsock has no unprivileged ICMP socket, so there is no MSI target. |
No telemetry, no analytics, no crash reporter, no ads, no account, no backend.
Pingy sends ICMP probes to the hosts you add, plus a DNS lookup when you type a name instead of a numeric address. It monitors nothing until you ask it to, and nothing leaves your device beyond those probes. Targets you mark as remembered are stored locally in app-private storage. Full details in PRIVACY_POLICY.md.
Android permissions are limited to INTERNET and ACCESS_NETWORK_STATE. No
credentials or keystore files are ever committed: local.properties, *.jks, and
the keystore/ directory are all .gitignored.
Requirements
- Android Studio 2025.3.1+ (Kotlin 2.4, Gradle 9.4)
- JDK 21 (the Gradle toolchain fetches it for you)
- Xcode 16.3+ for iOS (Compose Multiplatform 1.11 needs an SDK that provides
UIUtilities; Xcode 16.4 does not) - CMake 3.22.1+ (the NDK manages it on Android)
Android
./gradlew :androidApp:assembleDebug
Release signing reads three keys from local.properties, which is .gitignored:
keystore.keyAlias, keystore.keyPassword, keystore.storePassword. Unsigned
debug builds need no keystore at all.
iOS
open iosApp/iosApp.xcodeproj
No CocoaPods step. A Gradle build phase inside the Xcode project builds and embeds the Kotlin framework, so opening the project and pressing Run is enough.
./gradlew :shared:jvmTest :shared:iosSimulatorArm64Test
The engine suite runs against real loopback sockets on both the JVM and Kotlin/Native, because a socket bug that shows up on one runtime can be completely invisible on the other.
Open an issue or start a discussion.
Licensed under AGPL-3.0
