Voidly
Voidly Probes

Voidly Probes / Setup

One network.
Your vantage point.

Choose a client. Know what it shares.

Find your setup ↘

Volunteer contribution. No payment promise.

Two ways inDifferent credentials.
The same purpose.
01Run the clientPython or Docker
community registration → node token → observations
02Bring your own clientPrepare an ingest-key request
API registration → ingest key → observations

Registration creates an identity. Installation, consent and successful measurements are separate steps.

01 / Run a client

Install. Then choose to run.

The commands below are instructions. This preview does not run them.

PY

Python

Community-node identity. Stored on your machine.

Read the client source ↗

Installs the package. It does not consent to measurements.

First run registers at /v1/community/register, saves a node token, and starts outbound measurements. Review data sharing before running.

Alternative launch & ongoing operation
voidly-probe
voidly-probe --once
voidly-probe --status
voidly-probe --interval 600
nohup voidly-probe --consent &

With an existing identity, voidly-probe runs continuously. --once runs one measurement cycle; --status reads the node record; --interval 600 changes the cycle interval. The nohup command continues in the background.

The checked-in client defaults to 900 seconds between cycles. The ingest-registration protocol expects 300 seconds; these are different configurations, not a synchronized fleet setting.

◫

Docker

Same community client. Persistent identity volume.

Read the Dockerfile ↗

Starts immediately with --consent. This command both registers and runs the client; it is not an installation-only step.

Logs, status & container configuration
docker logs -f voidly-probe
docker exec voidly-probe voidly-probe --status
docker stop voidly-probe

Configuration: VOIDLY_CONFIG_DIR=/data/.voidly; identity: /data/.voidly/node.json. The named voidly-data volume preserves it across container restarts.

The Dockerfile health check only checks whether node.json exists. It does not verify current measurements or reachability.

Desktop downloads & existing guide

The existing Probes page lists these packages. Their versions and platform labels come from the checked-in guide, not a release check performed by this preview.

Existing installation guide ↗
Python environment & identity file

These are defaults in the checked-in Python client. Running deployments may override them.

VOIDLY_PROBE_INTERVAL
900

Seconds between cycles; --interval enforces a 300-second minimum.

VOIDLY_PROBE_TIMEOUT
10

Seconds allowed for a request.

VOIDLY_BATCH_SIZE
20

Results per submission batch.

VOIDLY_CONFIG_DIR
~/.voidly

Private node.json identity file lives here.

VOIDLY_API_URL
https://api.voidly.ai

API base URL.

VOIDLY_COUNTRY
Not set

Optional manual country override; skips ipinfo.io lookup.

VOIDLY_CITY
Unknown with manual country

Optional city used with the manual country override.

The file ~/.voidly/node.json contains nodeId, nodeToken, country, city, registeredAt and version. Keep the token private. The client attempts file mode 0600; verify your own machine’s permissions.

VOIDLY_FLEET_KEY is for Voidly-operated machines, not volunteers. It does not grant volunteer benefits. Use Claim your node for the existing public-profile workflow.

Raspberry Pi / ARM: legacy client compatibility

The checked-in probe-lite client calls /v1/probe/community/register, which is absent from the current Worker routes. It can save a local ID even when registration fails. These original instructions are retained for reference; successful registration and ingestion are not established.

The README asks for Node.js 18 or later and offers this NodeSource 20 installation. Review the script and your system’s package policy before running administrative commands.

curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash -
sudo apt-get install -y nodejs
node --version

The README also lists sudo apt install nodejs npm as a package-manager alternative; check the resulting Node version.

git clone https://github.com/voidly-ai/probe-lite.git
cd probe-lite
node probe.mjs --register --country US

This starts a measurement cycle immediately, then repeats every 300 seconds by default. Options are --register, --country US (default XX), and --interval 300. The local credential file is .probe-config.json. A subsequent node probe.mjs reuses it. Changing country by removing that file and registering again does not repair the endpoint mismatch.

Original systemd service & commands

Edit voidly-probe.service to match your own user, working directory and writable path before installing it. Enabling and starting the service runs measurements automatically.

[Unit]
Description=Voidly Probe Lite — Censorship Monitoring
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
# Change these to match your setup:
User=pi
WorkingDirectory=/home/pi/probe-lite
ExecStart=/usr/bin/node probe.mjs --interval 300
Restart=always
RestartSec=30
StandardOutput=journal
StandardError=journal

# Security hardening
NoNewPrivileges=yes
ProtectSystem=strict
ReadWritePaths=/home/pi/probe-lite

[Install]
WantedBy=multi-user.target
sudo cp voidly-probe.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable voidly-probe
sudo systemctl start voidly-probe
sudo systemctl status voidly-probe
journalctl -u voidly-probe -f

Stop with sudo systemctl stop voidly-probe. Disable automatic startup with sudo systemctl disable voidly-probe.

