Skip to content
← Public packages

@kody/fathom-analytics

Read Fathom Analytics site stats, aggregation reports, and current visitors.

AGENTS.md

120 lines · 3.5 KB · Markdown

@kody/fathom-analytics — agent notes

Human setup and intent live in README.md. This file is for agents: imports, smoke execute snippets, and edge cases. Secrets by name only — never paste token values. Do not disable live webhooks or jobs.

Auth

ItemValue
SecretFATHOM_ANALYTICS_API_TOKEN (user scope)
Placeholder{{secret:FATHOM_ANALYTICS_API_TOKEN|scope=user}}
HeaderAuthorization: Bearer …
API basehttps://api.usefathom.com/v1
Approved hostapi.usefathom.com

Prefill save URL: https://kody.codes/account/secrets/new?name=FATHOM_ANALYTICS_API_TOKEN&description=Fathom%20Analytics%20API%20token&allowedHosts=api.usefathom.com&scope=user

Import paths

Single export surface — root dispatcher plus named helpers from the same module:

ExportImport / call
root dispatcherkody:@kody/fathom-analytics
named helpersimport { smokeTest, listSites, aggregate, getSiteTrafficSummary, getCurrentVisitors, request, … } from 'kody:@kody/fathom-analytics'

Prefer static kody:@kody/fathom-analytics imports from execute. Do not lead with packages.invoke.

Dispatcher actions: overview (default), smokeTest, request, getAccount, getToken, listSites, getSite, listEvents, getEvent, aggregate, getCurrentVisitors, getSiteTrafficSummary.

Smoke test (read-only)

Costs 2 API requests (pageviews against the plan).

import { smokeTest } from 'kody:@kody/fathom-analytics'

export default async function main() {
	return await smokeTest()
	// => { token: { name, abilities, expiresAt }, siteCount, sites: [{ id, name }] }
}

Equivalent via dispatcher:

import fathom from 'kody:@kody/fathom-analytics'

export default async function main() {
	return await fathom({ action: 'smokeTest' })
}

Common snippets

Briefing-ready summary (costs 3 requests):

import fathom from 'kody:@kody/fathom-analytics'

export default async function main() {
	const access = await fathom({ action: 'smokeTest' })
	const siteId = access.sites?.[0]?.id
	if (!siteId) return { access, summary: null }
	return await fathom({
		action: 'getSiteTrafficSummary',
		siteId,
		days: 7,
	})
}

Top paths by pageviews:

import { aggregate } from 'kody:@kody/fathom-analytics'

export default async function main() {
	return await aggregate({
		siteId: 'SITE_ID',
		aggregates: 'pageviews,uniques',
		fieldGrouping: 'pathname',
		sortBy: 'pageviews:desc',
		limit: 20,
		dateFrom: '2026-07-01 00:00:00',
		filters: [{ property: 'pathname', operator: 'is like', value: '/blog/*' }],
	})
}

Current visitors:

import { getCurrentVisitors } from 'kody:@kody/fathom-analytics'

export default async function main() {
	return await getCurrentVisitors({ siteId: 'SITE_ID', detailed: true })
}

Edge cases

  • Every request counts as one pageview; prefer getSiteTrafficSummary over inventing three separate aggregations yourself.
  • Aggregation numeric fields are strings from the API; getSiteTrafficSummary converts them to numbers.
  • Aggregation data is accurate from March 2021 onwards; date_from / date_to use the site's reporting timezone.
  • request stays on https://api.usefathom.com/v1 and retries 429/5xx honoring Retry-After.
  • List helpers default to limit: 100 and surface hasMore plus cursor hooks (startingAfter / endingBefore).
  • No dedicated mutation helpers — use request only when the user explicitly asks to create/update/delete.