electerious / Ackee

Self-hosted, Node.js based analytics tool for those who care about privacy.
https://ackee.electerious.com
MIT License
4.27k stars 359 forks source link

Ackee counting unique page views on every page refresh #304

Open creotip opened 2 years ago

creotip commented 2 years ago

Ackee counting unique page on every page refresh. Using next.js with next following code in _app.tsx:

import { Box, ChakraProvider, useColorModeValue } from '@chakra-ui/react'
import type { AppProps } from 'next/app'
import Head from 'next/head'
import { DefaultSeo } from 'next-seo'
import { getSeo } from 'lib/getSeo'
import customTheme from 'configs/theme'
import { EmotionCache } from '@emotion/cache'
import { CacheProvider } from '@emotion/react'
import createEmotionCache from 'lib/createEmotionCache'
import { useRouter } from 'next/router'
import { ackeeConfig } from 'configs/ackee-config'
import { useEffect, useMemo } from 'react'
import * as ackeeTracker from 'ackee-tracker'

interface MyAppProps extends AppProps {
  emotionCache?: EmotionCache
}

const clientSideEmotionCache = createEmotionCache()
const { server, options, domainId } = ackeeConfig
function MyApp({
  Component,
  pageProps,
  emotionCache = clientSideEmotionCache,
}: MyAppProps) {
  const seo = getSeo()
  const mode = useColorModeValue('light', 'dark')
  const router = useRouter()

  let instance: any = useMemo(() => {
    if (typeof window !== 'undefined') {
      return ackeeTracker.create(server, options)
    }
  }, [])

  useEffect(() => {
    const attributes = ackeeTracker.attributes(options.detailed)
    const url = new URL(router.asPath, location as any)

    const { stop } = instance.record(domainId, {
      ...attributes,
      siteLocation: url.href,
    })
    return () => {
      stop()
    }
  }, [router.asPath])

  return (
    <CacheProvider value={emotionCache}>
      <ChakraProvider theme={customTheme}>
        <Head>
          <meta content="IE=edge" httpEquiv="X-UA-Compatible" />
          <meta content="width=device-width, initial-scale=1" name="viewport" />
          <link rel="icon" type="image/png" sizes="96x96" href="/favicon.png" />
          <meta
            name="google-site-verification"
            content="aTbQBMj8oiDmPHyuWHqMoxuv3NGKzHWCLV3rzlIJawo"
          />
          <Box
            as="meta"
            name="theme-color"
            content={mode === 'light' ? 'white' : '#141922'}
          />
        </Head>
        <DefaultSeo {...seo} />

        <Component {...pageProps} />
      </ChakraProvider>
    </CacheProvider>
  )
}

export default MyApp

⚙️ Environment

CookedApps commented 2 years ago

Which version of Ackee do you use? I have a similar problem, maybe it has something to do with it. See #305

electerious commented 2 years ago

This could have to do something with Vercel / serverless functions and the way Ackee generates the salt. A new one will be generated on every function invocation and the salt won't stay the same for the whole day like it does when used in a "normal" setup. I never thought about this and it's funny that no one complained about it so far.

I guess we need to find a way to generate a salt that is unique per day, but still different from user to user.

The current implementation: https://github.com/electerious/Ackee/blob/master/src/utils/salt.js

Ideas and PRs welcome.

Feuerhamster commented 2 years ago

We have a similar Issue with our site. We invoke the instance.record method of the tracker every time a user navigates on our page. In the Ackee dashboard, every single navigation from every user counts as a view. This doesn't seem like expected behavior.

Where can we see our unique visitors?

dottgonzo commented 2 years ago

same for me. This is the first time i use ackee, and i'm experiencing that if i reload the page it do a +1 on unique views

electerious commented 2 years ago

Can confirm the issue. It doesn't seem to be a Vercel / serverless function only issue. Will take a closer look at it on the weekend. Help is welcome!

electerious commented 2 years ago

Looks like we missed an important detail in the mongoose upgrade guide when we updated mongoose (#291). The unique visitor count and anonymisation is broken* since 3.2.0. I've pushed a fixed to the develop branch and will do some testing so I can release a hotfix tomorrow.

The unique visitor count might still be broken in serverless environments and we need a better way to generate a daily, but unique salt: https://github.com/electerious/Ackee/blob/master/src/utils/salt.js

mathe42 commented 2 years ago

The unique visitor count might still be broken in serverless environments and we need a better way to generate a daily, but unique salt: https://github.com/electerious/Ackee/blob/master/src/utils/salt.js

We could just hash the current date concated with something instance specific (the ACKEE_USERNAME?) and some value hardcoded.

electerious commented 2 years ago

@mathe42 That could work. It just feels a bit weird to use ACKEE_USERNAME for that, but the salt is never exposed, so it shouldn't be a security issue. Maybe it's also an option to add something like ACKEE_SALT.

electerious commented 2 years ago

Fixed in v3.3.1 (for non serverless environments).