# Anonymous usage statistics

> Exactly what CorePanel's daily check-in reports, what it never reports, and how to turn it off from the panel, the command line or your provisioning.

Source: https://www.corepanel.net/docs/telemetry/
Last updated: 2026-09-04
Part of the CorePanel documentation — https://www.corepanel.net/docs

---

Once a day, a CorePanel server reports that it exists. It sends a random installation
id, what it is running on, and round numbers about how much it hosts. That is the whole
feature.

It is **on by default**, and this page exists so that you can decide whether to leave it
that way with the full list in front of you rather than a paragraph of reassurance.

## Why we ask for it

We do not know how many CorePanel servers there are. Downloads do not answer it — a
download is not an install, an install is not a server that is still running next month,
and neither says anything about the OS it landed on.

Concretely, the questions this answers and nothing else does:

- Which RHEL versions are actually in use, so we know when dropping one stops hurting.
- Whether servers stay alive after the first week, which is the only honest measure of
  whether the product works.
- Which features are switched on, so effort goes where people are, not where we guess.
- Which CorePanel version the fleet is on, so a security fix can be judged on how much of
  the fleet has actually taken it.

None of that needs to know who you are, and none of it does.

## Exactly what is sent

One `POST` a day, to `licenses.corepanel.net`:

```json
{
  "install_id": "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
  "panel_version": "0.6.0",
  "edition": "personal",
  "os_id": "almalinux",
  "os_version": "9.5",
  "arch": "amd64",
  "installed_days": 42,
  "counts": {
    "accounts": 3,
    "domains": 7,
    "mailboxes": 12,
    "databases": 4,
    "apps": 1,
    "wp_sites": 2
  },
  "features": ["firewall_autoblock", "managed_dns"]
}
```

Field by field:

| Field | What it is |
|---|---|
| `install_id` | A random UUID generated once, when CorePanel was installed. It is not derived from your IP, your hostname or your hardware, and it is the same id you can read in the panel |
| `panel_version`, `edition` | Which CorePanel is running, and whether it is Personal, Pro or Business |
| `os_id`, `os_version`, `arch` | `almalinux` / `9.5` / `amd64` — read from `/etc/os-release` |
| `installed_days` | How long ago CorePanel was installed on this machine |
| `counts` | How many accounts, domains, mailboxes, databases, applications and WordPress sites exist. Numbers only |
| `features` | Names of features that are switched on. A name and nothing else: `managed_dns` says nameservers are configured, and says nothing about which |

## What is never sent

- **No hostnames and no domain names.** Not your server's, not your customers'.
- **No email addresses, no account names, no usernames, no passwords.**
- **No website content, files, databases, or logs.**
- **Nothing typed into the panel.**

There is no field for any of it, and the receiving service has nowhere to put it.

**About your IP address.** The server that receives the check-in sees the public IP it
arrives from, exactly as every website you visit sees yours — that is how HTTP works, not
a choice CorePanel makes. We resolve it to a country and keep the address on the
installation's row. Your panel does not report an address of its own, and the check-in
carries no field for one.

## Turning it off

**In the panel:** go to **Server → Settings** and switch off *Anonymous usage statistics*.

**From the command line:**

```bash
corepanel telemetry disable
corepanel telemetry status     # confirm
```

**For a fleet, before it is ever installed:** set `COREPANEL_NO_TELEMETRY=1` in the
environment of the `corepanel-core` service. That wins over the panel setting and needs no
database write, so a golden image can decide it once for every machine cloned from it.

```bash
sudo systemctl edit corepanel-core
# [Service]
# Environment=COREPANEL_NO_TELEMETRY=1
sudo systemctl restart corepanel-core
```

Turning it off stops future check-ins from the next slot onwards. **It does not delete
what was already reported** — your server has no way to reach into our records and remove
rows, and we would rather say that than imply an erasure that does not happen. If you want
what was collected under your installation id removed, write to
[info@corepanel.net](mailto:info@corepanel.net) with the id from **Server → Settings**.

