Telemetry

A ShellHub server sends a few usage counts to telemetry.shellhub.io. We use them to learn how many instances run, which versions and editions they run, and how large they get. Telemetry is on by default, and one setting turns it off.

What is sent

Every edition sends two events, and ShellHub Cloud sends a third. All of them are identified by a random instance ID that the database generates once. Nothing in them names a person, a namespace, a device or a host.

instance started, each time the server starts:

Property Example Meaning
edition community community, enterprise or cloud
version v0.27.0 The server’s SHELLHUB_VERSION
os linux Operating system the server runs on
arch amd64 CPU architecture
database postgres Database type

instance heartbeat, once a day at 05:30 UTC, with the properties above plus:

Property Meaning
namespaces Namespaces on the instance
users User accounts on the instance
devices_accepted Accepted devices
devices_pending Devices waiting for acceptance
devices_rejected Rejected devices
sessions Sessions started in the last 24 hours
sessions_interactive Of those, sessions that opened a shell with a terminal
sessions_shell_without_pty Sessions that opened a shell without a terminal, as a heredoc does
sessions_exec Sessions that ran a command other than scp
sessions_scp Sessions that ran scp as a command. An scp that speaks SFTP counts as SFTP
sessions_sftp Sessions that opened the SFTP subsystem
sessions_port_forwarding Sessions that forwarded a port to the device
sessions_agent_forwarding Sessions that forwarded the SSH agent
sessions_web Sessions opened from the console’s web terminal
sessions_recorded Sessions that were recorded
sessions_api_key Sessions opened with an API key
sessions_unauthenticated Sessions that never got past authentication
sessions_active Sessions open now, whenever they started
sessions_devices Distinct devices the authenticated sessions reached
sessions_events Events the sessions recorded, such as a shell, a command or a port forward
sessions_duration_seconds Total time the authenticated sessions lasted, in seconds
sessions_duration_median_seconds Median time an authenticated session lasted, in seconds
sessions_duration_p95_seconds Time 95% of the authenticated sessions lasted at most, in seconds
namespaces_legacy Namespaces still on public keys and firewall rules rather than SSH identities and access policies
namespaces_personal Personal namespaces
namespaces_team Team namespaces
namespaces_recording Namespaces that record sessions
namespaces_require_verified_device_key Namespaces that require a verified device key
devices_online Accepted devices online now
devices_ephemeral Accepted ephemeral devices
devices_owned Accepted devices with an owner
devices_custom_fields Accepted devices with custom fields
devices_tagged Accepted devices with at least one tag
devices_key_verified Accepted devices whose key is verified
devices_platforms Accepted devices by agent platform: docker, bundle, native or connector, such as {"docker": 7, "native": 3}
devices_versions Accepted devices by agent release, cut to major and minor, such as v0.27
devices_architectures Accepted devices by CPU architecture, as Go names it, such as amd64
devices_oses Accepted devices by operating system ID, such as ubuntu, from a fixed list of distributions
devices_enrolled_with Accepted devices by the kind of key they enrolled with: user, legacy or pairing
access_policies Access policies
public_keys Public keys
api_keys Namespace API keys
instance_api_keys Instance API keys
tags Tags
ssh_identities SSH identities by source: manual, browser or approval
provisioning_keys User provisioning keys not revoked, by mode
enrollments Enrollment attempts with a provisioning key in the last 24 hours
pending_invitations Namespace invitations not yet answered
authentication_local Whether login with a password is on
authentication_saml Whether SAML login is on
users_active Users who logged in during the last 24 hours
users_by_origin Users by where their account comes from: local or saml

A session that did several things counts under each of them, and one still open counts its time up to the last moment the server saw it. In the counts by value, a device that reported no value counts as unknown, and one that reported a value outside the known set counts as other, so a custom operating system ID or build version never leaves the instance.

Enterprise and ShellHub Cloud add:

Property Meaning
firewall_rules Firewall rules
users_mfa Users with multi-factor authentication on
web_endpoints Web endpoints
web_endpoints_created Web endpoints created or renewed in the last 24 hours
web_endpoints_tls Web endpoints that reach the device over TLS

namespace heartbeat, ShellHub Cloud only, one per namespace with each instance heartbeat:

Property Meaning
$groups {"namespace": "<hash>"}: an HMAC-SHA256 of the namespace’s tenant ID under a key the collector does not hold, so it cannot recover the tenant ID
members Members of the namespace
devices_accepted Accepted devices
devices_pending Devices waiting for acceptance
devices_rejected Rejected devices
sessions Sessions started in the last 24 hours

Every event also carries schema_version, which changes when a property changes meaning. The server sends events in PostHog’s capture v1 format, asks the collector to create no person profile, and the PostHog client adds an event ID, a timestamp and these properties:

Property Example Meaning
$os Linux Operating system the server runs on
$os_version 3.24.0 Its version, when the host reports one
$os_distro alpine Its distribution, when the host reports one. In the official image this is the container’s distribution, not the host’s
$go_version go1.26.9 Go version the server was built with
$is_server true Marks the event as sent by a server
$geoip_disable true Asks the collector not to look up a location

What is not sent

No IP addresses, hostnames, domains, email addresses, usernames, namespace names, device names, session contents or command lines. The collector drops the address the request came from before it stores anything.

How long it is kept

The collector keeps each event for 365 days. After that only monthly totals remain, with no instance ID. Cloud and Enterprise customers can have an instance’s events deleted sooner through their support channel.

The instance ID, the distinct_id in the payload preview, lets whoever holds it send events as your instance. The server shows it nowhere else. Do not post it in a public issue.

Seeing the exact payload

The Admin Console on Enterprise and Cloud shows the events the next heartbeat will send, under Settings > Telemetry.

Turning it off

On any edition, set SHELLHUB_TELEMETRY=false in .env.override and restart:

# .env.override
SHELLHUB_TELEMETRY=false
$ make restart

The server then opens no connection to the collector. The startup log says which way it is set:

level=info msg="telemetry is off: SHELLHUB_TELEMETRY is false"

On Enterprise and Cloud, an administrator can also turn it off in the Admin Console under Settings > Telemetry, without a restart. The change applies to the next event. When SHELLHUB_TELEMETRY=false is set, or the server could not set up telemetry, the console shows the switch as disabled by the environment and the server log says why.

Turning telemetry off changes nothing else. The server sends no final event when you do.

esc