feat: remove umami (#4520)

This commit is contained in:
Faisal Amir 2025-01-26 20:42:03 +07:00 committed by GitHub
parent cdc7d2ba47
commit 32436121c7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 8 additions and 303 deletions

View File

@ -122,8 +122,6 @@ jobs:
make build-and-publish make build-and-publish
env: env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ANALYTICS_ID: ${{ secrets.JAN_APP_UMAMI_PROJECT_API_KEY }}
ANALYTICS_HOST: ${{ secrets.JAN_APP_UMAMI_URL }}
POSTHOG_KEY: ${{ secrets.POSTHOG_KEY }} POSTHOG_KEY: ${{ secrets.POSTHOG_KEY }}
POSTHOG_HOST: ${{ secrets.POSTHOG_HOST }} POSTHOG_HOST: ${{ secrets.POSTHOG_HOST }}

View File

@ -168,8 +168,6 @@ jobs:
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
APP_PATH: '.' APP_PATH: '.'
DEVELOPER_ID: ${{ secrets.DEVELOPER_ID }} DEVELOPER_ID: ${{ secrets.DEVELOPER_ID }}
ANALYTICS_ID: ${{ secrets.JAN_APP_UMAMI_PROJECT_API_KEY }}
ANALYTICS_HOST: ${{ secrets.JAN_APP_UMAMI_URL }}
POSTHOG_KEY: ${{ secrets.POSTHOG_KEY }} POSTHOG_KEY: ${{ secrets.POSTHOG_KEY }}
POSTHOG_HOST: ${{ secrets.POSTHOG_HOST }} POSTHOG_HOST: ${{ secrets.POSTHOG_HOST }}

View File

@ -160,8 +160,6 @@ jobs:
make build-and-publish make build-and-publish
env: env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ANALYTICS_ID: ${{ secrets.JAN_APP_UMAMI_PROJECT_API_KEY }}
ANALYTICS_HOST: ${{ secrets.JAN_APP_UMAMI_URL }}
AZURE_KEY_VAULT_URI: ${{ secrets.AZURE_KEY_VAULT_URI }} AZURE_KEY_VAULT_URI: ${{ secrets.AZURE_KEY_VAULT_URI }}
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}

View File

