Toolarity

Tampermonkey Auto Click Every 5 Seconds: 6 Cases I Tested

Fix Tampermonkey Published October 30, 2026

The script everyone starts with is four lines: setInterval, querySelector, click(), 5000. It works on a plain button. On real sites it often clicks once and then goes quiet, or keeps “clicking” while nothing happens, or never stops.

I tested it on Tampermonkey 5.5.0 in Chrome 154 against a local test page with six kinds of buttons: a normal one, one that React-style code replaces after every click, one that is disabled for 7 seconds after a click, one that only reacts to real user clicks, one that only listens for mousedown, and one that submits a form and reloads the page. The page counts every click it actually receives, so you can compare what the script thinks it did with what the page saw.

Short answer (Tampermonkey 5.5.0, Chrome 154, tested 2026-09-25):

What you seeCauseFix
Nothing happens at allChrome’s Allow User Scripts toggle is offTurn it on
First click, then nothing (no error)You saved the button once; the page replaced itLook the button up again on every tick
Some clicks are skippedThe button was disabled at that momentPoll often, click when it’s enabled
Script logs clicks, page ignores themThe page checks event.isTrustedNot fixable from a userscript
click() does nothing on a menuThe page listens for mousedown, not clickDispatch the full mouse event sequence
“Stop after 3” never stopsThe page reloads and your counter resetsStore the counter with GM_setValue
Only one click per minuteThe tab is in the backgroundKeep the tab visible

If your script doesn’t run at all, check the Allow User Scripts toggle first. I covered that step with screenshots in Tampermonkey script can’t find the element. By default it is off in Chrome 138 and later, and Tampermonkey only shows a banner on its dashboard.

The basic script

// ==UserScript==
// @name         Auto click every 5s
// @match        https://example.com/*
// @grant        none
// ==/UserScript==

setInterval(() => {
  const btn = document.querySelector('#go-btn');
  if (btn) btn.click();
}, 5000);

Replace @match with your page and #go-btn with your button’s selector (right-click the button, Inspect, then right-click the element in the Elements panel and choose Copy > Copy selector).

On a normal button this clicked at 5.0, 10.0 and 15.0 seconds after the page started loading, exactly 5 seconds apart in a visible tab (132 clicks in 11 minutes, every gap 5 seconds). Note that the first click comes after 5 seconds, not right away: setInterval waits one full interval before the first run.

The important detail is that querySelector is inside the timer. The first problem below is what happens when it isn’t.

Case 1: the first click works, then nothing

A very common variant looks up the button once and reuses it:

const btn = document.querySelector('#go-btn');   // looked up once
setInterval(() => {
  btn.click();
}, 5000);

On my “re-render” test page, which replaces the button with a new one after each click (the way a React or Vue list does when its data changes), the page counted one click. The script kept calling click() every 5 seconds, with no error in the console:

Test page in re-render mode. The page counted 1 click. The log shows the script clicking at 6.5 seconds with btn.isConnected = true, the page re-rendering the button at 6.6 seconds, and the script clicking again at 11.5 and 16.5 seconds with btn.isConnected = false.

btn.isConnected = false is the giveaway: the script is clicking an old button that is no longer on the page. The page never hears about it.

How badly this fails depends on how the page listens. When I attached the page’s click handler directly to the button, the old button still counted clicks (3 of 3), because the handler lives on the button object and still runs after the button is removed from the page. When the page listened on document, which is how React 17 and later attach events (to the root container), the old button counted nothing. So a script like this can work on one site and silently fail on another.

Fix: call querySelector inside the timer, as in the basic script. With that change the same re-render page counted 3 clicks in 17 seconds.

Case 2: some clicks are skipped

Many buttons disable themselves while a request is running. On my “cooldown” page the button is disabled for 7 seconds after each click. The basic script clicked at 5 seconds (counted), at 10 seconds (button disabled, no click event at all, not even an error), and at 15 seconds (counted):

Test page in cooldown mode. The page counted 2 clicks. Log: click 1 at 5.0 seconds, button enabled again at 12.0 seconds, click 2 at 15.0 seconds. The button is greyed out.

Calling click() on a disabled <button> does nothing. Your 5-second timer and the page’s cooldown drift in and out of step, so you get a click every 10 seconds, or every 15, depending on the timing.

Checking btn.disabled and skipping makes the script honest (it logged “button disabled, skipping” at 10 and 20 seconds) but still loses those turns. What worked better was checking often and clicking as soon as the button is ready, with at least 5 seconds between clicks:

let last = 0;
setInterval(() => {
  const btn = document.querySelector('#go-btn');
  if (!btn || btn.disabled) return;
  if (Date.now() - last < 5000) return;
  last = Date.now();
  btn.click();
}, 500);

On the same cooldown page this clicked at 1.1, 8.6 and 16.1 seconds: each time within half a second of the button being enabled again, 3 clicks in 16 seconds instead of 2.

Some sites fake a disabled state with a CSS class (is-disabled, aria-disabled="true") instead of the real disabled attribute. Check the button in the Elements panel and add that condition if needed.

Case 3: the script clicks, the page ignores it

Every click a userscript makes has event.isTrusted === false. Only real mouse and keyboard input from the user is trusted. A page can check this and ignore everything else, and my “trusted” test page does:

Test page in trusted mode. The page counted 0 clicks. Log: ignored click (isTrusted=false) at 5.0 and 10.0 seconds.

I didn’t find a way around this from a userscript, and there isn’t a setting in Tampermonkey for it: click(), dispatchEvent with a MouseEvent, and the full pointer/mouse event sequence from Case 4 all arrived with isTrusted=false in my tests. If a site does this, it is deliberately blocking automated clicks, and an auto-clicker is probably against its terms anyway.