Nothing about your server changes when it is off. No feature is withheld, no warning is
shown, and the setting is never asked about again.

## When it runs

Once a day, at a fixed minute derived from your installation id. Servers are spread across
the 24 hours on purpose so that the whole fleet does not arrive at once — which also means
your check-in time is stable, not random, and the same across restarts.

It also runs once about 15 minutes after the panel starts. That is there so a server which
is not powered on around the clock still appears — with only a daily slot, a machine that
is off overnight and drew a 03:00 slot would never report at all.

Neither can double-count. A day that is reported twice is still one row: the receiving end
keys on (installation, day), so a reboot loop refreshes a row instead of accumulating
them.

A check-in that fails is dropped. There is no retry and no queue of missed days: a day
your server could not reach us is a day it does not appear in our count, which is the
correct outcome — your panel has better things to do than deliver our statistics.

## The migration tool's report

`corepanel-transform` — the tool that checks a cPanel server and converts it into a
CorePanel one — reports under the same rules, and to the same place. It is a separate
thing from the daily check-in above: it runs on a **cPanel** server, which is not a
CorePanel installation and may never become one, and its events are never counted as
panels.

It reports because of what is invisible otherwise. A CorePanel server that exists sends
the daily check-in above, so we know about it. A cPanel server that was checked and found
to carry a blocker, a transformation that failed halfway, a server that was transformed
and given back to cPanel an hour later — none of those ever become an installation, and
without this they leave no trace at all. Those are the cases worth learning from.

### When it reports

- **After a check** (`corepanel-transform check`, or the `curl | sh` one-liner): once,
  with the inventory and the verdict.
- **After each stage of a transformation** (PREPARE, CUTOVER, VERIFY, CLEANUP): what the
  stage did, what it cost, and which step stopped it if one did.
- **After a rollback**: that the server went back to cPanel.

A rehearsal (`--dry-run`) reports too, marked as one, and writes nothing to the server.

### Exactly what is sent

```json
{
  "machine_id": "b41f9c2e-7d38-4a15-9f60-2c8ab3d5e174",
  "run_id": "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
  "install_id": "9c1d7b40-5e2a-4c83-b7f1-6d0e2a94c518",
  "tool_version": "1.0.4",
  "kind": "phase",
  "source": {
    "os_id": "almalinux",
    "os_version": "8.10",
    "panel_version": "11.136.0.35",
    "mysql_version": "10.11.19-MariaDB",
    "php_versions": ["7.4", "8.1"],
    "dns_backend": "powerdns",
    "mail_server": "exim",
    "ftp_server": "pure-ftpd"
  },
  "counts": { "accounts": 45, "domains": 61, "mailboxes": 88, "databases": 52 },
  "phase": "cutover",
  "outcome": "done",
  "duration_ms": 616000,
  "offline_ms": 28000
}
```

| Field | What it is |
|---|---|
| `machine_id` | A one-way hash of this server's `/etc/machine-id`. It is not the machine id, cannot be turned back into it, and names nothing — it exists only so that a check in March and the transformation it leads to in April count as one server rather than two |
| `run_id` | A random id for one transformation, so the stages of a run that takes four sittings across a week are one run |
| `install_id` | Once CorePanel is installed, the id it reports under above — the join between "a cPanel server was transformed" and the installation counted from then on. Absent before PREPARE, and **absent entirely if telemetry is switched off in the new panel** |
| `tool_version`, `kind` | Which build reported, and whether this is a check, a stage or a rollback |
| `source` | The versions found on the **cPanel** server: OS, cPanel, MySQL/MariaDB, the PHP versions installed, and the names of the DNS, mail and FTP daemons |
| `counts` | How much that server holds. Numbers only |
| `score`, `finding_codes` | On a check: the score out of 100 and the stable codes of what was found (`os.unsupported`, `php.unsupported`). The **code**, never the message a finding prints — a message names the domain or the account it is about |
| `phase`, `outcome` | Which stage, and whether it finished, failed, or was declined at the prompt |
| `failed_step`, `failure` | The plan id of the step that stopped a run (`cutover.web`), and why from a fixed list (`edition_too_small`, `not_implemented`, `other`) |
| `duration_ms`, `offline_ms` | How long the stage took, and the part of it your sites were actually down for. This is the number that turns our estimate of the offline window into a measurement |
| `dry_run`, `forced` | Whether this was a rehearsal, and whether a rollback was forced |