@ -23,6 +23,4 @@ Adhering to Jan's privacy preserving philosophy, our analytics philosophy is to
## What is tracked ## What is tracked
1. By default, Github tracks downloads and device metadata for all public GitHub repositories. This helps us troubleshoot & ensure cross-platform support. 1. By default, Github tracks downloads and device metadata for all public GitHub repositories. This helps us troubleshoot & ensure cross-platform support.
2. We use [Umami](https://umami.is/) to collect, analyze, and understand application data while maintaining visitor privacy and data ownership. We are using the Umami Cloud in Europe to ensure GDPR compliance. Please see [Umami Privacy Policy](https://umami.is/privacy) for more details. 2. Additionally, we plan to enable a `Settings` feature for users to turn off all tracking.
3. We use Umami to track a single `app.opened` event without additional user metadata, in order to understand retention. In addition, we track `app.version` to understand app version usage.
4. Additionally, we plan to enable a `Settings` feature for users to turn off all tracking.

View File

@ -24,13 +24,6 @@ Jan runs with privacy by default and is used 100% offline on your own computer.
If you use a Remote AI API (e.g., OpenAI API, Groq API), your data will naturally travel to their servers. They will be subject to the privacy policy of the respective API provider. If you use a Remote AI API (e.g., OpenAI API, Groq API), your data will naturally travel to their servers. They will be subject to the privacy policy of the respective API provider.
</Callout> </Callout>
Jan uses [Umami](https://umami.is/) for analytics, which is a privacy-focused, GDPR-compliant analytics tool that does not track personal information. We use this to get aggregate reports on OS and hardware types and prioritize our engineering roadmap. As per [Umami's Privacy Policy](https://umami.is/privacy), Umami uses the following data points to generate its reports:
- OS and device characteristics
- IP address
Jan does not get any of this data, and we do not track IP addresses or other identifying information. We are actively looking into more privacy-respecting ways to handle analytics, crash reports, and telemetry and would love to work with the community on this.
### Cortex ### Cortex
Cortex is a library that runs large language models (LLMs) locally on your computer. Cortex does not collect any personal information. Cortex is a library that runs large language models (LLMs) locally on your computer. Cortex does not collect any personal information.

View File

@ -9,8 +9,6 @@ import JotaiWrapper from '@/containers/Providers/Jotai'
import ThemeWrapper from '@/containers/Providers/Theme' import ThemeWrapper from '@/containers/Providers/Theme'
import Umami from '@/utils/umami'
import { CoreConfigurator } from './CoreConfigurator' import { CoreConfigurator } from './CoreConfigurator'
import DataLoader from './DataLoader' import DataLoader from './DataLoader'
@ -26,7 +24,6 @@ const Providers = ({ children }: PropsWithChildren) => {
<SWRConfigProvider> <SWRConfigProvider>
<ThemeWrapper> <ThemeWrapper>
<JotaiWrapper> <JotaiWrapper>
<Umami />
<CoreConfigurator> <CoreConfigurator>
<> <>
<Responsive /> <Responsive />

View File

@ -1,210 +0,0 @@
!(function () {
'use strict'
!(function (t) {
var e = t.screen,
n = e.width,
r = e.height,
a = t.navigator.language,
i = t.location,
o = t.localStorage,
u = t.document,
c = t.history,
f = 'jan.ai',
s = 'mainpage',
l = i.search,
d = u.currentScript
if (d) {
var m = 'data-',
h = d.getAttribute.bind(d),
v = h(m + 'website-id'),
p = h(m + 'host-url'),
g = 'false' !== h(m + 'auto-track'),
y = h(m + 'do-not-track'),
b = h(m + 'domains') || '',
S = b.split(',').map(function (t) {
return t.trim()
}),
k =
(p ? p.replace(/\/$/, '') : d.src.split('/').slice(0, -1).join('/')) +
'/api/send',
w = n + 'x' + r,
N = /data-umami-event-([\w-_]+)/,
T = m + 'umami-event',
j = 300,
A = function (t, e, n) {
var r = t[e]
return function () {
for (var e = [], a = arguments.length; a--; ) e[a] = arguments[a]
return n.apply(null, e), r.apply(t, e)
}
},
x = function () {
return {
website: v,
hostname: f,
screen: w,
language: a,
title: M,
url: I,
referrer: J,
}
},
E = function () {
return (
(o && o.getItem('umami.disabled')) ||
(y &&
(function () {
var e = t.doNotTrack,
n = t.navigator,
r = t.external,
a = 'msTrackingProtectionEnabled',
i =
e ||
n.doNotTrack ||
n.msDoNotTrack ||
(r && a in r && r[a]())
return '1' == i || 'yes' === i
})()) ||
(b && !S.includes(f))
)
},
O = function (t, e, n) {
n &&
((J = I),
(I = (function (t) {
try {
return new URL(t).pathname
} catch (e) {
return t
}
})(n.toString())) !== J && setTimeout(D, j))
},
L = function (t, e) {
if ((void 0 === e && (e = 'event'), !E())) {
var n = {
// eslint-disable-next-line @typescript-eslint/naming-convention
'Content-Type': 'application/json',
}
return (
void 0 !== K && (n['x-umami-cache'] = K),
fetch(k, {
method: 'POST',
body: JSON.stringify({
type: e,
payload: t,
}),
headers: n,
})
.then(function (t) {
return t.text()
})
.then(function (t) {
return (K = t)
})
.catch(function () {})
)
}
},
D = function (t, e) {
return L(
'string' == typeof t
? Object.assign({}, x(), {
name: t,
data: 'object' == typeof e ? e : void 0,
})
: 'object' == typeof t
? t
: 'function' == typeof t
? t(x())
: x()
)
}
t.umami ||
(t.umami = {
track: D,
identify: function (t) {
return L(
Object.assign({}, x(), {
data: t,
}),
'identify'
)
},
})
var K,
P,
_,
q,
C,
I = '' + s + l,
J = u.referrer,
M = u.title
if (g && !E()) {
;(c.pushState = A(c, 'pushState', O)),
(c.replaceState = A(c, 'replaceState', O)),
(C = function (t) {
var e = t.getAttribute.bind(t),
n = e(T)
if (n) {
var r = {}
return (
t.getAttributeNames().forEach(function (t) {
var n = t.match(N)
n && (r[n[1]] = e(t))
}),
D(n, r)
)
}
return Promise.resolve()
}),
u.addEventListener(
'click',
function (t) {
var e = t.target,
n =
'A' === e.tagName
? e
: (function (t, e) {
for (var n = t, r = 0; r < e; r++) {
if ('A' === n.tagName) return n
if (!(n = n.parentElement)) return null
}
return null
})(e, 10)
if (n) {
var r = n.href,
a =
'_blank' === n.target ||
t.ctrlKey ||
t.shiftKey ||
t.metaKey ||
(t.button && 1 === t.button)
if (n.getAttribute(T) && r)
return (
a || t.preventDefault(),
C(n).then(function () {
a || (i.href = r)
})
)
} else C(e)
},
!0
),
(_ = new MutationObserver(function (t) {
var e = t[0]
M = e && e.target ? e.target.text : void 0
})),
(q = u.querySelector('head > title')) &&
_.observe(q, {
subtree: !0,
characterData: !0,
childList: !0,
})
var R = function () {
'complete' !== u.readyState || P || (D(), (P = !0))
}
u.addEventListener('readystatechange', R, !0), R()
}
}
})(window)
})()

View File

@ -1,67 +0,0 @@
import { useEffect } from 'react'
import Script from 'next/script'
// Define the type for the umami data object
interface UmamiData {
version: string
}
declare global {
interface Window {
umami:
| {
track: (event: string, data?: UmamiData) => void
}
| undefined
}
}
const Umami = () => {
const appVersion = VERSION
const analyticsScriptPath = './umami_script.js'
const analyticsId = ANALYTICS_ID
useEffect(() => {
if (!appVersion || !analyticsScriptPath || !analyticsId) return
const ping = () => {
// Check if umami is defined before ping
if (window.umami !== null && typeof window.umami !== 'undefined') {
window.umami.track(appVersion, {
version: appVersion,
})
}
}
// Wait for umami to be defined before ping
if (window.umami !== null && typeof window.umami !== 'undefined') {
ping()
} else {
// Listen for umami script load event
document.addEventListener('umami:loaded', ping)
}
// Cleanup function to remove event listener if the component unmounts
return () => {
document.removeEventListener('umami:loaded', ping)
}
}, [appVersion, analyticsScriptPath, analyticsId])
return (
<>
{appVersion && analyticsScriptPath && analyticsId && (
<Script
src={analyticsScriptPath}
data-website-id={analyticsId}
data-cache="true"
data-host-url="https://eu.umami.is"
defer
onLoad={() => document.dispatchEvent(new Event('umami:loaded'))}
/>
)}
</>
)
}
export default Umami