Every marketing dashboard has a clicks number. Few people can explain what it means, where it came from, or whether it can be trusted. This article walks through the anatomy of a click event, explains why raw counts lie, and gives you a measurement framework that survives contact with reality.
What a click actually is
A click event is recorded at the moment a redirect fires. The event captures metadata about that moment:
| Field | What it means | Privacy handling |
|---|---|---|
ipHash |
One-way hash of the visitor's IP | Raw IP never stored |
device |
mobile / tablet / desktop | Stored |
browser |
Chrome, Safari, in-app browsers | Stored |
os |
iOS, Android, Windows, macOS | Stored |
referrer |
The page the visitor came from | Stored, truncated |
bot |
Whether the request looked automated | Used for filtering |
createdAt |
Timestamp of the redirect | Stored |
Two properties of this event matter more than the rest: it is recorded server-side (so ad blockers can't erase it) and asynchronously (so analytics never slow the redirect).
Why raw counts lie
Run any public link through a few channels and you'll see the pattern: raw numbers are inflated, sometimes massively. The inflation comes from three sources:
- Crawlers and scanners. Googlebot, Bingbot, Ahrefs, security scanners, and uptime monitors all "click" links. They are not people and they never convert.
- Link previewers. Slack, iMessage, WhatsApp, Facebook, Discord, and Twitter all fetch your URL to render a preview card. One share on Slack can register five to ten preview hits — none of them humans.
- Accidental double counts. A person clicks, the page loads slowly, they click again. Each click is a real interaction but not a separate visitor.
The fix is bot filtering at ingest: heuristic user-agent matching (bot, crawl, spider, slurp, mediapartners, headless), plus device detection. yas.sh applies this to every event and exposes only filtered totals in the dashboard and API. The difference is routinely 30–40% — a raw count of 10,000 can be 6,500 real people.
The metric stack: from counts to decisions
A single number tells you almost nothing. The stack that works, in order:
1. Volume (filtered clicks). Did the campaign move at all? Compare against baseline.
2. Direction over time (daily series). Are clicks growing, flat, or decaying? A campaign that spikes and dies needs different treatment than one that builds steadily. The GET /api/v1/analytics/overview endpoint returns a daily series precisely for this.
3. Composition (devices, referrers, browsers). Where clicks come from decides what to fix:
device mobile 61% desktop 33% tablet 6%
referrer direct 44% twitter 21% newsletter 18% google 9% other 8%
61% mobile with a destination page that isn't responsive is a conversion problem, not a traffic problem. 44% direct usually means QR codes and printed materials are doing heavy lifting — measure them explicitly.
4. Conversion (destination-side). Clicks are inputs, not outcomes. Tag destinations with UTM parameters (build them properly) and compare click→purchase per channel. Conversion tracking shows the full setup.
Referrers: read them with care
Referrer data is best-effort by design. Browsers send Referer based on their own privacy policies; no-referrer policies, HTTPS-to-HTTP downgrades, in-app browsers, and QR scans produce empty referrers that show up as "direct". That's not a bug — it's the reality of a private web. The useful questions are:
- Is direct growing? → print/QR/SMS channels are working.
- Is twitter.com spiking on launch day? → your announcement landed.
- Is newsletter steady? → your list is healthy.
Privacy: analytics without surveillance
Click analytics can be built privacy-first without losing usefulness. The rules yas.sh follows are a good baseline:
- Hash IPs before storage — never store raw IPs.
- Don't set tracking cookies; the redirect itself is the measurement.
- No cross-site fingerprinting, no third-party scripts.
- Offer CSV export and full deletion of your events.
This is also why the marketing site runs no third-party analytics — measurement of your links is opt-in infrastructure, not ambient surveillance.
The workflow that produces trustworthy numbers
- Define the channel mix before launch — UTM taxonomy (template), QR for print, short links for digital.
- Check bot-filtered volume on day one; set a baseline.
- Watch the daily series, not the total — totals hide decay.
- Slice by device and referrer weekly; fix what the slices reveal.
- Close the loop with conversions at the destination.
Reading the dashboard like an analyst
The dashboard's overview screen is deliberately small: three cards and three breakdowns. Reading them in order turns the screen into a decision:
- Total links — the inventory. Flat or shrinking with healthy click growth means you're retiring dead links and keeping the library honest (organization workflow). Growing without click growth means link sprawl.
- Total clicks (30d, bot-filtered) — the momentum. Compare week-over-week, not month-over-month; the daily series shows the shape behind the number.
- Breakdowns — the diagnosis. Device mix tells you about the destination (a 61% mobile share on a non-responsive page is a conversion emergency, not an analytics question); referrer mix tells you about channels; browsers tell you about compatibility.
- Per-link views — the treatment. The links with the highest totals get the deepest look: recent events, series shape, and the A/B test next step.
The habit that compounds: every Friday, 15 minutes — write down the three numbers, note one anomaly, decide one action. After a quarter you have a decision log, not just a dashboard.
The API walkthrough
The same numbers, programmatically. The analytics endpoints return everything the dashboard renders:
# Totals + daily series + breakdowns (30d default, up to 90)
curl -H "Authorization: Bearer yas_live_..." \
"https://yas.sh/api/v1/analytics/overview?days=30"
# Per-link detail: recent events + lifetime total
curl -H "Authorization: Bearer yas_live_..." \
"https://yas.sh/api/v1/analytics/clx123?days=30"
const res = await fetch("https://yas.sh/api/v1/analytics/overview?days=30", {
headers: { Authorization: "Bearer " + process.env.YAS_KEY },
});
const { totalClicks, series, breakdowns } = await res.json();
Three integration patterns use these endpoints:
- Weekly report automation — a cron job pulls the overview, formats it, posts to Slack (automation guide).
- Threshold alerts — when
totalClickspasses a campaign milestone, notify the channel. - Data warehouse sync — pull daily series into the warehouse for cross-channel joins (conversion tracking).
Metrics that matter vs metrics that flatter
A short list of traps that make click dashboards lie:
| Trap | Why it lies | Fix |
|---|---|---|
| Raw (unfiltered) totals | Bots and previewers inflate 30–40% | Use bot-filtered numbers |
| Totals without series | Decay is invisible | Always pair totals with the daily series |
| Click-to-conversion ratio missing | Clicks ≠ outcomes | Join with destination conversions |
| Comparing across channels with different previewer mixes | Slack-heavy links look bigger | Compare like-for-like, or filter previewer noise consistently |
| Weekday-only comparisons | Weekend dips look like decline | Compare like days, or 7-day rolling windows |
The platform's own numbers are bot-filtered at ingest, which removes the first and worst trap. The rest are reading habits.
Conclusion
Raw clicks are a vanity metric; filtered clicks with composition and direction are a decision tool. The difference is infrastructure: ingest-time bot filtering, hashed IPs, daily series, and per-channel breakdowns — all of which are table stakes in a production link platform.
Start measuring properly: create your first link on the dashboard and open the analytics API docs — you'll have a trustworthy number within the hour.