Read the legacy source ↗

02 / Bring your own client

Build the request.

Prepare an ingest-key registration. No request leaves this form.

Preview only. Nothing is sent and no key is issued.

Your request

POST/v1/probe/register

Fill in the fields to see the exact request.

This endpoint is for your own client integration. Python and Docker obtain a separate community-node token.

Response, one-time key & result submissions

A new registration returns node_id, a one-time ingest_key, header X-Probe-Ingest-Key, status, trial end, rate limit, heartbeat interval, promotion threshold and accepted domains. Use values from your actual response; no key or success result is simulated here.

An existing ID returns already_registered: true with its status and registration date, but no replacement key. If the original key is lost, choose a new public ID. A failed or interrupted response does not prove no registration was created; do not retry automatically.

The optional domains_supported registration field is informational. The handler returns its approved-domain set; actual ingest can also use the served domain registry. Off-list results may be dropped. Inspect current targets ↗

Only submit observations your client actually made. Create measurements.json with the nodeId, country and results array; each result carries the observed domain, blocking result, confidence and latency. The original guide’s made-up result is not used as a submission template here.

curl -X POST https://api.voidly.ai/v1/probe/results \
  -H 'Content-Type: application/json' \
  -H "X-Probe-Ingest-Key: $PROBE_INGEST_KEY" \
  --data-binary @measurements.json

PROBE_INGEST_KEY in this example is a local shell variable you supply privately. It is not a Python-client configuration variable. Do not paste keys into public records. Registration alone does not produce a community-node profile; its public identity appears in the heartbeat registry.

Full protocol and example payload ↗

03 / Ingest-registration policy

Earn trust through evidence.

Checked-in quality formula Configuration, not your node’s score
70%successful submissions30%freshness

No submitted data means quality zero. Freshness stays at 1 within an hour, then declines to zero by 24 hours.

Trial → FullQuality ≥ 0.9 and registration age ≥ 7 days.
Full → SuspendedQuality below 0.5 or silence above 24 hours.
Trial → SuspendedSilence above 24 hours.
Suspended → DeactivatedSilence above 14 days.
Rate limits, heartbeat & policy limitations

The checked-in limits are 100 submissions/minute for trial and 600 for full. A tier excess can return HTTP 429 with Retry-After: 60 and increase the failed-probe counter. Registration requests have a separate per-IP rate limit.

The protocol expects a submission every 300 seconds. The heartbeat endpoint labels gaps above twice that interval as silent. “Silent” is distinct from suspension, and neither is proof that a whole country is offline.

Quality uses cumulative counters and registration age in the current handler; it does not prove seven complete days of observations or peer consensus. The quality-history consensus field is null. The checked-in evaluator has no automatic suspended-to-full recovery branch; the older protocol’s recovery wording is not a guarantee.

The protocol describes automated recovery of Voidly-owned core machines and notifications for community nodes. This does not grant access to your machine or demonstrate that every notification/recovery ran. Operational gates ↗

Protocol v1 describes a path-versioning policy with at least 90 days after a future v2 general release. This is a stated policy, not an announced v2 schedule.

04 / Before you contribute

Know what leaves your machine.

Public observations.

Domains, results, latency, blocking methods, location and timestamps can enter the public dataset. A machine’s network is one vantage point, not a country-wide sample.

The client sends outbound DNS, TLS and HTTP checks to a served target list. It is not a relay, VPN or browsing-history collector. Targets can change remotely without a client update.

Visible network activity.

Your ISP and tested services can observe the checks. The probe identifies itself; a location plus measurement timeline may identify a node. Running it does not provide anonymity.

The service describes hashed-IP deduplication rather than plaintext-IP retention. The Python client’s default registration lookup contacts ipinfo.io, which receives the request IP. A manual country/city override skips that lookup.

Stop, identity, attribution & compensation

Stop the running process with Ctrl+C, or stop its container/service. After stopping any other running instances, voidly-probe --unregister deletes the local identity file; it does not revoke a remote token or erase past public observations. Submitted records and downstream copies can remain.

Choose a public node ID without personal data, session tokens, email or internal host names. Ingest keys are stored as SHA-256 hashes by the registration service. Community tokens and ingest keys are different secrets; neither belongs in a public profile.

The original guide’s August 23, 2026 compensation note reported no paid operators, no funded treasury, and withheld DID-binding/accrual routes returning HTTP 410. Those payment endpoints were not rechecked by this preview. There is no payment promise here.

The described accrual is a theoretical, scarcity-weighted record after DID binding, not credit issuance or a payment ledger. Voidly-owned hardware is excluded. The named /v1/probe/link-did and /v1/probe/payouts/status remain documentation references, not offered actions.

Voidly aggregates observations with OONI, Censored Planet and IODA. This does not mean every observation was independently verified by each source. Original Voidly data uses CC BY 4.0; source-specific terms also apply.