Appflare

Anonymous report

What leaving the anonymous report on does, what Appflare sends and never sends, where it goes, and the ways to turn it off.

Appflare collects anonymous usage data to decide what to build and fix: the manager sends an anonymous report once a day, with an event for each job, and the installer sends one event when it ends. It is on by default and easy to turn off. The manager's first report goes out with its first scheduled run after setup finishes (or, on a manager updated from a version without the report, after the update). No banner in the manager announces it: this page, Settings > Anonymous report in the manager, and the installer's notice when it starts are where it is disclosed, and nothing waits for an answer. A development build never sends anything, and a pre-release of the manager (a version with a pre-release part, such as 0.4.0-rc.1) sends no report, so test managers stay out of the numbers. Settings > Anonymous report says so on either, and the Worker's log notes the skipped report once.

What it does for you

Every manager runs in someone's own Cloudflare account, where the maintainers cannot see it. The anonymous report is how they find out what happens there. Leaving it on lets them:

  • Keep the versions you run working. They see which versions of the manager are in use, so they know which ones to keep supporting and which upgrade paths to test an update against.
  • Fix what breaks, sooner. They learn which install paths, apps and steps fail, and how often, so the most common failures get fixed first and updates break less often.
  • Work on what matters. They see which features people use, such as passkeys, automatic updates or notification channels, so time goes where it helps most.

Turning it off changes nothing about how Appflare works for you.

The anonymous report is not the usage Appflare shows you. What each of your apps uses of Cloudflare, and what it costs, stays in your Appflare; the report only counts pausing and resuming an app as jobs, like the others below. See Usage and spend protection.

What is sent

Every event carries the Appflare version, whether it came from the manager or the installer, and the random id described below. Everything else is a count, a yes or no, a version, a duration, or a value from a fixed list, apart from the filtered Cloudflare error message a failed job can carry (below).

Daily report (manager)

Once a day, the manager sends one report with:

  • Manager: its database schema version, the Workers plan chosen in Settings > Your account (free, paid or unset), whether it uses Appflare's catalog or a custom one, how many catalogs were added in Settings > Catalogs (a count only, never their URLs or labels), days since setup, and whether a newer manager release exists.
  • Users: how many users and admins there are, whether passkeys are in use, and how many users have one.
  • Features: whether Cloudflare Access protection is on, whether the sandbox Worker is connected, whether Appflare and apps update automatically, and how many apps use the account setting for automatic updates or override it with on or off, and how many notification channels there are of each kind (Telegram, Slack, Discord, webhook), and how many GitHub access tokens there are (the count only: never a label, a repository or a token).
  • Apps: how many are installed, counted by status (installed, failed, installing, updating, uninstalling), by build type (prebuilt, sandbox, self-deploying), and by version age (current, or, when the catalog has a newer version, how long ago the running one was installed: under 7 days, 7 to 30, 30 to 90, over 90 days); how many have a custom domain, Email Routing, or cron triggers; how many install as several Workers; how many come from added catalogs; how many removed apps still keep data; and the catalog slugs of the installed apps, only for apps in Appflare's own catalog.

Jobs (manager)

