diff --git a/docs/Admin.md b/docs/Admin.md index 6d75a17b810..15c65ab646f 100644 --- a/docs/Admin.md +++ b/docs/Admin.md @@ -32,6 +32,7 @@ Here are all the props accepted by the component: - [`i18nProvider`](#i18nprovider) - [`title`](#title) - [`dashboard`](#dashboard) +- [`disableTelemetry`](#disableTelemetry) - [`catchAll`](#catchall) - [`menu`](#menu) - [`theme`](#theme) @@ -138,6 +139,28 @@ const App = () => ( ![Custom home page](./img/dashboard.png) +## `disableTelemetry` + +In production, react-admin applications send an anonymous request on mount to a telemetry server operated by marmelab. You can see this request by looking at the Network tab of your browser DevTools: + +`https://react-admin-telemetry.marmelab.com/react-admin-telemetry` + +The only data sent to the telemetry server is the admin domain (e.g. "example.com") - no personal data is ever sent, and no cookie is included in the response. The react-admin team uses these domains to track the usage of the framework. + +You can opt out of telemetry by simply adding `disableTelemetry` to the `` component: + +```jsx +// in src/App.js +import * as React from "react"; +import { Admin } from 'react-admin'; + +const App = () => ( + + // ... + +); +``` + ## `catchAll` When users type URLs that don't match any of the children `` components, they see a default "Not Found" page. diff --git a/examples/demo/src/App.tsx b/examples/demo/src/App.tsx index 17a529ff4b5..42d87b66e3d 100644 --- a/examples/demo/src/App.tsx +++ b/examples/demo/src/App.tsx @@ -74,6 +74,7 @@ const App = () => { loginPage={Login} layout={Layout} i18nProvider={i18nProvider} + disableTelemetry > ComponentType[]; * // it's relatively straightforward to replace it: * * import * as React from 'react'; -import { useEffect, useState } from 'react'; + * import { useEffect, useState } from 'react'; * import { * CoreAdminContext, * CoreAdminUI, @@ -96,6 +96,7 @@ const CoreAdmin: FunctionComponent = ({ customSagas, dashboard, dataProvider, + disableTelemetry, history, i18nProvider, initialState, @@ -121,6 +122,7 @@ const CoreAdmin: FunctionComponent = ({ layout={appLayout || layout} customRoutes={customRoutes} dashboard={dashboard} + disableTelemetry={disableTelemetry} menu={menu} catchAll={catchAll} theme={theme} diff --git a/packages/ra-core/src/core/CoreAdminUI.tsx b/packages/ra-core/src/core/CoreAdminUI.tsx index 2a956fb9689..cc0ac8e4dde 100644 --- a/packages/ra-core/src/core/CoreAdminUI.tsx +++ b/packages/ra-core/src/core/CoreAdminUI.tsx @@ -4,6 +4,7 @@ import { FunctionComponent, ComponentType, useMemo, + useEffect, } from 'react'; import { Switch, Route } from 'react-router-dom'; @@ -32,6 +33,7 @@ export interface AdminUIProps { children?: AdminChildren; customRoutes?: CustomRoutes; dashboard?: DashboardComponent; + disableTelemetry?: boolean; layout?: LayoutComponent; loading?: LoadingComponent; loginPage?: LoginComponent | boolean; @@ -50,6 +52,7 @@ const CoreAdminUI: FunctionComponent = ({ children, customRoutes = [], dashboard, + disableTelemetry = false, layout = DefaultLayout, loading = Noop, loginPage = false, @@ -62,6 +65,21 @@ const CoreAdminUI: FunctionComponent = ({ const logoutElement = useMemo(() => logout && createElement(logout), [ logout, ]); + + useEffect(() => { + if ( + disableTelemetry || + process.env.NODE_ENV !== 'production' || + typeof window === 'undefined' || + typeof window.location === 'undefined' || + typeof Image === 'undefined' + ) { + return; + } + const img = new Image(); + img.src = `https://react-admin-telemetry.marmelab.com/react-admin-telemetry?domain=${window.location.hostname}`; + }, [disableTelemetry]); + return ( {loginPage !== false && loginPage !== true ? ( diff --git a/packages/ra-core/src/types.ts b/packages/ra-core/src/types.ts index 08953f673d2..fed87db2691 100644 --- a/packages/ra-core/src/types.ts +++ b/packages/ra-core/src/types.ts @@ -474,6 +474,7 @@ export interface AdminProps { customSagas?: any[]; dashboard?: DashboardComponent; dataProvider: DataProvider | LegacyDataProvider; + disableTelemetry?: boolean; history?: History; i18nProvider?: I18nProvider; initialState?: InitialState; diff --git a/packages/react-admin/src/Admin.tsx b/packages/react-admin/src/Admin.tsx index 7a5b24add47..5d613cb8e7b 100644 --- a/packages/react-admin/src/Admin.tsx +++ b/packages/react-admin/src/Admin.tsx @@ -94,6 +94,7 @@ const Admin: FunctionComponent = ({ customSagas, dashboard, dataProvider, + disableTelemetry, history, i18nProvider, initialState, @@ -137,6 +138,7 @@ const Admin: FunctionComponent = ({ layout={appLayout || layout} customRoutes={customRoutes} dashboard={dashboard} + disableTelemetry={disableTelemetry} menu={menu} catchAll={catchAll} theme={theme}