datlechin / flarum-link-clicks
Show a click count next to each link in a post.
Package info
github.com/datlechin/flarum-link-clicks
Type:flarum-extension
pkg:composer/datlechin/flarum-link-clicks
Fund package maintenance!
Requires
- php: ^8.3
- flarum/core: ^2.0
Requires (Dev)
- flarum/gdpr: ^2.0
- flarum/phpstan: ^2.0
- flarum/realtime: ^2.0
- flarum/tags: ^2.0
- flarum/testing: ^2.0
This package is auto-updated.
Last update: 2026-05-09 15:39:14 UTC
README
A Flarum extension that puts a click count next to every link in a post.
What it does
Every http(s) link grows a small badge once people start clicking. The badge inherits your theme and dark mode automatically. The number tells everyone reading the post how many people opened that link.
On top of the badge:
- Popular links sidebar widget on each discussion.
- Most clicked links widget on user profiles.
- Live updates when
flarum/realtimeis installed. Badges tick up without a page reload. - Admin analytics with filters, CSV export, and a per-link drill-down that shows who clicked. Daily clicks chart, top domains rollup, weekday-by-hour heatmap, and a mobile / tablet / desktop split.
- Per-discussion click stats. Mods get a "Click stats" item in the discussion controls dropdown, scoped to that thread.
- User click trail. Drill from a clicker into every link that user has opened.
- Webhook to forward click events. Exponential backoff retries, dedup header, and a "Send test ping" button.
- Console tooling: backfill, counter reconcile, daily rollup, anomaly detection, weekly digest.
- Domain blocklist and an optional confirm-before-leaving dialog for outbound clicks.
- Privacy controls: forum-wide skip-guests, per-user opt-out, author per-post toggle, tag-level opt-out (with
flarum/tags), and full GDPR export / anonymize / delete (withflarum/gdpr).
| Popular links sidebar | Most clicked links on profile |
|---|---|
![]() |
![]() |
Installation
composer require datlechin/flarum-link-clicks
Enable from Admin → Extensions.
Updating
composer update datlechin/flarum-link-clicks php flarum migrate php flarum cache:clear
Configuration
The extension page (Admin → Extensions → Link Clicks) has three tabs.
Settings
| Key | Default | What it does |
|---|---|---|
enabled |
true |
Master switch. Off means no badges and no recording. |
track_internal |
false |
Track links pointing back at the forum. Off keeps the focus on outbound traffic. Attachments are tracked regardless. |
min_display_count |
1 |
Hide the badge below this number. |
honor_dnt |
true |
Skip recording when the request carries DNT: 1. The redirect still works. |
skip_guests |
false |
Drop all guest clicks. Logged-in users only. |
dedup_window_hours |
24 |
A given user (or guest IP) only counts once per link in this window. |
event_retention_days |
90 |
Daily job removes click events older than this. Set to 0 to keep everything. |
bot_user_agents |
Extra User-Agent fragments treated as bots. One per line. | |
tracking_params_strip |
Extra query params to strip before counting. One per line. Trailing * matches a prefix. Defaults already cover utm_*, fbclid, gclid, mc_*, igshid, _ga and others. |
|
attachment_path_prefixes |
Extra URL path prefixes treated as attachments. One per line. /assets/files/ is built in. |
|
domain_blocklist |
Hosts to skip entirely. One per line. *.example.com matches every subdomain. Posts referencing these hosts get no badge and clicks aren't recorded. |
|
confirm_external_clicks |
false |
Show a browser confirm dialog when a reader clicks an external tracked link. |
digest_enabled |
false |
Mail every administrator a plain-text summary of the past week's clicks every Monday morning. |
anomaly_threshold_ratio |
10 |
Daily anomaly check logs a warning when the past 24 hours' click volume exceeds the prior six-day average by this ratio. |
anomaly_min_clicks |
20 |
Floor below which the anomaly check is skipped, so quiet forums don't fire on every blip. |
Webhook
Each recorded click is sent to your URL as a JSON POST. Toggle it on, paste a URL, optionally set a shared secret to sign the request body.
{
"event": "click_recorded",
"counted": true,
"post_link": { "id": 123, "url": "https://example.com/page", "is_internal": false, "is_attachment": false, "post_id": 456, "discussion_id": 789, "clicks_count": 42 },
"actor": { "user_id": 10, "username": "alice" },
"ip_address": "192.168.1.1",
"user_agent": "Mozilla/5.0 ...",
"clicked_at": "2026-05-09T12:34:56Z"
}
actor is null for guest clicks. counted is false when the click hit a dedup or self-click rule (the badge didn't tick up). When a secret is set, the signature is sent in X-LinkClicks-Signature: sha256=<hex>, computed over the raw body. Delivery is async and retried a few times on failure.
Permissions
Adds one permission: View link click analytics. Admins have it by default. Grant to other groups from Admin → Permissions.
Console commands
| Command | What it does |
|---|---|
link-clicks:backfill |
Registers links from posts that existed before the extension was enabled. Safe to re-run. --chunk=N, --from-id=X. |
link-clicks:reconcile |
Walks every tracked link and writes back any drift between the stored counter and the actual recorded events. --dry-run reports without writing. Daily-scheduled. |
link-clicks:build-daily-rollup |
Aggregates raw events into the daily rollup table that powers the time-series chart on large forums. First run backfills from the oldest event; subsequent runs resume. --rebuild wipes and recomputes. Daily-scheduled. |
link-clicks:detect-anomalies |
Logs a warning when the past day's click volume jumps versus the prior six-day average. Daily-scheduled. |
link-clicks:purge-events |
Removes click events older than the retention window. Daily-scheduled. |
link-clicks:send-digest |
Mails the weekly summary to administrators. Weekly-scheduled (Monday 06:00). |
Privacy and GDPR
The extension stores the IP address and User-Agent of each recorded click. Under GDPR these are personal data. As the forum operator you're responsible for:
- Disclosing the collection in your privacy notice.
- Choosing a lawful basis (legitimate interest is the usual fit for engagement analytics).
- Setting a retention window (the daily purge handles this).
- Honouring access and erasure requests. Install
flarum/gdprto expose them automatically.
Defaults that lean toward privacy: bots are dropped, DNT: 1 is honoured, authors can't inflate their own counts, the redirect URL never contains the destination.
Sponsors
If this extension is useful to you, sponsoring on GitHub helps me keep building and maintaining open source for Flarum.