### What is never sent

The same list as above, and for the same reason — **there is no field for any of it**:

- No hostnames and no domain names.
- No account names, email addresses, usernames or passwords.
- **No error messages.** A step's error text can quote a path, a domain or a database, so
  what travels is the step's id and nothing else. It means we cannot see *why* a step
  failed, only which one — that is the trade, and it is deliberate.
- Nothing from `report.json`. That file stays on your server; it is the one that carries
  domain names, and it is never uploaded.

### Turning it off

`--no-telemetry` on any command, or `COREPANEL_NO_TELEMETRY=1` in the environment:

```bash
curl -fsSL https://get.corepanel.net/check | sh -s -- --no-telemetry
corepanel-transform --no-telemetry
COREPANEL_NO_TELEMETRY=1 corepanel-transform run --phase cutover
```

The tool says which happened. A check that reported says so in its last lines; a
transformation says it once, before the first stage, and not again.

Two more things it does rather than says. An event it cannot deliver — no route out, our
endpoint down — waits in the run's state directory and goes out with the next command,
and is deleted with everything else when the transformation is cleaned up; a check that
cannot deliver simply drops it, because a check writes nothing to your server at all. And
once CorePanel is installed, if you switch telemetry off in the new panel, the tool stops
sending its `install_id` — a "no" in the panel is a no here too.

## The installer's failure report

The installer checks, before it tells you it is done, that the services it just installed
are actually running. If the panel came up broken it says so, exits non-zero, and sends us
a report of what failed.

This is the one place on this page where **error text leaves your server**, and it is the
opposite of the rule the rest of this page describes. It is worth saying why. A CorePanel
server that works reports itself daily; a server whose panel died during installation
never reports at all, so it is invisible here and indistinguishable from a machine nobody
ever switched on. Measured over the five weeks to September 2026: of 14 installs that ran
to the end, **4 had a dead panel and none of them told anyone**. The people who hit it
reinstalled, moved to another provider, tried again, and left.

Nothing is sent when an install goes well: a clean install pings the endpoint exactly as
it always has, and the endpoint sees only your IP.

### Exactly what is sent

```
corepanel-install-report/1
result=failed
when=2026-09-04T08:54:41Z
os=almalinux 9.8
kernel=5.14.0-503.el9.x86_64

[server]
cpus=2
ram_mb=1966 available_mb=143 swap_mb=0
disk / total=40000M used=8200M free=31800M

[units]
corepanel-sys          active     restarts=0   result=success
corepanel-core         failed     restarts=5   result=oom-kill
corehttpd              active     restarts=0   result=success

[packages]
corepanel-core 1.6.3-1
corepanel-sys 1.6.4-1

[journal:corepanel-core]
2026-09-04T08:00:01+0000 core: dial /run/corepanel-sys.sock: no such file
2026-09-04T08:00:02+0000 systemd: start request repeated too quickly
```

| Part | What it is |
|---|---|
| `result` | `failed` if the panel is unusable, `degraded` if the panel works but a service behind it does not |
| `os`, `kernel` | The distribution and kernel, the same two facts the daily check-in sends |
| `[server]` | How big this machine is: cores, total and available memory, swap, and the size and free space of the filesystems the panel writes to. Sizes only — never the device names or the mount layout beyond `/`, `/home` and `/var`, and only for filesystems that are actually distinct |
| `[units]` | For each of our services: whether it is running, how many times systemd restarted it on its own, and systemd's verdict on why it last stopped. The restart count catches a service that is up only because it keeps being put back; the verdict is what tells `oom-kill` (the kernel took it, this server ran out of memory) apart from `start-limit-hit` (it failed so often that systemd stopped retrying) |
| `[packages]` | The versions of the CorePanel packages installed, so a failure can be tied to a release |
| `[journal:…]` | The last 50 journal lines of **the failing units only**, and only ours |