Case 4: click() does nothing on menus and some games

element.click() fires only a click event. Some menus, drag handles and browser games react to mousedown or pointerdown instead. On my “mousedown” test page the basic script ran every 5 seconds and the page counted 0:

Test page in mousedown mode. The page counted 0. The log only shows the button being rendered at 1.0 seconds.

Sending the whole sequence of events that a real click produces fixed it:

function realClick(el) {
  for (const type of ['pointerdown', 'mousedown', 'pointerup', 'mouseup', 'click']) {
    const Ev = type.startsWith('pointer') ? PointerEvent : MouseEvent;
    el.dispatchEvent(new Ev(type, { bubbles: true, cancelable: true, view: window }));
  }
}

setInterval(() => {
  const btn = document.querySelector('#go-btn');
  if (btn) realClick(btn);
}, 5000);

Test page in mousedown mode after switching to realClick. The page counted mousedown 1 at 5.0 seconds and mousedown 2 at 10.0 seconds.

On a normal button, realClick still counted as exactly one click per tick (4 clicks in 21 seconds), so it’s safe to use everywhere. It won’t help with Case 3: these events are not trusted either.

Case 5: “stop after 3 clicks” never stops

If the button submits a form or otherwise reloads the page, your whole script starts over after every click, including its variables. This version is meant to stop after 3 clicks:

let clicks = 0;
const timer = setInterval(() => {
  if (clicks >= 3) return clearInterval(timer);
  clicks++;
  document.querySelector('#go-btn')?.click();
}, 5000);

On my “reload” page it never did. The log for 31 seconds, one block per page load:

[limit-memory] script starts, clicks = 0
[limit-memory] clicking, clicks = 1
page: form submitted, reloading
[limit-memory] script starts, clicks = 0
[limit-memory] clicking, clicks = 1
page: form submitted, reloading
...

The counter was back to 0 on every load; the page had been submitted 6 times when I stopped the test, and it would have kept going.

Fix: store the counter with GM_setValue, which Tampermonkey keeps across page loads. You need to grant both functions in the header:

// ==UserScript==
// @name         Auto click - stop after 3
// @match        https://example.com/*
// @grant        GM_getValue
// @grant        GM_setValue
// ==/UserScript==

const timer = setInterval(() => {
  const clicks = GM_getValue('clicks', 0);
  if (clicks >= 3) return clearInterval(timer);
  GM_setValue('clicks', clicks + 1);
  document.querySelector('#go-btn')?.click();
}, 5000);

Result on the same page: stored clicks 1, 2, 3 across three reloads, then “limit reached, stopped” on the fourth load. The page counted 3 submits.

The catch: the stored value never resets by itself. The next time you open the page, the script sees 3 and does nothing. If you want “3 per day”, put the date in the key, for example 'clicks-' + new Date().toDateString() (I didn’t run this across a real day change).

Adding @grant lines also runs your script in Tampermonkey’s sandbox instead of the page, so page variables like window.someAppObject need unsafeWindow.someAppObject. I show that difference in the SPA section of the element article.

Case 6: in a background tab it clicks once a minute

I opened two tabs with the basic script and left them for 11 minutes: one visible, one in the background.

TabClicksGap
Visible1325 s
Background225 s, then 60 s

(In the background tab the gap was 5 seconds for the first 56 seconds only.)

The background tab clicked at 6.1, 11.1 … 56.1 seconds, then at 79.1, 139.1, 199.1, 259.1 and so on, once a minute. That is Chrome throttling timers in hidden tabs to save battery, and a userscript can’t opt out of it: setInterval, setTimeout and the polling pattern from Case 2 are all timers.

In my headless test the switch to one per minute happened after about a minute in the background. The exact point may be different in a normal Chrome window, and other browsers throttle differently. What to do:

  • Keep the tab you’re automating visible. A separate window works if it isn’t minimized or covered (I tested windows being visible in headless mode, not window covering on a real desktop).
  • Don’t rely on exact timing in the background. If “every 5 seconds” matters, the tab has to stay in front.

What I’d do

  1. Check the Allow User Scripts toggle before debugging anything else.
  2. Look up the button inside the timer, every time.
  3. Check disabled (or the site’s disabled class) and poll every 500 ms instead of blindly clicking every 5 seconds.
  4. If click() does nothing, try the realClick sequence.
  5. If the page reloads, keep any counter or on/off state in GM_setValue.
  6. If the page ignores even realClick and logs isTrusted, stop: the site is blocking automation on purpose.

And be reasonable with it. Auto-clicking a “refresh” button on your own dashboard is fine; hammering someone else’s site every 5 seconds can get you rate-limited or break its terms of service.

Test setup and what this doesn’t cover

  • Tampermonkey 5.5.0, the version the Chrome Web Store update server delivered for Chrome 154 on 2026-09-25. I downloaded the package, checked that its signature and extension ID match the store listing (dhdgffkkebhmkfjojejmpbldmpobfkfo), and loaded it unpacked into a separate Chrome test profile. A normal install from the Chrome Web Store can behave differently, for example in how the Allow User Scripts toggle is set after installing.
  • Chrome 154.0.8037.57 in headless mode on macOS 15.3.1. Background throttling in particular may differ in a normal Chrome window. Not tested: Firefox, Edge, Safari, Violentmonkey, Greasemonkey.
  • All pages were local test pages that I wrote to reproduce each case, not real sites. Real sites combine these cases, for example a React button that is also disabled while loading.
  • Default Tampermonkey settings, except the interface language, which I set to English.