BIO.RE
Creator Analytics

Creator Traffic Sources

Top 15 referrer domains for the authenticated creator's bio page, with visit counts and percentage share. Direct visits show up as "direct".

GET /api/v1/creators/analytics/traffic โ€” ๐Ÿ”‘ Bearer ยท Rate limit: 60 req / minute

Returns the top 15 referrer domains driving traffic to the creator's bio page, plus each one's share of total visits. referrerDomain was extracted at session-create time (URL.hostname.replace('www.', '')); sessions with no referrer or an unparseable one show up under 'direct'.

Always 15 rows max. The SQL is LIMIT 15 โ€” there's no ?limit= knob. If you need a longer tail, fall back to the admin traffic-sources endpoint or aggregate client-side from the overview + trend data.

direct is the catch-all. Any session with referrer === null or a referrer that didn't parse as a URL became 'direct' at write-time. You'll always see it as a row when there's any direct traffic โ€” there's no separate "unknown" bucket.

percentage is rounded to whole integers. Math.round((visits / total) * 100) โ€” no decimals. The sum across rows can drift a percent or two from 100 due to rounding; don't render it as "100% pie" without normalizing client-side.

Request

Query parameters

ParamTypeDefaultNotes
daysinteger30Lookback window. Capped at 365.

Headers

HeaderRequiredNotes
Authorization: Bearer <accessToken>โœ“JwtAuthGuard.

Response

200 OK โ€” ApiResponseOf<CreatorTrafficDto>

{
  "success": true,
  "data": {
    "sources": [
      { "source": "instagram.com", "visits": 600, "percentage": 35 },
      { "source": "direct",        "visits": 280, "percentage": 16 },
      { "source": "youtube.com",   "visits": 150, "percentage": 9 }
    ]
  }
}

Item fields (sources[])

FieldTypeNotes
sourcestringReferrer domain (e.g. "instagram.com") or "direct".
visitsnumberSession count where referrerDomain matched (or was null/unparseable, mapped to "direct").
percentagenumberWhole-number percentage of total visits. Rows are sorted by visits DESC.

Errors

Same as overview โ€” 401 / 404 error.creator.not_found / 404 error.creator.bio_not_found / 429.

Side effects

  1. JwtAuthGuard + ThrottleGuard.
  2. getBioPageId(userId) (main DB โ†’ 404 if missing creator/bio page).
  3. analyticsDb.$queryRaw (Analytics DB):
    SELECT COALESCE("referrerDomain", 'direct') as source,
           COUNT(*)::int as visits
    FROM "AnalyticsSession"
    WHERE "bioPageId" = $bioPageId::uuid
      AND "startedAt" >= $since
    GROUP BY "referrerDomain"
    ORDER BY visits DESC
    LIMIT 15
  4. Compute total = sum(visits), then map each row to add percentage = Math.round((visits / total) * 100). 0 when total is zero.

Code samples

curl 'https://api.bio.re/api/v1/creators/analytics/traffic?days=30' \
  -H "Authorization: Bearer $ACCESS_TOKEN"
type TrafficSource = { source: string; visits: number; percentage: number };

async function getTraffic(
  accessToken: string,
  days = 30,
): Promise<{ sources: TrafficSource[] }> {
  const res = await fetch(
    `https://api.bio.re/api/v1/creators/analytics/traffic?days=${days}`,
    { headers: { Authorization: `Bearer ${accessToken}` } },
  );
  const json = await res.json();
  if (!res.ok || !json.success) throw new Error(json?.error?.message ?? 'Failed');
  return json.data;
}

Try it

GET
/api/v1/creators/analytics/traffic
AuthorizationBearer <token>

In: header

Query Parameters

days?string

Response Body

application/json

application/json

application/json

curl -X GET "https://loading/api/v1/creators/analytics/traffic"
{
  "success": true,
  "data": {
    "sources": [
      {
        "source": "instagram",
        "visits": 600
      }
    ]
  }
}
{
  "success": false,
  "error": {
    "code": "AUTH_UNAUTHORIZED",
    "message": "Invalid credentials",
    "i18nKey": "auth.login.invalid_credentials",
    "i18nVars": {
      "field": "email"
    },
    "details": [
      {
        "message": "email must be an email"
      }
    ],
    "correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }
}
{
  "success": false,
  "error": {
    "code": "AUTH_UNAUTHORIZED",
    "message": "Invalid credentials",
    "i18nKey": "auth.login.invalid_credentials",
    "i18nVars": {
      "field": "email"
    },
    "details": [
      {
        "message": "email must be an email"
      }
    ],
    "correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }
}

Source

SourcePathLines
Controllerapps/api-core/src/modules/analytics/creator-analytics.controller.ts64โ€“80 (traffic)
DTO (response)apps/api-core/src/modules/analytics/dto/analytics-client-response.dto.ts89โ€“92 (CreatorTrafficDto), 76โ€“85 (item shape)
Prisma modelpackages/prisma-analytics/prisma/schema.prismaAnalyticsSession.referrerDomain (line 59), index @@index([referrerDomain, startedAt]) (91)

On this page