~/.canonry/config.yaml on the server and never echoed back to the dashboard.
+ + Crawler hits and AI-referral arrivals pulled directly from server logs (Cloud Run, etc.). Independent of GA — useful when you need server-side evidence that GPTBot or ChatGPT-User actually hit a page. +
+No traffic sources connected for {activeProject}.
+Connect a Cloud Run service to start ingesting crawler and AI-referral hits from server logs.
+| Source | +Status | +Last sync | +24h crawler | +24h AI referral | +24h samples | ++ |
|---|---|---|---|---|---|---|
|
+ {source.displayName}
+ {source.sourceType} · {source.id.slice(0, 8)}
+ |
+
+ + {source.lastError} + + ) : null} + |
+ {relativeTime(source.lastSyncedAt)} | ++ {isLoading ? '—' : formatCompact(detail?.totals24h.crawlerHits ?? 0)} + | ++ {isLoading ? '—' : formatCompact(detail?.totals24h.aiReferralHits ?? 0)} + | ++ {isLoading ? '—' : formatCompact(detail?.totals24h.sampleCount ?? 0)} + | +
+
+ |
+
+ Showing {sources.filter((s) => s.status !== TrafficSourceStatuses.archived).length} active source{sources.length === 1 ? '' : 's'} for {projectName}.
+ Same shape as canonry traffic status {projectName} --format json.
+
Missing project name or source id in URL.
+Loading source…
+Could not load this source.
+ ++ {detail.sourceType} · project {projectName} · + {detail.id} +
+Latest sync run
++ {detail.latestRun.error} +
+ ) : null} +Events
++ {totals.crawlerHits} crawler · {totals.aiReferralHits} AI referral · over the selected window +
+ ) : null} +No events in this window.
+ ) : ( +Event rows
+| Hour | +Kind | +Identity | +Evidence / status | +Path | +Hits | +
|---|---|---|---|---|---|
| {formatHourLabel(event.tsHour)} | ++ {event.kind === TrafficEventKinds.crawler ? 'Crawler' : 'AI referral'} + | ++ {event.kind === TrafficEventKinds.crawler ? event.botId : event.product} + {event.operator} + | ++ {event.kind === TrafficEventKinds.crawler + ? `${event.verificationStatus} · HTTP ${event.status}` + : `${event.evidenceType} · ${event.sourceDomain}`} + | ++ {event.kind === TrafficEventKinds.crawler ? event.pathNormalized : event.landingPathNormalized} + | +{event.hits} | +