Resource error verification
Stop ad-blocker noise from drowning out real CDN failures.
Sentry's browser SDK does not natively capture <img> / <script> / <link> load failures — those error events don't bubble. 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.
The @glitchreplay/network-probe integration solves this with two layered signals:
- 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 the 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 (CSP violation, decode error, transient outage) → 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, Ahrefs analytics) unconditionally — these are virtually always blocked and never represent an actionable failure.
- 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. Pass any URL on EasyList for fine-grained detection. |
verifyResourceErrors | [] | Strings (case-insensitive substring) or regexes against the failing URL. Hosts you've identified as yours. |
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 filtering to events you capture yourself. |
dropHosts | built-in tracker list | Hosts/patterns to drop unconditionally. Override to add or replace the defaults. |
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 — the original <img> error is real. |
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>. |
gr.target_host | hostname | Host of the failing resource. |
Recipes
Filter resource-error issues to "real failures only"
Use noiseAction: "drop" (the default) and let the integration filter at the source. Or use noiseAction: "tag" and configure an alert rule that ignores events with gr.noise:adblocker while still surfacing gr.probe:reachable.
Run alongside an existing handler
networkProbeIntegration({
captureResourceErrors: false,
verifyResourceErrors: ["cdn.acme.com"],
})The integration's processEvent still applies bait / probe to any event whose exception.values[0].type is "resource_error" and that has a URL on request.url or in the exception value.
Skip the tracker drop list
For B2B SaaS apps that have stripped third-party trackers entirely, override the default drop list:
networkProbeIntegration({
dropHosts: [],
verifyResourceErrors: ["cdn.acme.com"],
})Caveats
Corporate firewalls vs ad-blockers
Some corporate networks block static.doubleclick.net without an ad-blocker being installed. The integration still flags gr.adblocker:true in that case, which is usually 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 a host more specific to your app.
Probe leaks referrer
The verify probe sends a fetch with mode: "no-cors", cache: "no-store", credentials: "omit". No cookies, no body — but the request line still includes a Referer if your page emits one. Only list hosts you control on verifyResourceErrors.
No-fetch environments
If fetch is unavailable (very old browsers, sandboxed iframes that block it), bait simply never resolves, and verify probes skip and treat the host as reachable. No false positives, no thrown errors.