Skip to content

bug: uniqueViewers count in /api/analytics/overview is inflated — groupBy(['viewerId', 'viewerIp']) produces a Cartesian product, not a true distinct-viewer count #436

@Srejoye

Description

@Srejoye

Description:

The /api/analytics/overview endpoint computes unique viewer count via:

const uniqueViewersQuery = await app.prisma.cardView.groupBy({
  by: ['viewerId', 'viewerIp'],
  where: { ownerId: userId },
});
const uniqueViewers = uniqueViewersQuery.length;

Grouping by the composite key (viewerId, viewerIp) means a single authenticated viewer who visits from two different IP addresses generates two group rows, and an anonymous viewer (viewerId = null) with three different IPs generates three rows — all counted as separate unique viewers. The result can massively overcount uniqueness, especially for anonymous visitors where viewerId is null and viewerIp varies (mobile networks, VPNs, proxies).

The comment in the code even acknowledges that the correct query is COUNT(DISTINCT viewer_id), but the implemented workaround does not actually approximate that.

Affected file: apps/backend/src/routes/analytics.ts (lines 72–78)

Steps to reproduce:

  1. A logged-in viewer visits a profile from two different network connections (two IPs).
  2. uniqueViewers returns 2 for that single viewer.
  3. Ten anonymous web scrapers visiting from different IPs each increment the counter by 1, regardless of whether they are the same agent.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions