Qyra

Data flows and telemetry in self-hosted Qyra

What data stays inside your infrastructure, what leaves it, where it goes, and how to control it

This page is for self-hosted Qyra. Qyra Cloud is fully managed by Qyra and has a different data-processing profile.

Summary

  • Warehouse credentials, dbt or Qyra YAML definitions, generated SQL, query results, dashboard and chart definitions, and underlying warehouse data are processed inside your deployment. None of these are sent to Qyra through product telemetry.
  • Product telemetry is enabled by default and points at Qyra's RudderStack endpoint (https://analytics.qyraflow.com) using a built-in write key. It can be disabled with a single environment variable, or redirected to your own RudderStack instance.
  • Enterprise Edition validates its license key against Keygen on every server start. The request contains the license key only — no warehouse credentials, no query text, no business data. See License validation request for the exact payload.
  • Optional integrations (SSO, SMTP, Slack, GitHub, object storage, AI providers, MCP, sandbox providers, Sentry, and the organization roadmap) talk directly to the endpoints you configure. They are not proxied through Qyra Cloud.

Everything below is grounded in the current Qyra source code and applies to a standard self-hosted deployment on the official Helm chart or Docker Compose.

Three telemetry configurations

Telemetry means the RudderStack event stream emitted by the Qyra backend and browser. The three supported configurations map to three environment-variable combinations.

Configuration 1: default Qyra telemetry

