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

@ -103,7 +103,7 @@ jobs:
# check public_provider is true or not # check public_provider is true or not
echo "public_provider is ${{ inputs.public_provider }}" echo "public_provider is ${{ inputs.public_provider }}"
if [ "${{ inputs.public_provider }}" == "none" ]; then if [ "${{ inputs.public_provider }}" == "none" ]; then
make build make build
else else
make build-and-publish make build-and-publish
fi fi
@ -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

@ -134,7 +134,7 @@ jobs:
# check public_provider is true or not # check public_provider is true or not
echo "public_provider is ${{ inputs.public_provider }}" echo "public_provider is ${{ inputs.public_provider }}"
if [ "${{ inputs.public_provider }}" == "none" ]; then if [ "${{ inputs.public_provider }}" == "none" ]; then
make build make build
else else
make build-and-publish make build-and-publish
fi fi
@ -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

@ -136,7 +136,7 @@ jobs:
# check public_provider is true or not # check public_provider is true or not
echo "public_provider is ${{ inputs.public_provider }}" echo "public_provider is ${{ inputs.public_provider }}"
if [ "${{ inputs.public_provider }}" == "none" ]; then if [ "${{ inputs.public_provider }}" == "none" ]; then
make build make build
else else
make build-and-publish make build-and-publish
fi fi
@ -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

@ -10,27 +10,20 @@ Homebrew Computer Company is committed to protecting your privacy and ensuring t
## Data Collection ## Data Collection
Jan, Cortex, and all Homebrew Computer Company products do not collect personally identifying information. You can read about [our philosophy](/about#philosophy) here and audit our open-source codebases. Jan, Cortex, and all Homebrew Computer Company products do not collect personally identifying information. You can read about [our philosophy](/about#philosophy) here and audit our open-source codebases.
### When you voluntarily provide data ### When you voluntarily provide data
We -do- collect personal information you voluntarily provide us, e.g., when you sign up for our newsletter, join our Discord, or contact us via email. We -do- collect personal information you voluntarily provide us, e.g., when you sign up for our newsletter, join our Discord, or contact us via email.
### Jan ### Jan
Jan runs with privacy by default and is used 100% offline on your own computer. Your data (e.g., conversation history, usage logs) are stored locally and never leave your computer. Jan runs with privacy by default and is used 100% offline on your own computer. Your data (e.g., conversation history, usage logs) are stored locally and never leave your computer.
<Callout type="info"> <Callout type="info">
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