The whole report is capped at 16 KB.

The size of the server is in there because the installer has never looked at it. It will
fit MariaDB, PowerDNS, Dovecot, Rspamd, four PHP-FPM pools and the four CorePanel services
onto whatever it is pointed at, and says nothing about whether they fit. A service that
dies on one VPS and runs on the next is what running out of memory looks like from the
outside, and without these three numbers there is no way to tell that apart from a bug in
CorePanel.

### What is never sent

- **No journal but ours.** Only `corepanel-*` and `corehttpd` units, only the ones that
  failed. Never the system journal.
- **No configuration files**, of ours or of anything else.
- No account names, domains, mailboxes or database names — the report is produced before
  any of those exist.
- **No passwords.** The two the installer generates (`/root/.corepanel_password` and
  `/root/.mariadb_root_password`) are removed from the text by exact match before it is
  sent, so a log line that quotes one arrives as `[redacted]`.

What we cannot promise is that a journal line never quotes a path or a hostname of yours,
because a service's own error message is written by that service. That is the trade this
report makes and the reason it is only ever sent when something is broken.

### Turning it off

```bash
# Send the ping, keep the diagnostic on this machine
COREPANEL_NO_DIAGNOSTICS=1 bash install.sh

# Say nothing at all, as before
COREPANEL_NO_ACTIVATE=1 bash install.sh
```

Either way the installer still prints the failure, still tells you which units are down
and which command to look at, and still exits non-zero. Switching the report off keeps it
from us, never from you.

## A service that died of a bug

The installer's report above covers a server that never came up. This one covers a panel
service that dies on a server already running, and only in one case: **a panic**, which is
a bug in our code rather than a situation on your server.

When systemd stops retrying a failed service it runs a reporter, which always emails your
administrator (see [maintenance](https://www.corepanel.net/docs/maintenance#when-a-service-fails-or-the-server-runs-out-of-memory)).
That part is not telemetry and cannot be switched off — it is your server telling you. The
part that reaches us is separate, and narrower:

- **Only for a panic.** The reporter looks for one in the journal. A service killed for
  running out of memory, or that could not start because of something on the server, is
  your situation to act on and is never sent to us.
- **Only if telemetry is on.** The preference is read from the database, and a value that
  cannot be read counts as "no" — nothing is sent on an assumption.

What travels is the failing unit, systemd's verdict, how many times it restarted, your
installation id, the OS, the CorePanel package versions, and the last 100 journal lines of
**that unit only** — with the two passwords the installer generated removed by exact match.
Capped at 16 KB. No configuration, no account data, no other unit's journal.

The same caveat as the installer's report applies, and for the same reason: a panic's stack
names our own functions, but a log line around it is written by the service and can quote a
path or a hostname of yours. That is the trade, and it buys the one thing we cannot get any
other way — the actual bug, instead of a guess at it.

## What we do with it

Counts, on our side, and nothing else:

- how many servers checked in each day, and how that number moves;
- how those servers split by country, OS, CorePanel version and edition;
- how much is hosted on CorePanel in total.

From the migration tool: how many cPanel servers were checked, how many of those went on
to be transformed, where the ones that stopped stopped, and what the offline window really
is on a server that size. Those four numbers are the whole reason it reports.

We do not sell it, we do not share it with anyone, and we do not use it to contact you —
there is nothing in it to contact you with. It sits in the same database as the license
records because that service is already deployed and already public, not because the two
are connected: the check-in carries no license key, and a Personal server with no license
at all reports exactly like a Business one.

See also the [privacy policy](https://www.corepanel.net/privacy).