If you set none of the RUDDERSTACK_* variables, Qyra uses a built-in write key and its own RudderStack endpoint:

  • Endpoint: https://analytics.qyraflow.com
  • Write key: built into the release
  • Enabled by default: yes, on every fresh install
  • Applies to: the backend, the scheduler, and the browser (the frontend loads its RudderStack config from the backend's /api/v1/health response)

If you do nothing, telemetry is on and points at Qyra.

Configuration 2: disable outbound RudderStack telemetry

Set one variable on every Qyra container:

RUDDERSTACK_ANALYTICS_DISABLED=true

When this is true the backend clears both the write key and the data plane URL, no matter what RUDDERSTACK_WRITE_KEY or RUDDERSTACK_DATA_PLANE_URL are set to. That means:

  • The backend QyraAnalytics.track(), identify(), and group() calls short-circuit and send nothing.
  • The /api/v1/health response returns an empty rudder block, so the browser skips rudder-sdk-js initialization and emits no client-side events.
  • RUDDERSTACK_ANALYTICS_DISABLED=true takes precedence over RUDDERSTACK_WRITE_KEY and RUDDERSTACK_DATA_PLANE_URL.

Set the variable on every process that runs Qyra code:

  • The backend container (qyra-headless / qyra)
  • The scheduler container (scheduler.enabled: true)
  • Any NATS worker containers (warehouseNatsWorker, preAggregateWorker)

Disabling RudderStack telemetry does not change product functionality. Nothing in the query, dashboard, AI, or admin surface depends on it. Prometheus metrics, in-product Usage Analytics dashboards, audit logs, query tags in your warehouse, and the optional usage event stream all keep working — they are independent systems (see Related systems).

# quanvio/qyra Helm chart
extraEnv:
  - name: RUDDERSTACK_ANALYTICS_DISABLED
    value: "true"

scheduler:
  extraEnv:
    - name: RUDDERSTACK_ANALYTICS_DISABLED
      value: "true"

warehouseNatsWorker:
  extraEnv:
    - name: RUDDERSTACK_ANALYTICS_DISABLED
      value: "true"
services:
  qyra:
    image: quanvio/qyra:latest
    environment:
      RUDDERSTACK_ANALYTICS_DISABLED: "true"

  scheduler:
    image: quanvio/qyra:latest
    environment:
      RUDDERSTACK_ANALYTICS_DISABLED: "true"

Configuration 3: send telemetry to your own RudderStack

Point Qyra at a RudderStack source you control:

RUDDERSTACK_WRITE_KEY=your-write-key
RUDDERSTACK_DATA_PLANE_URL=https://your-rudderstack.example.com
  • The backend uses these values in place of the built-in ones.
  • The browser reads them from /api/v1/health and initializes rudder-sdk-js against your endpoint.
  • Events go to your RudderStack destination instead of Qyra's. Qyra never sees them.
  • If RUDDERSTACK_ANALYTICS_DISABLED=true is also set, disable wins — no events are sent anywhere.

This is a redirection of the same event stream — it is not the same thing as audit logs, Prometheus metrics, warehouse query tags, or the in-product Usage Analytics dashboards. Those systems are independent (see Related systems).

Telemetry payload

The backend emits RudderStack events through QyraAnalytics.track(). Every event carries a common context.app block and the event's own properties.

Common context on every event

All telemetry events carry the following installation context:

FieldDescription
app.namespaceConstant "qyra"
app.nameConstant "qyra_server"
app.versionBackend version, e.g. "0.1500.0"
app.modeDeployment mode: default, cloud_beta, demo, pr, dev — self-hosted is default
app.siteUrlPresent only in cloud_beta and demo. Not sent for standard self-hosted deployments.
app.installIdValue of QYRA_INSTALL_ID if set, otherwise a random UUID generated at process start
app.installTypeValue of QYRA_INSTALL_TYPE if set, otherwise unknown (Helm chart, Docker image, etc.)
app.installChartVersionValue of QYRA_HELM_CHART_VERSION if set, otherwise null

The user identifier is either the Qyra userId (a UUID), the anonymous ID (00000000-0000-0000-0000-000000000000) when the user has enabled tracking anonymization, or the constant string "embed" for embedded viewers.

Event categories

CategoryWhat the events describeRepresentative fields
Installation and lifecycleProcess start, version upgrades, feature-flag configurationapp.version, app.installId, app.installType, app.installChartVersion
User and authenticationSignup, login, invite, password reset, personal access token, SSO identity link/removaluserId, loginProvider, context, is_tracking_anonymized; email and name only if the user has not enabled tracking anonymization
Organization, project, and resource identifiersCreate/update/delete of organizations, projects, warehouse connections, spacesorganizationId, projectId, warehouseType, dbtConnectionType
Charts, dashboards, spaces, search, sharing, scheduling, APIContent lifecycle (saved_chart.created, dashboard.updated, space.created, scheduler.created, etc.), feature usage, share link creationResource IDs, structural counts (dimensions, metrics, filters, sorts), chart type, and for creates/updates: title and description of charts, dashboards, and schedulers
Query executionOne event per query — query.executed, query.ready, query.completed, query.errorqueryId, organizationId, projectId, context (e.g. explore, dashboard), warehouseType, executionSource (warehouse, pre_aggregate_duckdb, pre_aggregate_warehouse, external_source_duckdb), totalRowCount, columnsCount, warehouseExecutionTimeMs, cacheHit, exploreName, chartId, dashboardId
AI usageOne ai.usage event per model callfeature (agent, deep-research, data-app, chart-metadata, embedding, etc.), provider (openai, anthropic, bedrock, …), model, keyManagement (qyra-managed or self-managed), inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens, reasoningTokens, totalTokens, organizationId, projectId, aiAgentId, threadId, promptId
Errors and operational eventsQuery errors, scheduler-job outcomes, integration-connection outcomesqueryId, context, warehouseType, errorMessage (short server-side error strings — see next section)

Telemetry is not fully anonymous. Events carry stable identifiers (organizationId, projectId, userId, chart/dashboard/space UUIDs) and, for some events, human-readable resource metadata: chart and dashboard titles and descriptions, scheduler names, warehouse type, dbt connection type, and short errorMessage strings from server-side failures. Do not assume every event is anonymous.

User-level tracking anonymization

Users can toggle Anonymize my usage data in their profile. When on:

  • The is_tracking_anonymized: true flag is set on the user record and included in identify/update events.
  • The user.updated, user.verified, and user.deleted events drop email, firstName, and lastName.
  • The userId and resource identifiers (organizationId, projectId, chart/dashboard UUIDs) are still sent — anonymization operates at the user-name/email level, not at the identifier level.

This is a user-scoped setting. It does not disable telemetry, and it does not scrub identifiers or resource metadata from non-user events. To stop telemetry leaving the deployment, use RUDDERSTACK_ANALYTICS_DISABLED=true.

Not sent through RudderStack telemetry

Verified against the current backend source. RudderStack telemetry never contains:

  • Warehouse credentials or authentication secrets. Connection strings, keys, and tokens live in QYRA_SECRET-encrypted rows in Postgres and are never included in event payloads.
  • dbt project files or complete semantic-layer definitions. Warehouse type and dbtConnectionType are included; the manifest, .yml model files, and metric definitions are not.
  • Generated SQL or SQL Runner query text. Query events carry an ID, structural counts, timings, and warehouse type — never the SQL string.
  • Query results, row values, or warehouse records. Query events carry totalRowCount and columnsCount — never row data.
  • Complete dashboard or chart definitions. Create/update events carry structural counts (metrics, dimensions, filters, series types), the chart type, and the chart or dashboard title and description. They do not carry the full config JSON, tile layout, or filter values.
  • AI prompt text, conversation text, or model responses. ai.usage events carry token counts, provider, model, feature, and IDs (aiAgentId, threadId, promptId, organizationId, projectId). They do not carry prompt or completion text.
  • Integration credentials or application secrets. OAuth tokens, Slack bot tokens, GitHub app credentials, SMTP passwords, QYRA_LICENSE_KEY, QYRA_SECRET, and AI-provider API keys are never sent.

Exceptions and potentially sensitive metadata that is sent:

  • Chart, dashboard, space, and scheduler titles and descriptions on create/update events.
  • Explore name (exploreName) and virtual view ID on query events.
  • User email, first name, last name on user identify/update events — unless the user has enabled tracking anonymization.
  • Short server-side error messages on error events (typed exception messages, not stack traces of user data).
  • Stable UUIDs for organizations, projects, users, charts, dashboards, spaces, schedulers, queries, and AI agents.

Enterprise license validation

Enterprise Edition (QYRA_LICENSE_KEY set) validates the license against Keygen at server start and periodically thereafter.

License validation request

  • Endpoint: POST https://api.keygen.sh/v1/accounts/1ae7d3a8-4665-44e4-989d-9de54c84761a/licenses/actions/validate-key

  • Timing: on server start and roughly once every 24 hours from the process cache

  • Initiator: the Qyra backend and any process that instantiates LicenseClient (backend, scheduler, workers)

  • Request headers: Content-Type: application/json, Accept: application/json

  • Request body:

    {
      "meta": {
        "key": "<value of QYRA_LICENSE_KEY>"
      }
    }
  • Response: validity, human-readable detail, and a status code. No code or configuration is pulled during validation.

The request contains the license key only. It does not contain warehouse credentials, dbt project data, query text, query results, chart or dashboard definitions, or any organization business data.

Keygen is the only Qyra-operated external service required for Enterprise features. If you also enable the optional organization roadmap, the backend additionally calls https://roadmap.qyraflow.com — see the egress matrix below.

For full license setup steps and troubleshooting, see Enterprise features and licensing.

These systems are commonly conflated with RudderStack telemetry. They are independent, and each continues to work when RUDDERSTACK_ANALYTICS_DISABLED=true.

SystemWhere the data goesBehaviour when RUDDERSTACK_ANALYTICS_DISABLED=true
RudderStack product telemetryOutside the deployment — https://analytics.qyraflow.com by default, or your own RudderStack endpoint if redirectedDisabled
In-product Usage Analytics dashboardsApplication Postgres inside the deploymentContinues to work
Warehouse query tagsYour warehouse's query historyContinues to work
Prometheus metrics and OpenTelemetry HTTP metricsExposed on the Qyra instance for your scraperContinues to work
Audit logs and application logsWherever your log stack collects stdoutContinues to work
Customer-configured usage event streamThe S3 bucket you configure with USAGE_EVENTS_* variablesContinues to work — the event stream sink runs before the RudderStack path and is independent of it

Egress matrix

Every default and optional outbound destination from a self-hosted Qyra deployment. "Required" means the deployment fails without the destination for the feature it enables; "Optional" means the destination is only reached when the feature is turned on.

DestinationWhen it is usedRequired or optionalInitiating componentData sentControl
analytics.qyraflow.comDefault RudderStack telemetry endpointOptional (on by default)Backend, scheduler, workers, browserEvent stream — see Telemetry payloadRUDDERSTACK_ANALYTICS_DISABLED=true, or redirect with RUDDERSTACK_WRITE_KEY + RUDDERSTACK_DATA_PLANE_URL
api.keygen.shEnterprise license validation on server start and every 24hRequired for Enterprise Edition. Not called at all in Community Edition.Backend, scheduler, workersLicense key inside a JSON meta.key fieldRemove QYRA_LICENSE_KEY (Community only), or run the validation proxy in front
roadmap.qyraflow.comOptional organization roadmap, and optional license-validation proxyOptionalBackendRoadmap requests: organization UUID as a path segment and license key in the qyra-license-key header. Proxy requests: license key in a JSON key field. No query text or business data.Do not enable the roadmap feature; leave QYRA_LICENSE_VALIDATION_PROXY_ENABLED unset so license validation goes directly to api.keygen.sh
Customer data warehouseEvery query, dbt compile, warehouse workerRequiredBackend, scheduler, warehouse NATS workersSQL queries, receives query results in returnWarehouse connection config — kept internal to the deployment
Application PostgresAll persistent state (users, projects, encrypted secrets, dashboards, results cache metadata)RequiredBackend, scheduler, workersFull application dataPGHOST and related variables
Object storage (S3 / S3-compatible)Results cache, exports, images, headless browser artifacts, data-app bundlesRequiredBackend, scheduler, headless browserEncrypted results parquet, generated CSVs/PDFs/PNGs, data-app static bundlesS3_* variables
SMTP providerTransactional email (invites, password resets, scheduled deliveries)OptionalBackend, schedulerEmail content: recipient address, invitation link, scheduled chart image or CSV attachmentSMTP_* variables
Identity provider (Google, Okta, Azure AD, OneLogin, generic OIDC, Snowflake OAuth, Databricks OAuth)Sign-in and SSOOptionalBackend, browser (redirect)OIDC/OAuth handshake — user claims from the IdP; Qyra sends only what the OAuth flow requiresAUTH_* variables and SSO setup
AI/model provider (OpenAI, Anthropic, Azure OpenAI, OpenRouter, Bedrock)AI agents, AI writeback, data apps, embeddings, chart metadata generationOptionalBackend, scheduler, sandboxes (when the agent runs in a sandbox)Prompts, tool calls, semantic-layer metadata for context, and — depending on the feature — query results the agent has already fetched from your warehouse. Provider API key.AI_COPILOT_ENABLED=false, AI_WRITEBACK_ENABLED=false, or a private LLM gateway; see AI providers
GitHub (or other source-control provider)dbt project write-back and AI writeback PRsOptionalBackend, sandboxes (AI writeback)Git commits and pull-request contents against the dbt repo you configured; GitHub App installation token or personal access tokenDo not connect GitHub; use a self-hosted GitLab / GHES instance you control
SlackScheduled deliveries, unfurls, AI agents in SlackOptionalBackend, schedulerMessage content: chart images, CSVs, unfurl payloads; Slack bot tokenDo not install the Slack app
MCP serversModel Context Protocol tool calls from Qyra AI agentsOptionalBackend, schedulerMCP tool call payloads to the servers you registerDo not enable MCP; register only internal MCP endpoints
E2B (api.e2b.dev and per-sandbox subdomains)Default managed sandbox provider for AI writeback and data appsOptionalBackend, schedulerFiles copied into the sandbox (dbt project, generated code), API key. Sandbox egress from inside E2B is separately allowlisted per sandbox.SANDBOX_PROVIDER=aws-lambda-microvms or SANDBOX_PROVIDER=azure-container-apps to run sandboxes inside your own cloud
AWS Lambda MicroVMs / Azure Container Apps SandboxesAlternative sandbox providersOptionalBackend, schedulerSame payload as E2B, but into your own AWS or Azure accountProvider-specific configuration; stays inside your cloud
Sentry (or another DSN)Error reporting (optional; disabled unless a DSN is set)OptionalBackend, scheduler, browserError message, stack trace, breadcrumbs, userId, organizationUuid, projectUuid, dashboardUuid tags. Session replay is enabled on error.Leave SENTRY_BE_DSN and SENTRY_FE_DSN unset (default). Point at your own Sentry to keep it internal.
Google Sheets APIOptional Google Sheets syncOptionalBackend, schedulerQuery results written to the target sheet; Google service-account credentialsDo not configure Google Sheets integration
dbt Cloud APIOptional dbt Cloud integration for a project's dbt configurationOptionalBackendJob trigger requests, project artifact fetches; dbt Cloud API tokenDo not configure a dbt Cloud connection for the project
Container image registry (Docker Hub / GHCR)docker pull when starting or upgradingRequired at deploy time only. Not called at runtime.Container orchestratorImage pullMirror the image into a private registry

Community Edition (no QYRA_LICENSE_KEY) does not call api.keygen.sh or roadmap.qyraflow.com. Every other row is identical.

Security-review checklist

Set RUDDERSTACK_ANALYTICS_DISABLED=true on every Qyra container (backend, scheduler, NATS workers). See Configuration 2.

Set RUDDERSTACK_WRITE_KEY and RUDDERSTACK_DATA_PLANE_URL on every Qyra container. Confirm the browser picks up the new endpoint by inspecting GET /api/v1/health — the rudder block should show your write key and data plane URL. See Configuration 3.

  • api.keygen.sh — Enterprise Edition only, required.
  • roadmap.qyraflow.com — only if you enable the organization roadmap.
  • analytics.qyraflow.com — only if you leave default telemetry on.
  • Your warehouse endpoint, S3 endpoint, IdP, SMTP host, AI provider endpoints, Slack, GitHub, and sandbox provider endpoints — whichever features you use.

Everything else can be blocked. See the production deployment checklist for a starting egress policy.

  • AI providers: point ANTHROPIC_BASE_URL, OPENAI_BASE_URL, or BEDROCK_BASE_URL at an internal LLM gateway.
  • Sandboxes: set SANDBOX_PROVIDER=aws-lambda-microvms or azure-container-apps to keep sandbox execution inside your cloud account.
  • Sentry: leave SENTRY_BE_DSN and SENTRY_FE_DSN unset, or point them at your own Sentry instance.
  • GitHub: connect a GHES or self-hosted GitLab instead of GitHub.com.
  • MCP: register only internal MCP endpoints.
  • Google Sheets, Slack, dbt Cloud: leave disabled.
  • GET /api/v1/health returns the effective rudder and sentry config the frontend will use.
  • Backend startup logs record whether Sentry initialized and whether license validation succeeded.
  • Run a network capture or eBPF/Cilium egress log against the backend, scheduler, and worker pods to confirm the observed destinations match the allow-list.
  • Query the Instance health page in Qyra for the running configuration snapshot.

Further reading