For each install, update, settings change, rollback, database restore, uninstall, deletion of a removed app's kept data, build for review, pause, resume, manager self-update, and manager rollback, one event when it starts and one when it ends, with:

  • the kind of job, the app's catalog slug (custom for an app from a custom catalog or from a repository), the version it moves from and to (none for a custom catalog's app, an app from a repository, or an app built from source), the build type, where the app comes from (catalog, repository or source), how many Workers the app installs, and what started it (an admin, or the schedule for automatic updates and automatic pauses); a manager rollback carries its kind only, never the versions it moves between. Nothing about a repository is sent: not its address, owner, name, branch or commit;
  • when it ends: whether it succeeded, how long it took, and for a failure, its error category (such as cloudflare_permission, plan_limit, d1_migration or access_conflict), the phase it failed in (such as resources, upload, health or access), and, for a failed Cloudflare API request, the HTTP status and Cloudflare's numeric error code. When the failure is in the Cloudflare categories (cloudflare_permission, cloudflare_rate_limited, cloudflare_unavailable, cloudflare_rejected), it also carries an excerpt of Cloudflare's own error message (cf_message, at most 200 characters, such as incomplete input: SQLITE_ERROR). The excerpt starts after Cloudflare's error code, so it never holds the request's method or path. It ends at the closing bracket when Appflare put Cloudflare's message in brackets, and otherwise at the first semicolon that does not start another of Cloudflare's errors, or at a line break. Before it is sent, anything in quotes, anything shaped like a hostname and every IP address is replaced (Cloudflare's own hostnames, such as dash.cloudflare.com, and its error keys, such as access.api.error.conflict, are kept), and so is everything the failure report filter takes out: your account id, other ids, email addresses, anything that looks like a token or password, your workers.dev subdomain, and every hostname, Worker name and other name Appflare recorded. Then every other word of three characters or more with a hyphen, an underscore or a digit in it, such as acme-payroll-api, is replaced ([name]), except error constants in capitals such as SQLITE_ERROR, error codes in brackets, numbers of up to six digits (HTTP statuses, error codes and limits), versions and dates. A name made only of letters, such as Intranet Portal, cannot be told apart from Cloudflare's own words, so it stays in the excerpt unless Appflare recorded it. If Appflare cannot read the names it recorded when it reports, the excerpt is left out.

Setup and use (manager)

  • Once, after setup: how many minutes passed between connecting Cloudflare and creating the owner, and whether the manager continues the installer's id.
  • At most once a day: that the manager was opened that day, and whether the first person to open it was an admin or a member.

Installer

The installer sends one event per run, when the install ends:

  • whether it succeeded, failed or was cancelled, how long it took, the last step it reached, and an error category (such as wrangler_login, wrangler_deploy or health_timeout);
  • the installer's version, the operating system, CPU architecture and Node.js major version;
  • whether it ran interactively, in CI, or with --yes; whether the Worker name was the default one; whether the login had several accounts; whether a wrangler login was needed; the coding agent it ran under, if any (such as claude, codex or cursor, from the variables those agents set).

What is never sent

Your Cloudflare account id or name, email addresses, user names, Worker or instance names, domains or URLs, secret or variable names or values, tokens, resource ids, logs, error messages, or anything from a custom catalog, its app names and versions included. The exceptions to logs and error messages are the filtered excerpt of a Cloudflare API error message described above, and a failure report, which only an admin sends, by hand.

How it is sent

Every event is tied to a random id created at install, never to a person. Setup with the installer creates the id and hands it to the manager, so both report under the same id. The manager sends from its Worker, not from your browser: there is no tracking script, no cookie and no page view. The installer sends from your machine, and gives up after 3 seconds so a run is never held up.

Preview in Settings > Anonymous report shows the next daily report, built the same way the scheduled one is.

Where it goes

Events go to PostHog Cloud in the EU region (Frankfurt), at eu.i.posthog.com, as anonymous events: every event asks PostHog to create no person profile and to skip its IP-based location lookup.

Two more protections are PostHog project settings, not something the code enforces: the Appflare project is set to discard IP addresses, and events are kept for as long as PostHog's plan retains them (a year on the free plan).

Failure reports

When a job fails, admins see Send a report on the failure message: on the job's page, and on the sandbox and Appflare update cards. Nothing is sent until an admin opens it, reads what the report contains, and clicks Send. A report is never sent automatically, and each failed job can be reported once.

A report contains:

  • the kind of job, the app's catalog slug and version (with the same rules as the job events above, so custom for an app from a custom catalog or a repository), the Appflare version, and the Workers plan;
  • the step the job stopped at, its error, the error category and phase, and every Cloudflare error code in the log;
  • the job's log (its last 400 lines at most);
  • a note, if the admin writes one;
  • the same random id as the anonymous report, and whether the anonymous report is on.

Before the report leaves, the error, the step, the log and the note are passed once more through a filter that takes out anything that looks private: tokens, keys and passwords, including every value of a NAME=value environment line and of flags such as --password (shown as [redacted]); email addresses ([email]); your Cloudflare account id ([account id]); other Cloudflare ids and UUIDs ([id]); your workers.dev subdomain and your custom hostnames ([domain]); the names of your Workers ([worker]); and the other names Appflare recorded: the apps' databases, namespaces, buckets, queues and Access applications, and the names you gave apps ([name]). What stays readable is what a fix needs: Cloudflare's error codes and HTTP statuses, step names, versions, and the app's catalog slug. The dialog's See exactly what is sent shows the report exactly as it will leave, after that filter.

A failure report goes the same way as the anonymous report: from the manager's Worker to the Appflare PostHog project in the EU, as an event called job_failure_report. It is sent even when the anonymous report is turned off, because the admin chose to send it; the dialog says so. A development build never sends one.

Turning it off

Any one of these stops everything:

  • The Send the anonymous report switch in Settings > Anonymous report (admins).
  • The installer's flag: npx create-appflare --no-telemetry.
  • APPFLARE_TELEMETRY=off (0 and false work too) or DO_NOT_TRACK=1 in the installer's environment.
  • The same variables on the manager's Worker, set in the Cloudflare dashboard under the Worker's Settings, Variables and Secrets. Either one locks the anonymous report off: Settings > Anonymous report shows the switch off and disabled, with "Turned off by the APPFLARE_TELEMETRY variable on this Worker. Remove the variable to change this here." (naming DO_NOT_TRACK when that is the one set). Updates of the manager keep the variable.

When the installer's report is off by the flag or a variable, it deploys the manager with APPFLARE_TELEMETRY=off, so the manager's is locked off too.

When it is off, nothing is sent, not even the fact that it is off, apart from a failure report an admin chooses to send. Turning it on again continues with the same random id, and jobs that ran while it was off are not reported.

Wrangler's own metrics

The installer runs wrangler to deploy the manager. Wrangler has usage metrics and error reports of its own, which go to Cloudflare. The installer turns both off for every wrangler command it runs, whether Appflare's anonymous report is on or off, unless you set WRANGLER_SEND_METRICS or WRANGLER_SEND_ERROR_REPORTS yourself.

On this page