Better Popunder JS
#1 Popunder Script on the market
Version 3.x.x includes fewer APIs, but it is more powerful and gives better results. The entire script has been rewritten.
Last updated: 2025/01/08
- Author: Phan Thanh Cong
- Email: [email protected] / [email protected] / [email protected]
- Official website: https://popunderjs.com / https://popunderjs.dev
Table Of Contents
Introduction
BetterJsPop is the #1 popunder script on the market, written in JavaScript by Thanh Cong since 2012. It was originally shared for free but was not updated frequently; in late 2015 it became a paid premium script, with many improvements.
- Opens pop-unders, pop-ups, tab-unders and tab-ups, and works on every desktop and mobile browser.
- Bypasses Adblock Plus.
- Supports multiple URLs, random URLs and hooks.
- Uses modern syntax and is very easy to set up.
- Filters mobile and desktop traffic.
- Supports asynchronous loading.
- Can bind to, or ignore, specific HTML tag names or DOM elements.
- Hides the traffic source.
- Comes with a complete API and documentation.
- And more.
About Bypass Adblock
Our script can open pops even when Adblock is enabled. Unfortunately, if your pop URL is on Adblock's blocklist, Adblock will close the pop window or tab right after it opens. We used to bypass this with a
redirectortrick, but Adblock has since updated its mechanism to work like uBlock Origin: it monitors the URLs of all tabs and windows and closes any that match its blocklist.If your pop URL is not on their blocklist, congratulations! You can use our script to open your pops even when Adblock is enabled.
Installation
To install the script, upload the following files to your server:
script.js and license.XX.js, where XX is a random number.
If you are working in a local environment, you can use local domains such as 127.0.0.1 or *.local to test the script.
Note:
license.XX.jsis your license file. We will email it to you after you have registered your domains with us. Do not use the license file included in updates or in the .zip file; it is only a demo license and does not work in a production environment.
For example, if your domain is domain.com, after uploading the files you will have the following links:
http://domain.com/script/script.js
http://domain.com/script/license.XX.js
Here is a basic setup to see how it works:
<script src="http://domain.com/script/script.js"></script>
<script src="http://domain.com/script/license.XX.js"></script>
<script>
BetterJsPop.add('http://example.com', {under: true, tab: false});
</script>
You can use our merger tool at https://popunderjs.com/merger.php to merge the script and the license file into one file, which makes uploading to your server easier. The tool also provides some tweaks to help the script run better.
Note: The page must be served over
http://orhttps://. Do not open your HTML file by double-clicking it; the script may not work with thefile://protocol.
Configuration
By default, the script uses
BetterJsPopas its variable name. You can change it to any name you want to avoid conflicts with other ad networks (many of our customers are ad networks). To change the variable name, addwindow.popns = 'YourOwnName'at the top ofscript.jsor before loadingscript.js. For example:<script>window.popns = 'YourOwnName';</script> <script src="http://domain.com/script/script.js"></script> <script src="http://domain.com/script/license.XX.js"></script> <script>YourOwnName.add('http://example.com');</script>
This is the manual method; you can also use our Merger Tool to do this.
The following config options are available, with their default values:
| Option | Type | Default |
|---|---|---|
prefix |
string |
BetterJsPop |
perPage |
integer |
-1 |
bindTo |
Array |
null |
ignoreTo |
Array |
null |
interval |
integer |
0 |
debug |
boolean |
false |
fallback |
Object |
{ under: true, tab: true } |
mobileSensitive |
integer |
15 |
noOpenner |
boolean |
true |
noReferrer |
boolean |
false |
allowScrollbar |
boolean |
true |
allowPopUnderTrick |
boolean |
true |
blankAnchor |
string |
TAB_UNDER |
To use these options, pass them to .config().
For example:
BetterJsPop.config({
debug: true,
perPage: 5
});
Option: perPage
In earlier versions this option was named perpage; both names work in version 3.
Limits the number of pops per page load. The default is -1 (no limit). You can add multiple URLs to the stack using .add(), and the script will open them one after another, one per user click.
Option: bindTo
An array of query selectors or DOM elements. The script will only open a pop when the user clicks one of these elements.
Option: ignoreTo
An array of query selectors or DOM elements. The script will not open a pop when the user clicks one of these elements.
Option: interval
In earlier versions this option was delay, in milliseconds; since 3.x it is expressed in seconds.
The number of seconds to wait between two pops, to avoid spamming users and "pop-up blocked" messages.
Option: debug
Enable this option to see log messages. Alternatively, use BetterJsPop.Logger.print() to print all queued messages.
Option: blankAnchor
WebKit only allows one pop or tab to be opened per click; more cannot be opened at once. If the user clicks a link with target="_blank", the script can open either the pop or that link, but not both.
IGNORE: The script does nothing when the user clicks a _blank anchor.
TAB_UNDER: Opens a tab-under: the link opens in the focused tab, and the pop URL opens in the tab underneath.
PREVENT: Opens the pop and prevents the link's default behavior.
Option: fallback
In earlier versions this option was named popFallbackOptions; both names work in version 3.x.
When a pop-under is not available, the script uses this option to open the pop.
The default is tab-under: { under: true, tab: true }.
You can change it to pop-up with { under: false, tab: false },
or to tab-up with { under: false, tab: true }.
Option: mobileSensitive
mobileSensitive controls our fast-click technique. If the user scrolls only a short distance, the script may treat it as a click and open the pop quickly.
The default value is 15. Larger values are more sensitive and can trigger a pop while the user is scrolling.
The value should be a number from 5 to 30. Do not set it higher than 30.
Option: noOpener
A global setting that prevents the pop window from redirecting the main window through window.opener.location. You can override this setting for each pop.
Option: noReferrer
A global setting that hides the referrer. You can override this setting for each pop.
Option: allowScrollbar
In earlier versions this option was named coverScrollbar; both names work in version 3.x.
Allows the script to fire a pop when the user clicks the scrollbar. The default value is true.
Option: allowPopUnderTrick
Creates a small window and then moves it around. When the user clicks back on the main window, the small window becomes a pop-under.
Limit Domains For Unlimited Package
The unlimited package means any website can embed and use your script. If you want to prevent this and allow only certain domains, simply open your license file and add the following code at the top:
window[window.popns || 'BetterJsPop'].href = ['domain1.com', 'domain2.com'];
...
Add new pop
To add a new pop to the queue, use the .add() method.
BetterJsPop.add('http://example.com', {});
Pop Options {}
Each pop supports the following options:
name, typestring- The name of the pop window. Each pop has a unique name by default; you can change it if you want.
devicetypestring, default"any", accepted values"desktop","mobile"or"any"- Filters the traffic for the pop, for example when you want to open the pop only on
"mobile"or only on"desktop".
- Filters the traffic for the pop, for example when you want to open the pop only on
expirestypeintegerorDateTime, default: session- By default, pops are tied to the browser session, which means the user has to close their browser to get a new pop. You can change this to a number of seconds or a
DateTimevalue. (read more) - For example, to show the pop every 30 minutes, use
expires: 1800.
- By default, pops are tied to the browser session, which means the user has to close their browser to get a new pop. You can change this to a number of seconds or a
undertypeboolean, defaulttrue- Set this to
falseto open a pop-up instead.
- Set this to
tabtypeboolean, defaultfalse- Set this to
trueto use a tab instead of a new window.
- Set this to
shouldFiretypefunction(pop, event, target)- Lets you add your own logic to decide whether the pop should fire.
- Your logic runs after the main logic, so if the main logic decides not to fire the pop, returning
truewill not make it fire. - You can use this to open the pop only when the user clicks a specific element. (read more)
beforeOpentypefunction(pop), default: NOOP- Called before the pop is fired.
afterOpentypefunction(pop, popWin), default: NOOP- Called after the pop is fired.
popWinreferences the window object of the pop (when using a pop-up or pop-under).
noReferrertypeboolean, defaultfalse- Set this to
trueto hide the referrer for the pop URL.
- Set this to
noOpennertypeboolean, defaulttrue- Set this to
trueto hide the opener for the pop URL.
- Set this to
tabUnderUrltypestringorfunction(url), defaultnull- When using tab-under, use this hook to customize the URL of the new tab, for example to add extra parameters.
- You can also use the
width,height,topandleftoptions to customize the pop window's size and position.
Example: use pop options
Here is a basic example of how to use pop options:
BetterJsPop
.add('http://example.com/url1', {
under: true,
tab: false
})
.add('http://example.com/url2', {
device: 'desktop',
expires: 900, // open every 15 minutes. Note: the user still has to click the page content to get a pop
beforeOpen: function(pop) {
console.log('pop url', pop.url);
},
afterOpen: function(pop, popWin) {
console.log('after pop open', pop, popWin);
}
})
Example: shouldFire option
BetterJsPop.add('http://example.com', {
shouldFire: function(pop, event, target) {
return target === jQuery('#your-element')[0];
}
});
Pop option: expires
By default, the script uses a session cookie for each pop, so once a pop has fired, the user has to close the browser to get a new one.
You can also set expires to a DateTime or to an integer number of seconds.
To open a pop on every click, use expires: 0.
API
config() method
Configures the script. For all available options, see the Configuration section.
/**
* @param options object
* @return self
*/
BetterJsPop.config(options);
getConfig() method
Returns all options the script is currently using.
/**
* return object
*/
BetterJsPop.getConfig();
add() method
Adds a pop to the queue. The pop fires when the user clicks the page content.
/**
* @param url string|function
* @param options object or not defined.
* @return self
*/
BetterJsPop.add(url, options);
You can pass a function as the URL to get a random URL, or to run your own logic before the pop URL is determined.
Example with random URLs:
// Each time before this pop opens, the script calls the function to get a new URL.
BetterJsPop.add(function() {
var urls = [
'http://example.com/?url1',
'http://example.com/?url2'
];
return urls[Math.floor(Math.random() * urls.length)];
});
You can also call .add() multiple times to add more pops:
BetterJsPop.add('http://example1.com');
BetterJsPop.add('http://example2.com');
BetterJsPop.add('http://example3.com');
Or chain the calls like this:
// Remember: do not put `;` after each `add`
BetterJsPop
.add('http://example.com')
.add('http://example2.com')
.add('http://example3.com')
getStack() method
Returns all added pops.
/**
* @return array
*/
BetterJsPop.getStack();
emptyStack() method
Removes all added pops from the stack. This does not remove the cookie flags.
To remove the cookies as well, use the reset() method instead.
/**
* @return void
*/
BetterJsPop.emptyStack();
bindTo() method
Binds the pop to specific tag names or DOM nodes.
/**
* @param string|array|multiple arguments
* @return self
*/
BetterJsPop.bindTo(arguments);
Example:
// Bind the script to all <img> tags
BetterJsPop.bindTo('img');
// Bind to all <a> tags
BetterJsPop.bindTo('a');
// Bind to more than one tag
BetterJsPop.bindTo(['button', 'img']);
// or
BetterJsPop.bindTo('button', 'img');
// @since 2.5.16 - Selectors are supported
BetterJsPop.bindTo(['#id-of-element', '.class-of-elements']);
// To clear the bind/ignore list, use
BetterJsPop.bindTo(false);
To bind the script to all elements with a given class name:
jQuery(document).ready(function($) {
$('.your-class-name').each(function () {
BetterJsPop.bindTo(this);
});
});
ignoreTo() method
Works the same as bindTo(), but tells the script not to open a pop when the user clicks the ignored elements or DOM nodes.
/**
* @param string|array|multiple arguments
* return self
*/
BetterJsPop.ignoreTo(arguments);
getBindTo() method
/**
* @return array DOM elements
*/
BetterJsPop.getBindTo();
getIgnoreTo() method
/**
* @return array DOM elements
*/
BetterJsPop.getIgnoreTo();
reset() method
/**
* Deletes all cookies and flags so that pops can fire again without reloading the page.
*/
BetterJsPop.reset();
Logger API
Logger.log() method
/**
* Adds a message to the log. If debug mode is enabled, the message is also written to the console immediately.
* Accepts multiple arguments, like console.log().
*/
BetterJsPop.Logger.log(arguments)
Logger.print() method
/**
* Prints all log messages to the console.
*/
BetterJsPop.Logger.print();
Cookie API
Cookie.set() method
/**
* Sets a cookie.
*
* @param name string
* @param value mixed
* @param expires DateTime|integer number of seconds
* @param attributes object
*/
BetterJsPop.Cookie.set(name, value, expires, attributes);
Cookie.get() method
/**
* Gets a cookie by name.
*
* @param string
* @return string|null
*/
BetterJsPop.Cookie.get();
Cookie.remove() method
/**
* Removes a cookie by name.
*
* @param string name
*/
BetterJsPop.Cookie.remove(name);
Storage API
Storage.set() method
/**
* Sets a storage item.
*
* @param string name
* @param mixed value
*/
BetterJsPop.Storage.set(name, value);
Storage.get() method
/**
* Gets a storage item by name.
*
* @param string name
* @return string|null
*/
BetterJsPop.Storage.get(name);
Storage.remove() method
/**
* Removes an item by name.
*
* @param name string
*/
BetterJsPop.Storage.remove(name);
Storage.clear() method
/**
* Clears all storage items.
*
* @param name string
*/
BetterJsPop.Storage.clear();
Browser API
Browser.isLinux property
/**
* @type boolean
*/
BetterJsPop.Browser.isLinux;
Browser.isWin property
/**
* @type boolean
*/
BetterJsPop.Browser.isWin;
Browser.isMac property
/**
* @type boolean
*/
BetterJsPop.Browser.isMac;
Browser.isIOS property
/**
* @type boolean
*/
BetterJsPop.Browser.isIOS;
Browser.isAndroid property
/**
* @type boolean
*/
BetterJsPop.Browser.isAndroid;
Browser.isMobile property
/**
* @type boolean
*/
BetterJsPop.Browser.isMobile;
Browser.isWebkit property
/**
* @type boolean
*/
BetterJsPop.Browser.isWebkit;
Browser.isMozilla property
/**
* @type boolean
*/
BetterJsPop.Browser.isMozilla;
Browser.isChrome property
/**
* @type boolean
*/
BetterJsPop.Browser.isChrome;
Browser.isFirefox property
/**
* @type boolean
*/
BetterJsPop.Browser.isFirefox;
Browser.isSafari property
/**
* @type boolean
*/
BetterJsPop.Browser.isSafari;
Browser.isIE property
/**
* @type boolean
*/
BetterJsPop.Browser.isIE;
Browser.isEdge property
/**
* @type boolean
*/
BetterJsPop.Browser.isEdge;
Browser.isOpera property
/**
* @type boolean
*/
BetterJsPop.Browser.isOpera;
Browser.version property
/**
* Returns the browser's version number
* @type integer
*/
BetterJsPop.Browser.version;
Browser.longVersion property
/**
* Returns the browser's full version number
* @type string
*/
BetterJsPop.Browser.longVersion;
Browser.versionCompare method
/**
* Compares the current browser version with the given version.
* @return boolean
*/
BetterJsPop.Browser.versionCompare(operator, version);
Example:
BetterJsPop.Browser.versionCompare('>=', '10.5');
BetterJsPop.Browser.versionCompare('<', '60');