diff --git a/docs/admin_docs/installation/docker-compose.mdx b/docs/admin_docs/installation/docker-compose.mdx index 04d14915860..9ec86e3c060 100644 --- a/docs/admin_docs/installation/docker-compose.mdx +++ b/docs/admin_docs/installation/docker-compose.mdx @@ -223,8 +223,9 @@ compose based installation, edit the `x-superset-image:` line in your `docker-co `docker-compose-non-dev.yml` files, replacing `apachesuperset.docker.scarf.sh/apache/superset` with `apache/superset` to pull the image directly from Docker Hub. -To disable the Scarf telemetry pixel, set the `SCARF_ANALYTICS` environment variable to `False` in -your terminal and/or in your `docker/.env` file. +To disable the Scarf telemetry pixel, set the `SCARF_ANALYTICS` environment variable to `false` in +your `docker/.env` file. This is read at runtime, so it disables the pixel on the pre-built image +without rebuilding the frontend. ::: ## 3. Log in to Superset diff --git a/docs/admin_docs/installation/kubernetes.mdx b/docs/admin_docs/installation/kubernetes.mdx index c18bf803f92..6433564f8bd 100644 --- a/docs/admin_docs/installation/kubernetes.mdx +++ b/docs/admin_docs/installation/kubernetes.mdx @@ -136,7 +136,17 @@ init: :::note Superset uses [Scarf Gateway](https://about.scarf.sh/scarf-gateway) to collect telemetry data. Knowing the installation counts for different Superset versions informs the project's decisions about patching and long-term support. Scarf purges personally identifiable information (PII) and provides only aggregated statistics. -To opt-out of this data collection in your Helm-based installation, edit the `repository:` line in your `helm/superset/values.yaml` file, replacing `apachesuperset.docker.scarf.sh/apache/superset` with `apache/superset` to pull the image directly from Docker Hub. +There are two independent telemetry channels: + +- **Image pulls** (Scarf Gateway): to opt out, edit the `repository:` line in your `helm/superset/values.yaml` file, replacing `apachesuperset.docker.scarf.sh/apache/superset` with `apache/superset` to pull the image directly from Docker Hub. +- **The analytics pixel** rendered in the UI: to opt out, set the `SCARF_ANALYTICS` environment variable to `false` on the Superset containers via `extraEnv` in your `values.yaml`: + + ```yaml + extraEnv: + SCARF_ANALYTICS: "false" + ``` + + This is read at runtime, so it takes effect on the pre-built images without rebuilding the frontend. ::: ### Dependencies diff --git a/docs/docs/faq.mdx b/docs/docs/faq.mdx index 2e6ff2fefa8..26c92a4a849 100644 --- a/docs/docs/faq.mdx +++ b/docs/docs/faq.mdx @@ -321,8 +321,8 @@ This can be used, for example, to convert UTC time to local time. Superset uses [Scarf](https://about.scarf.sh/) by default to collect basic telemetry data upon installing and/or running Superset. This data helps the maintainers of Superset better understand which versions of Superset are being used, in order to prioritize patch/minor releases and security fixes. We use the [Scarf Gateway](https://docs.scarf.sh/gateway/) to sit in front of container registries, the [scarf-js](https://about.scarf.sh/package-sdks) package to track `npm` installations, and a Scarf pixel to gather anonymous analytics on Superset page views. Scarf purges PII and provides aggregated statistics. Superset users can easily opt out of analytics in various ways documented [here](https://docs.scarf.sh/gateway/#do-not-track) and [here](https://docs.scarf.sh/package-analytics/#as-a-user-of-a-package-using-scarf-js-how-can-i-opt-out-of-analytics). -Superset maintainers can also opt out of telemetry data collection by setting the `SCARF_ANALYTICS` environment variable to `false` in the Superset container (or anywhere Superset/webpack are run). -Additional opt-out instructions for Docker users are available on the [Docker Installation](/admin-docs/installation/docker-compose) page. +You can also opt out of the analytics pixel by setting the `SCARF_ANALYTICS` environment variable to `false`. This is read at runtime, so setting it on the Superset container (for example via `extraEnv` in the Helm chart, or `docker/.env` for Docker Compose) disables the pixel on the pre-built images without rebuilding the frontend. +Additional opt-out instructions are available on the [Docker Compose](/admin-docs/installation/docker-compose) and [Kubernetes](/admin-docs/installation/kubernetes) installation pages. ## Does Superset have an archive panel or trash bin from which a user can recover deleted assets? diff --git a/superset-frontend/packages/superset-ui-core/src/components/TelemetryPixel/TelemetryPixel.test.tsx b/superset-frontend/packages/superset-ui-core/src/components/TelemetryPixel/TelemetryPixel.test.tsx index 7dc5d4e63d6..b7b32ebc3bf 100644 --- a/superset-frontend/packages/superset-ui-core/src/components/TelemetryPixel/TelemetryPixel.test.tsx +++ b/superset-frontend/packages/superset-ui-core/src/components/TelemetryPixel/TelemetryPixel.test.tsx @@ -46,3 +46,19 @@ test('should NOT render the pixel link when FF is off', () => { const image = document.querySelector('img[src*="scarf.sh"]'); expect(image).not.toBeInTheDocument(); }); + +test('should NOT render the pixel link when disabled at runtime', () => { + process.env.SCARF_ANALYTICS = 'true'; + render(); + + const image = document.querySelector('img[src*="scarf.sh"]'); + expect(image).not.toBeInTheDocument(); +}); + +test('should render the pixel link when enabled at runtime', () => { + process.env.SCARF_ANALYTICS = 'true'; + render(); + + const image = document.querySelector('img[src*="scarf.sh"]'); + expect(image).toBeInTheDocument(); +}); diff --git a/superset-frontend/packages/superset-ui-core/src/components/TelemetryPixel/index.tsx b/superset-frontend/packages/superset-ui-core/src/components/TelemetryPixel/index.tsx index dfe0a7e0057..f0e3062dabd 100644 --- a/superset-frontend/packages/superset-ui-core/src/components/TelemetryPixel/index.tsx +++ b/superset-frontend/packages/superset-ui-core/src/components/TelemetryPixel/index.tsx @@ -23,17 +23,25 @@ interface TelemetryPixelProps { version?: string; sha?: string; build?: string; + enabled?: boolean; } /** * Renders a telemetry pixel component to capture anonymous, aggregated telemetry via Scarf. - * This can be disabled by setting the SCARF_ANALYTICS environment variable to false. + * + * Telemetry can be disabled in two ways: + * - At build time, by setting the SCARF_ANALYTICS environment variable to `false` + * (inlined by webpack; only effective when building the frontend yourself). + * - At runtime, by passing `enabled={false}`, which the app derives from the + * `SCARF_ANALYTICS` backend config exposed via the bootstrap payload. This is + * what allows opting out in pre-built images, where the build-time flag is fixed. * * @component * @param {TelemetryPixelProps} props - The props for the TelemetryPixel component. * @param {string} props.version - The version of Superset that's currently in use. * @param {string} props.sha - The SHA of Superset that's currently in use. * @param {string} props.build - The build of Superset that's currently in use. + * @param {boolean} props.enabled - Runtime opt-out switch; when false the pixel is not rendered. * @returns {JSX.Element | null} The rendered TelemetryPixel component. */ @@ -43,9 +51,11 @@ export const TelemetryPixel = ({ version = 'unknownVersion', sha = 'unknownSHA', build = 'unknownBuild', + enabled = true, }: TelemetryPixelProps): ReactElement | null => { const pixelPath = `https://apachesuperset.gateway.scarf.sh/pixel/${PIXEL_ID}/${version}/${sha}/${build}`; - return process.env.SCARF_ANALYTICS === 'false' ? null : ( + const disabled = !enabled || process.env.SCARF_ANALYTICS === 'false'; + return disabled ? null : ( (state => state.common.conf); const [showDatabaseModal, setShowDatabaseModal] = useState(false); const [showCSVUploadModal, setShowCSVUploadModal] = useState(false); @@ -781,6 +782,7 @@ const RightMenu = ({ // segments in the Scarf pixel URL. sha={navbarRight.version_sha || undefined} build={navbarRight.build_number || undefined} + enabled={SCARF_ANALYTICS !== false} /> ); diff --git a/superset-frontend/src/features/home/types.ts b/superset-frontend/src/features/home/types.ts index 633f0bffcfa..09814bdd72f 100644 --- a/superset-frontend/src/features/home/types.ts +++ b/superset-frontend/src/features/home/types.ts @@ -36,6 +36,7 @@ export interface ExtensionConfigs { COLUMNAR_EXTENSIONS: Array; EXCEL_EXTENSIONS: Array; HAS_GSHEETS_INSTALLED: boolean; + SCARF_ANALYTICS?: boolean; } export interface RightMenuProps { align: 'flex-start' | 'flex-end'; diff --git a/superset/config.py b/superset/config.py index fdfdbbda513..ac6d39c1ace 100644 --- a/superset/config.py +++ b/superset/config.py @@ -2336,6 +2336,13 @@ DATABASE_OAUTH2_TIMEOUT = timedelta(seconds=30) # Enable/disable CSP warning CONTENT_SECURITY_POLICY_WARNING = True +# Superset uses Scarf (https://about.scarf.sh/) to collect anonymous, aggregated +# telemetry via a pixel rendered in the UI. Set the SCARF_ANALYTICS environment +# variable to "false" to opt out. This value is exposed to the frontend through +# the bootstrap payload so it takes effect at runtime, including in pre-built +# images where the webpack build-time flag of the same name cannot be changed. +SCARF_ANALYTICS = utils.cast_to_boolean(os.environ.get("SCARF_ANALYTICS", True)) + # Do you want Talisman enabled? TALISMAN_ENABLED = utils.cast_to_boolean(os.environ.get("TALISMAN_ENABLED", True)) diff --git a/superset/views/base.py b/superset/views/base.py index aa069d69b23..5ab75a5876a 100644 --- a/superset/views/base.py +++ b/superset/views/base.py @@ -125,6 +125,7 @@ FRONTEND_CONF_KEYS = ( "MAPBOX_API_KEY", "DEFAULT_MAP_RENDERER", "CSV_STREAMING_ROW_THRESHOLD", + "SCARF_ANALYTICS", ) logger = logging.getLogger(__name__) diff --git a/tests/unit_tests/views/test_base.py b/tests/unit_tests/views/test_base.py index 75a59baef44..b32f97ae770 100644 --- a/tests/unit_tests/views/test_base.py +++ b/tests/unit_tests/views/test_base.py @@ -76,6 +76,14 @@ def test_default_map_renderer_is_exposed_to_frontend_config() -> None: assert "DEFAULT_MAP_RENDERER" in FRONTEND_CONF_KEYS +def test_scarf_analytics_is_exposed_to_frontend_config() -> None: + # Exposed at runtime so pre-built images can opt out via the SCARF_ANALYTICS + # config/env var (the webpack build-time flag cannot be changed there). + from superset.views.base import FRONTEND_CONF_KEYS + + assert "SCARF_ANALYTICS" in FRONTEND_CONF_KEYS + + _FULL_METADATA = { "version_string": "4.0.0", "version_sha": "abcdef12",