Fathom Analytics Playbook
This is the standard for using Selah Tools' existing Fathom setup across all current and future products.
Use this guide when you add:
- new apps or web properties
- new badges, embeds, QR flows, and share links
- outbound links (email, social, paid, partner)
- custom event tracking
Goals
- Track attribution consistently across all Selah surfaces.
- Keep analytics privacy-safe and aligned with Fathom requirements.
- Make attribution readable in one place without ad hoc naming.
What already exists in Selah
- Route Bible loads Fathom with a runtime-configurable site id and host allowlist.
- Route Bible URL flows support pass-through for
utm_*query parameters. - Route Bible
badge.jscan add attribution tags for badge-driven traffic. - Selah badges across apps append UTM parameters to
https://selah.toolslinks.
Required query parameter standard
Every outbound link that we want attribution for should include:
utm_source: machine-friendly source tag for traffic origin.utm_medium: channel type.
Canonical taxonomy
utm_source
Use lowercase snake case:
- allowed chars:
a-z,0-9,_ - normalize separators (
-,/, spaces) to_ - max length: 64 chars
- examples:
route_bible_buildereveryones_scripture_headerbadge_example_org_post_alpha
utm_medium
Use one of:
badgeqrshareemailsocialpaidapireferral
Privacy and compliance rules
Never send personal data in any UTM value.
Do not include:
- names
- email addresses
- phone numbers
- postal addresses
- IP addresses
- identifiers that can single out a person
If a value can identify a person, do not track it.
Implementation pattern (copy/paste)
ts
function normalizeSourceTag(input: string): string {
return input
.trim()
.toLowerCase()
.replace(/[^a-z0-9]+/g, "_")
.replace(/_+/g, "_")
.replace(/^_+|_+$/g, "")
.slice(0, 64);
}
function withSelahTracking(
baseUrl: string,
sourceBase: string,
medium: string,
): string {
const source = normalizeSourceTag(sourceBase);
const url = new URL(baseUrl);
url.searchParams.set("utm_source", source);
url.searchParams.set("utm_medium", medium);
return url.toString();
}Fathom script setup pattern
Use this for new surfaces that need pageview tracking:
html
<script
src="https://cdn.usefathom.com/script.js"
data-site="YOUR_SITE_ID"
data-spa="auto"
defer
></script>For SPAs, keep data-spa="auto" unless there is a concrete reason to change.
Event tracking pattern
Use events only for meaningful outcomes (not every click). Typical examples:
signup_startedsignup_completedcopy_snippetopen_in_appcheckout_startedcheckout_completed
Safe helper:
ts
function trackFathomEvent(eventName: string, value?: number): void {
const fathom = (window as unknown as { fathom?: { trackEvent?: (name: string, value?: number) => void } }).fathom;
if (!fathom?.trackEvent) return;
if (typeof value === "number") {
fathom.trackEvent(eventName, value);
return;
}
fathom.trackEvent(eventName);
}Standard use-case recipes
1) Selah badge on a product page
utm_medium=badge
2) QR link from slides or print
utm_medium=qr
3) Share-target and embedded badge flows
- add
utm_sourceandutm_mediumwhere outbound links are generated - preserve pass-through parameters across redirects and resolver flows
4) Email newsletters
utm_medium=email
5) Paid and partner traffic
utm_medium=paidorutm_medium=referral
QA checklist before shipping
- Click the tagged link and verify URL contains
utm_source+utm_medium. - Confirm redirect/resolver paths preserve attribution parameters.
- Confirm no personal data appears in any tracking parameter.
- Validate values follow naming conventions (lowercase snake case).
- Confirm Fathom dashboard shows expected UTM breakdown after traffic lands.
Change management
When adding new tracking:
- Reuse this taxonomy and helper pattern.
- Add or update tests if link-generation behavior changed.
- Document any new
utm_mediumor event names in this page. - Avoid one-off conventions per app.
This page is the source of truth for analytics tagging in Selah Tools.