PHPackages                             datlechin/flarum-link-clicks - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. datlechin/flarum-link-clicks

ActiveFlarum-extension[Utility &amp; Helpers](/categories/utility)

datlechin/flarum-link-clicks
============================

Show a click count next to each link in a post.

v1.1.0(1mo ago)03MITPHPPHP ^8.3CI passing

Since May 8Pushed 1mo agoCompare

[ Source](https://github.com/datlechin/flarum-link-clicks)[ Packagist](https://packagist.org/packages/datlechin/flarum-link-clicks)[ Docs](https://nqd.vn)[ GitHub Sponsors](https://github.com/sponsors/datlechin)[ RSS](/packages/datlechin-flarum-link-clicks/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (2)Dependencies (6)Versions (4)Used By (0)

Link Clicks
===========

[](#link-clicks)

[![License](https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667)](LICENSE.md) [![Latest Stable Version](https://camo.githubusercontent.com/1df7087ba169c092ce874e641ab19d3e9ef605de2fbd0e9fc5a4ad0f1a59748d/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6461746c656368696e2f666c6172756d2d6c696e6b2d636c69636b732e737667)](https://packagist.org/packages/datlechin/flarum-link-clicks) [![Total Downloads](https://camo.githubusercontent.com/0bfe73de1bf2b8acaf54de5c46f8a9257dece0acb785d570fc15181808c85ba4/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6461746c656368696e2f666c6172756d2d6c696e6b2d636c69636b732e737667)](https://packagist.org/packages/datlechin/flarum-link-clicks)

A Flarum extension that puts a click count next to every link in a post.

[![Badge in a post](screenshots/badge.png)](screenshots/badge.png)

What it does
------------

[](#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/realtime` is 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 (with `flarum/gdpr`).

Popular links sidebarMost clicked links on profile[![Popular links widget](screenshots/popular-widget.png)](screenshots/popular-widget.png)[![Most clicked links on user profile](screenshots/user-widget.png)](screenshots/user-widget.png)Installation
------------

[](#installation)

```
composer require datlechin/flarum-link-clicks
```

Enable from Admin → Extensions.

Updating
--------

[](#updating)

```
composer update datlechin/flarum-link-clicks
php flarum migrate
php flarum cache:clear
```

Configuration
-------------

[](#configuration)

The extension page (Admin → Extensions → Link Clicks) has three tabs.

[![Admin analytics tab](screenshots/admin-analytics.png)](screenshots/admin-analytics.png)

### Settings

[](#settings)

KeyDefaultWhat 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

[](#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=`, computed over the raw body. Delivery is async and retried a few times on failure.

[![Drill-down: who clicked this link](screenshots/drilldown-modal.png)](screenshots/drilldown-modal.png)

### Permissions

[](#permissions)

Adds one permission: **View link click analytics**. Admins have it by default. Grant to other groups from Admin → Permissions.

Console commands
----------------

[](#console-commands)

CommandWhat 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
----------------

[](#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/gdpr` to 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
--------

[](#sponsors)

If this extension is useful to you, [sponsoring on GitHub](https://github.com/sponsors/datlechin) helps me keep building and maintaining open source for Flarum.

Links
-----

[](#links)

- [Packagist](https://packagist.org/packages/datlechin/flarum-link-clicks)
- [GitHub](https://github.com/datlechin/flarum-link-clicks)
- [Discuss](https://discuss.flarum.org/d/39223)

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance94

Actively maintained with recent releases

Popularity4

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity50

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 77.5% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

31d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/b5dca3124d040fb5f1e59100485f3a23e42e4e4b1c6d89c5d4cd3e79d95f574e?d=identicon)[Ngô Quốc Đạt](/maintainers/Ng%C3%B4%20Qu%E1%BB%91c%20%C4%90%E1%BA%A1t)

---

Top Contributors

[![datlechin](https://avatars.githubusercontent.com/u/56961917?v=4)](https://github.com/datlechin "datlechin (31 commits)")[![flarum-bot](https://avatars.githubusercontent.com/u/39334649?v=4)](https://github.com/flarum-bot "flarum-bot (8 commits)")[![ImgBotApp](https://avatars.githubusercontent.com/u/31427850?v=4)](https://github.com/ImgBotApp "ImgBotApp (1 commits)")

---

Tags

discussion

### Embed Badge

![Health badge](/badges/datlechin-flarum-link-clicks/health.svg)

```
[![Health](https://phpackages.com/badges/datlechin-flarum-link-clicks/health.svg)](https://phpackages.com/packages/datlechin-flarum-link-clicks)
```

###  Alternatives

[flarum/tags

Organize discussions into a hierarchy of tags and categories.

38744.9k133](/packages/flarum-tags)[flarum-lang/russian

Russian language pack for Flarum.

12127.5k](/packages/flarum-lang-russian)[flarum/pusher

See new discussions and posts in real-time using Pusher.

22378.5k4](/packages/flarum-pusher)[flarum/likes

Allow users to like posts.

18461.4k25](/packages/flarum-likes)[flarum/mentions

Mention and reply to specific posts and users.

18435.7k12](/packages/flarum-mentions)[flarum/sticky

Pin discussions to the top of the list.

10431.6k12](/packages/flarum-sticky)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
