@glitchreplay/network-probe
v0.1.0
Published
Ad-blocker detection and resource-error verification for Sentry-compatible SDKs. Distinguishes real CDN failures from client-side network blocking before events hit GlitchReplay.
Downloads
331
Maintainers
Readme
@glitchreplay/network-probe
Ad-blocker detection and resource-error verification for any Sentry-compatible SDK. Stops client-side network blocking from drowning out real CDN failures in your issue dashboard.
Why
Sentry's browser SDK does not natively capture <img> / <script> / <link> load failures. When you add your own capture, ~80% of the resulting events are noise — ad-blockers, privacy extensions, and DNS filters (Pi-hole, NextDNS, Brave Shields) intercept image-CDN and asset-host requests at the network layer. None of those are bugs you can fix.
This integration adds two layered signals that distinguish noise from real failures:
- Boot-time bait — fetch a URL that is reliably on EasyList. If the request rejects, every subsequent event gets
tags["gr.adblocker"] = "true". Resource errors on hosts you've marked as "yours" are dropped (or tagged) without a second probe. - Per-URL probe — when a resource error is reported for a host you've marked as "yours" and bait did not flag the user, re-fetch the same URL via
fetch. If it fails too, it's blocked client-side → drop. If it succeeds, the original failure is real → keep withtags["gr.probe"] = "reachable".
Install
pnpm add @glitchreplay/network-probeUse
import * as Sentry from "@sentry/nextjs";
import { networkProbeIntegration } from "@glitchreplay/network-probe";
Sentry.init({
dsn: "<YOUR_DSN>",
integrations: [
networkProbeIntegration({
// Resource errors on these hosts are ambiguous and need probing.
verifyResourceErrors: [
"cdn.example.com",
/imagedelivery\.net/,
],
}),
],
});That's it. The integration:
- Runs the bait fetch once at startup.
- Installs a capture-phase
errorlistener ondocumentthat auto-captures<img>/<script>/<link>/<source>/<video>/<audio>failures. - Drops third-party tracker errors (Facebook, GTM, Hubspot, Clarity, etc.) unconditionally.
- For events on
verifyResourceErrorshosts: drops if bait flagged the user; otherwise probes the URL and drops or keeps based on the result.
Options
| Option | Default | Notes |
|---|---|---|
| baitUrl | https://static.doubleclick.net/instream/ad_status.js | Pass null to disable. |
| verifyResourceErrors | [] | Strings (case-insensitive substring) or regexes against the failing URL. |
| noiseAction | "drop" | "drop" filters silently. "tag" keeps the event with tags["gr.noise"] set to "adblocker" or "tracker". |
| captureResourceErrors | true | Disable if you already have your own resource-error handler. The processEvent half still applies bait/probe to events you capture yourself. |
| dropHosts | built-in tracker list | Hosts/patterns to drop unconditionally. Override to add or replace. |
| fetchTimeoutMs | 4000 | Timeout for bait + probe fetches. |
Tags surfaced on events
| Tag | Values | Meaning |
|---|---|---|
| gr.adblocker | "true" / "false" | Bait probe result. Set on every event after bait completes. |
| gr.probe | "reachable" | Set when a per-URL probe succeeded for a verified host — meaning the original <img> error is real (CSP, decode, transient outage). |
| gr.noise | "adblocker" / "tracker" | Set when noiseAction: "tag" is used and the event was identified as noise. |
| gr.target_tag | element tag name | Auto-captured <img> / <script> / <link> etc. |
| gr.target_host | hostname | Host of the failing resource. |
Recipes
Filter resource-error issues to "real failures only" in the dashboard. Set up an issue rule to ignore events with gr.noise:adblocker or gr.adblocker:true, and surface those with gr.probe:reachable in alerts. Or use noiseAction: "drop" and let the integration filter at the source.
Run alongside an existing handler. Set captureResourceErrors: false. The integration's processEvent will still apply bait/probe filtering to any event whose exception.values[0].type === "resource_error" and that has a URL on request.url or in the exception value.
Custom drop list per project. The default tracker list is good for general consumer apps. For B2B SaaS where you've stripped the trackers entirely, override:
networkProbeIntegration({
dropHosts: [],
verifyResourceErrors: ["cdn.acme.com"],
});Don't trust doubleclick.net at the firewall. Some corporate environments block static.doubleclick.net without an "ad-blocker" being installed — the integration still flags gr.adblocker:true in that case, which is what you want (the user can't reach typical ad-blocker-targeted hosts, so they probably can't reach your image CDN either if it's on a similar list). If you need finer-grained detection, override baitUrl with something more specific to your CDN.
How it appears in GlitchReplay
Events flow through the same pipeline as any other Sentry event — same fingerprint, same dedup, same resolve / ignore / assign workflow. The gr.* tags are searchable in the issue list and usable in alert rules. If noiseAction: "drop" is set, filtered events never touch the wire — no ingest billing.
Why off-by-default for verification?
Bait detection costs one request per page and produces a useful signal even on customers who don't care about resource errors. Per-URL probing costs one extra request per failed resource (memoized per host per session), and it only makes sense for hosts the customer has explicitly identified as theirs — blanket-probing every URL would be expensive and would leak referrers to third-party domains.
