Skip to main content

JavaScript Modules

Network blocker

When you need it

The network blocker holds fetch and XMLHttpRequest calls that match a rule until the rule's category is allowed. Use it for requests you cannot move behind the script loader, such as a first-party events endpoint or a vendor SDK you bundle yourself.

Add rules

With @c15t/browser or createConsentRuntime, pass networkBlocker next to your other options:

networkBlocker: {
	rules: [
		{
			id: 'events',
			domain: 'example.com',
			pathIncludes: '/api/track',
			methods: ['POST'],
			category: 'measurement',
		},
	],
},

Rules start holding matching requests when the client or runtime is created, before start(), so a request sent early in your app still waits.

For a kernel you created yourself, attach the module:

src/network-blocker.ts
import type { ConsentKernel } from 'c15t';
import { createNetworkBlocker } from 'c15t/modules/network-blocker';

export const blockTracking = function blockTracking(kernel: ConsentKernel) {
	return createNetworkBlocker({
		kernel,
		onRequestBlocked: ({ method, url, rule }) => {
			console.info('Held back', method, url, rule?.id);
		},
		rules: [
			{
				category: 'measurement',
				domain: 'collect.example.com',
				id: 'collector',
			},
			{
				category: 'measurement',
				domain: 'example.com',
				id: 'events',
				methods: ['POST'],
				pathIncludes: '/api/track',
			},
		],
	});
};

createNetworkBlocker returns { dispose, updateRules, setEnabled }. updateRules(next) takes effect on the next request. setEnabled(false) keeps the patches but lets everything through. dispose() restores fetch and XMLHttpRequest. Dispose blockers in the reverse order you created them.

Rule fields

FieldRequiredWhat it does
domainYesThe host to match. Subdomains match too.
categoryYesThe category, or a condition, that lets matching requests through.
pathIncludesNoMatch only URLs whose path contains this text.
methodsNoMatch only these HTTP methods. All methods when omitted.
idNoA name shown in logs and passed to onRequestBlocked.
vendorNoAlso block while the visitor has turned this vendor off.
vendorId, iabPurposes, iabLegIntPurposes, iabSpecialFeaturesNoIAB conditions, checked only under an IAB policy.

Blocker options

OptionDefaultWhat it does
rulesrequiredThe rules.
enabledtruefalse keeps the configuration but blocks nothing.
logBlockedRequeststrueLog each blocked request with console.warn, as [c15t] blocked POST https://… (rule: events).
onRequestBlockednoneCalled with { method, url, rule } for each blocked request.

What a blocked request sees

  • A blocked fetch resolves with a 451 response. Check response.ok.
  • A blocked XMLHttpRequest aborts and fires an error event.
  • A request sent while the policy is still loading waits, then goes out or is blocked. If the policy fails to load, it is blocked.
  • A synchronous XHR cannot wait. While matching requests are held, a matching synchronous XHR throws a NetworkError.
  • When the blocker loads on demand and its chunk fails to load, requests its rules match are blocked, including ones already waiting for it, even for granted categories. Nothing can check consent for them. The chunk is tried again when the browser comes back online, and the blocker then decides requests as usual.
  • Requests that match no rule go out at once.

What it cannot block

It patches fetch and XMLHttpRequest in the page's own window. It does not cover navigator.sendBeacon, WebSockets, EventSource, requests from elements such as <img> and <script>, other frames, or service workers.

Check it works

  1. Send a matching request before any choice. The console logs [c15t] blocked … and the Network tab shows nothing.
  2. Allow the category and send it again. It goes out.
  3. Withdraw the category with reloadOnConsentRevoked: false. The next request is blocked again.