prevent-window-open

Description

Intercepts window.open calls whose arguments match a pattern and neutralises them — the tool for forced pop-ups and pop-unders. A prevented call returns null, or optionally a decoy pop-up handle, so a page that inspects the returned window cannot tell that the call was blocked. Calls that do not match are passed through to the native window.open, so legitimate pop-ups (sign-in flows, print dialogs, document viewers) keep working. The wrapper preserves the native property descriptor and toString() output, so it is not identifiable by the usual toString() and descriptor checks.

Parameters

Name

Description

Mandatory

Default

pattern

Matched against all window.open arguments (URL, target, features) joined with spaces — there is no per-argument matching. /…/ is a regular expression and /…/i a case-insensitive one; no other flags are honoured. Anything else is matched as a literal substring. A leading ! inverts the match. An empty pattern matches every call, including window.open() with no arguments.

no

'' (matches every call)

delay

Milliseconds. When omitted, a prevented call returns null. When given, a decoy pop-up handle is returned instead and torn down after this many milliseconds.

no

none — null is returned

decoy

Fidelity of the returned handle: iframe, obj or blank. Inert unless delay is given. An unrecognised value raises an error and the filter is ignored, leaving window.open untouched.

no

iframe

Decoy modes

  • iframe (default) — the URL is loaded in a hidden 1×1 off-screen <iframe>, and the returned handle is a fake window object.

  • obj — the same, using an <object> element instead, for pages that watch for injected iframes.

  • blank — calls the native window.open with about:blank, so the handle is a genuine window. Highest fidelity against aggressive detectors, but a real empty window opens and is closed again after delay, which the user will see. Use it only when iframe and obj are detected.

Filter Examples

The filter parser keeps only \n, \r and \t as escapes, so \?, \. and \w do not survive into the pattern. Write patterns escape-free, using character classes such as [?], [.] and [^.]. For example /popunder|\?key=/ reaches the snippet as /popunder|?key=/, which is not a valid regular expression.

Filter

Result

prevent-window-open

Prevents every window.open call; each returns null.

prevent-window-open /popunder/

Prevents only calls whose arguments contain popunder; everything else opens normally.

prevent-window-open _blank

Literal match (no slashes): prevents calls whose arguments contain _blank anywhere — usually the target, but a URL carrying that text matches too.

prevent-window-open /[?&]key=/i

Case-insensitive regular expression against a tracking-key query parameter, written escape-free.

prevent-window-open /popunder/ 2000 obj

Prevented calls receive a decoy <object> handle, removed after 2000 ms.

prevent-window-open '' 2000

Match-all with a decoy: '' supplies the empty pattern so that delay lands in the right position.

prevent-window-open !/^https://([^.]+[.])?example[.]com/ 1000

Inverted: prevents every call not aimed at example.com, returning a decoy iframe removed after 1000 ms.

Debugging

#

Message

When

Meaning

1

Wrapped window.open

Once, when the first prevent-window-open filter installs the wrapper.

Wrapping succeeded. From this moment on, window.open calls are intercepted.

2

window.open not wrappable, bailing out (warning)

Instead of #1, when window.open is absent, is not a function, or has already been made non-configurable by the page.

Nothing is installed and the page keeps its own open. The filter has no effect.

3

Prevented window.open(<arguments>) followed by FILTER: prevent-window-open <arguments>

Each time a call matches a rule.

The call was prevented. Shows the joined arguments that were matched and which filter matched them.

4

Allowed window.open(<arguments>)

Each time a call matches no rule.

The call was passed through to the native window.open.

Notes

  • Several prevent-window-open filters on the same page share a single wrapper. Their rules are evaluated in the order the filters were applied, and the first match wins.

  • The snippet runs in the page's own JavaScript context and is applied per frame, so a filter for a domain also covers that domain's same-origin subframes when they are the ones calling window.open.