# Visitor beacon — detect reachability per ISP from real visitors

The beacon reports, for each real visitor, whether a site was reachable — and maps
their IP to their ISP. This is the only free way to cover **Celcom & Digi**, and it
fills in every ISP your visitors actually use. Results merge into the dashboard Block
chips and the bot's `/status` automatically.

There are two snippets. Use the passive one everywhere; add the active one on one
safe page if you want a direct "blocked" verdict (not just "reachable").

---

## A) Passive beacon — put on EVERY monitored site (recommended)
One line, in the `<head>` or before `</body>` of each site you monitor:
```html
<script src="https://wbdb.info/domain-monitor/beacon.js" async></script>
```
- When the page loads, it reports **that site is reachable** for this visitor, tagged
  by their ISP. So you get live per-ISP reachability (Unifi, Maxis, Celcom, Digi, …).
- A blocked ISP shows up as its visitors **disappearing** (reachable hits stop coming).
- Zero config, no data read from the visitor — it only sends the hostname.
- Easy bulk install: add it once to a shared header/footer template, or via Google Tag
  Manager across all sites.

## B) Active "hub" beacon — optional, for a direct 🚫 blocked verdict
Put this on **one page that's always reachable** (e.g. a clean domain, or your main
site that's never blocked). It test-loads every monitored domain from the visitor's
browser and reports reachable/blocked — so a Celcom user who's blocked produces a
direct **Celcom: blocked** result.
```html
<script>
(function () {
  var BASE = 'https://wbdb.info/domain-monitor';
  fetch(BASE + '/api/beacon_targets.php').then(function (r) { return r.json(); }).then(function (hosts) {
    hosts.forEach(function (host) {
      var img = new Image(), done = false;
      function report(ok) {
        if (done) return; done = true;
        new Image().src = BASE + '/api/beacon.php?host=' + encodeURIComponent(host) +
                          '&reachable=' + (ok ? 1 : 0) + '&t=' + Date.now();
      }
      img.onload  = function () { report(true); };   // got the favicon = reachable
      img.onerror = function () { report(false); };  // failed = blocked/unreachable
      setTimeout(function () { report(false); }, 8000);
      img.src = 'https://' + host + '/favicon.ico?_b=' + Date.now();
    });
  }).catch(function () {});
})();
</script>
```
> The active test loads each site's `/favicon.ico`. Make sure your sites serve a
> favicon (most do) — a reachable site with no favicon would look "blocked". If a
> site lacks one, add any small favicon, or skip the active beacon for it.

---

## How results appear
- **Dashboard → Block column:** a per-ISP chip (🚫 / ✓) sourced from real visitors,
  merged with Globalping. Real-visitor data and agents take priority over remote probes.
- **Telegram bot → `/status <domain>`:** a "Block by ISP" line including beacon ISPs.
- Verdicts use the **last 48 h** of hits, so they reflect current reality.

## Privacy / cost
- The beacon sends only the hostname + reachable flag. IP→ISP is looked up server-side
  via the free ip-api.com and **cached**, so repeat visitors cost nothing.
- No paid services, no API keys.
