Here are some of the bookmarklets I've created or collected over the years for my personal use.
What are bookmarklets? They are basically bookmarks that execute javascript code when clicked instead of opening a website. Bookmarklets give you the power of javascript to do whatever you want (within the limits of your browser), so use it with care and only use bookmarklets you trust!
To install a bookmarklet, create a new bookmark and paste the code into the URL bar. See examples below, images taken from freeCodeCamp.
Alternatively, if the bookmarklet is available as a link, you can also drag and drop it to your bookmarks menu to install. Note that the JS code in the bookmarklet link might be different as it has been minified.
Only install bookmarklets from sources you trust and whenever possible, review the code before running it!
Deletes an element on click. Press the Esc key or right-click to exit, able to undo using Ctrl + Z or Cmd + Z (favorite bookmarklet thus far, fun to play with).
Thinking of adding some new fun features in the future, or maybe turn it into a browser extension.
delete-element.js
javascript: (() => {
let mouseX = 0;
let mouseY = 0;
const undo = [];
const handleMouseover = (e) => {
mouseX = e.clientX;
mouseY = e.clientY;
e.target.style.outline = 'dashed';
};
const handleMouseout = (e) => {
e.target.style.outline = '';
};
const handleClick = (e) => {
e.preventDefault();
const el = e.target;
const index = Array.from(el.parentElement.children).indexOf(el);
undo.push([el, el.parentElement, index]);
el.remove();
};
const unmount = () => {
document.elementFromPoint(mouseX, mouseY).style.outline = '';
document.body.removeEventListener('click', handleClick);
document.body.removeEventListener('mouseover', handleMouseover);
document.body.removeEventListener('mouseout', handleMouseout);
document.body.removeEventListener('keydown', handleKeydown);
document.body.removeEventListener('contextmenu', handleContextmenu);
};
const handleKeydown = (e) => {
if (e.key === 'Escape') {
e.preventDefault();
unmount();
}
if (e.key === 'z' && (e.ctrlKey || e.metaKey) && undo.length > 0) {
const [el, parentEl, index] = undo.pop();
el.style.outline = '';
parentEl.insertBefore(el, parentEl.children[index]);
}
};
const handleContextmenu = (e) => {
e.preventDefault();
unmount();
};
document.body.addEventListener('click', handleClick);
document.body.addEventListener('mouseover', handleMouseover);
document.body.addEventListener('mouseout', handleMouseout);
document.body.addEventListener('keydown', handleKeydown);
document.body.addEventListener('contextmenu', handleContextmenu);
})();
Deletes an element on click, one time only, no undo. Press the Esc key or right-click to cancel.
delete-element-one.js
javascript: (() => {
let mouseX = 0;
let mouseY = 0;
const handleMouseover = (e) => {
mouseX = e.clientX;
mouseY = e.clientY;
e.target.style.outline = 'dashed';
};
const handleMouseout = (e) => {
e.target.style.outline = '';
};
const unmount = () => {
document.elementFromPoint(mouseX, mouseY).style.outline = '';
document.body.removeEventListener('click', handleClick);
document.body.removeEventListener('mouseover', handleMouseover);
document.body.removeEventListener('mouseout', handleMouseout);
document.body.removeEventListener('keydown', handleKeydown);
document.body.removeEventListener('contextmenu', handleContextmenu);
};
const handleClick = (e) => {
e.preventDefault();
e.target.remove();
unmount();
};
const handleKeydown = (e) => {
if (e.key === 'Escape') {
e.preventDefault();
unmount();
}
};
const handleContextmenu = (e) => {
e.preventDefault();
unmount();
};
document.body.addEventListener('click', handleClick);
document.body.addEventListener('mouseover', handleMouseover);
document.body.addEventListener('mouseout', handleMouseout);
document.body.addEventListener('keydown', handleKeydown);
document.body.addEventListener('contextmenu', handleContextmenu);
})();
Ever want to remove all the CSS and images/videos/etc on a webpage? Well now you can with this amazing new bookmarklet! Removes img/svg/iframe/audio/video/canvas.
Why would you ever want to do that? Well, you can browse flashy websites without attracting the attention of others walking by (my current use case), and you can use it to see a before/after comparison of the website/webapp with and without CSS applied.
remove-css-media.js
javascript: (() => {
document.querySelectorAll('img').forEach((el) => {
el.replaceWith(`img_alt: ${el.alt}`);
});
document.querySelectorAll('svg').forEach((el) => {
el.replaceWith(
`svg_title: ${el.querySelector('title')?.textContent ?? ''}`
);
});
document
.querySelectorAll('iframe, audio, video')
.forEach((el) =>
el.replaceWith(`${el.tagName.toLowerCase()}_src: ${el.src}`)
);
document
.querySelectorAll('canvas')
.forEach((el) => el.replaceWith(`canvas_WxH: ${el.width}x${el.height}`));
document
.querySelectorAll('[style]')
.forEach((el) => el.removeAttribute('style'));
document
.querySelectorAll('style, link[rel="stylesheet"]')
.forEach((el) => el.remove());
})();
A collection of audio/video-related bookmarklets, works as long as the website uses audio/video tags. Applies to the first audio/video on the website, won't work for audios/videos inside an iframe.
Note: If you want to apply to a audio/video inside an iframe, use the iframe bookmarklet below to open the audio/video iframe in a new tab, then try the audio/video bookmarklet.
I was thinking of turning this into a browser extension to fix the iframe issue (see note above) but ended up using this extension instead. Thinking of forking it and making my own version sometime.
Creates a small audio/video playback controller fixed to the top right side of the screen, click the bookmarklet again to remove. Note that the controller buttons will be affected by the website's existing CSS.
Able to change playback speed, restart the audio/video, rewind or fast forward in 10s increments, play/pause, and mute/unmute the audio/video. The video controller is my most used bookmarklet when watching videos.
Note: Due to the use of innerHTML
, this bookmarklet will not work on sites that require TrustedHTML assignment (CSP). In such cases, use the other bookmarklets below instead.
Audio: aud-controller.js
javascript: (() => {
const audControl = document.querySelector('#audControl-div');
if (audControl) {
return audControl.remove();
}
if (!document.querySelector('audio')) {
return alert('No audio tags found');
}
const div = document.createElement('div');
div.id = 'audControl-div';
div.style.zIndex = '9999';
div.style.position = 'fixed';
div.style.top = '0%';
div.style.right = '0%';
div.style.display = 'flex';
div.style.gap = '0.2em';
div.style.padding = '0.1em';
div.style.userSelect = 'none';
div.innerHTML = `
<button id="ac-s" style="pointer-events: none;">${document
.querySelector('audio')
.playbackRate.toFixed(1)}x</button>
<button onclick="const aud = document.querySelector('audio'); aud.playbackRate -= 0.2; document.querySelector('#ac-s').textContent = aud.playbackRate.toFixed(1) + 'x'" style="cursor: pointer;">-</button>
<button onclick="const aud = document.querySelector('audio'); aud.playbackRate = 1; document.querySelector('#ac-s').textContent = aud.playbackRate.toFixed(1) + 'x'" style="cursor: pointer;">1x</button>
<button onclick="const aud = document.querySelector('audio'); aud.playbackRate = 2; document.querySelector('#ac-s').textContent = aud.playbackRate.toFixed(1) + 'x'" style="cursor: pointer;">2x</button>
<button onclick="const aud = document.querySelector('audio'); aud.playbackRate = 3; document.querySelector('#ac-s').textContent = aud.playbackRate.toFixed(1) + 'x'" style="cursor: pointer;">3x</button>
<button onclick="const aud = document.querySelector('audio'); aud.playbackRate += 0.2; document.querySelector('#ac-s').textContent = aud.playbackRate.toFixed(1) + 'x'" style="cursor: pointer;">+</button>
<button onclick="document.querySelector('audio').currentTime = 0;" style="cursor: pointer;">Restart</button>
<button onclick="document.querySelector('audio').currentTime -= 10;" style="cursor: pointer;">-10s</button>
<button onclick="const aud = document.querySelector('audio'); aud.paused ? aud.play() : aud.pause(); document.querySelector('#ac-p').textContent = aud.paused ? 'Play' : 'Pause'" id="ac-p" style="cursor: pointer;">${
document.querySelector('audio').paused ? 'Play' : 'Pause'
}</button>
<button onclick="document.querySelector('audio').currentTime += 10;" style="cursor: pointer;">+10s</button>
<button onclick="const aud = document.querySelector('audio'); aud.muted = !aud.muted; document.querySelector('#ac-m').textContent = aud.muted ? 'Unmute' : 'Mute'" id="ac-m" style="cursor: pointer;">${
document.querySelector('audio').loop ? 'Unmute' : 'Mute'
}</button>
<button onclick="const aud = document.querySelector('audio'); aud.loop = !aud.loop; document.querySelector('#ac-l').textContent = aud.loop ? 'Loop ON' : 'Loop OFF'" id="ac-l" style="cursor: pointer;">${
document.querySelector('audio').loop ? 'Loop ON' : 'Loop OFF'
}</button>
`;
document.body.appendChild(div);
})();
Video: vid-controller.js
javascript: (() => {
const vidControl = document.querySelector('#vidControl-div');
if (vidControl) {
return vidControl.remove();
}
if (!document.querySelector('video')) {
return alert('No video tags found');
}
const div = document.createElement('div');
div.id = 'vidControl-div';
div.style.zIndex = '9999';
div.style.position = 'fixed';
div.style.top = '0%';
div.style.right = '0%';
div.style.display = 'flex';
div.style.gap = '0.2em';
div.style.padding = '0.1em';
div.style.userSelect = 'none';
div.innerHTML = `
<button id="vc-s" style="pointer-events: none;">${document
.querySelector('video')
.playbackRate.toFixed(1)}x</button>
<button onclick="const vid = document.querySelector('video'); vid.playbackRate -= 0.2; document.querySelector('#vc-s').textContent = vid.playbackRate.toFixed(1) + 'x'" style="cursor: pointer;">-</button>
<button onclick="const vid = document.querySelector('video'); vid.playbackRate = 1; document.querySelector('#vc-s').textContent = vid.playbackRate.toFixed(1) + 'x'" style="cursor: pointer;">1x</button>
<button onclick="const vid = document.querySelector('video'); vid.playbackRate = 2; document.querySelector('#vc-s').textContent = vid.playbackRate.toFixed(1) + 'x'" style="cursor: pointer;">2x</button>
<button onclick="const vid = document.querySelector('video'); vid.playbackRate = 3; document.querySelector('#vc-s').textContent = vid.playbackRate.toFixed(1) + 'x'" style="cursor: pointer;">3x</button>
<button onclick="const vid = document.querySelector('video'); vid.playbackRate += 0.2; document.querySelector('#vc-s').textContent = vid.playbackRate.toFixed(1) + 'x'" style="cursor: pointer;">+</button>
<button onclick="document.querySelector('video').currentTime = 0;" style="cursor: pointer;">Restart</button>
<button onclick="document.querySelector('video').currentTime -= 10;" style="cursor: pointer;">-10s</button>
<button onclick="const vid = document.querySelector('video'); vid.paused ? vid.play() : vid.pause(); document.querySelector('#vc-p').textContent = vid.paused ? 'Play' : 'Pause'" id="vc-p" style="cursor: pointer;">${
document.querySelector('video').paused ? 'Play' : 'Pause'
}</button>
<button onclick="document.querySelector('video').currentTime += 10;" style="cursor: pointer;">+10s</button>
<button onclick="const vid = document.querySelector('video'); vid.muted = !vid.muted; document.querySelector('#vc-m').textContent = vid.muted ? 'Unmute' : 'Mute'" id="vc-m" style="cursor: pointer;">${
document.querySelector('video').loop ? 'Unmute' : 'Mute'
}</button>
<button onclick="const vid = document.querySelector('video'); vid.loop = !vid.loop; document.querySelector('#vc-l').textContent = vid.loop ? 'Loop ON' : 'Loop OFF'" id="vc-l" style="cursor: pointer;">${
document.querySelector('video').loop ? 'Loop ON' : 'Loop OFF'
}</button>
`;
document.body.appendChild(div);
})();
Toggles the default HTML5 audio/video controls and remove all controlsList
attributes.
Audio: aud-toggle-ctrl.js
javascript: (() => {
const aud = document.querySelector('audio');
if (!aud) {
return alert('No audio tags found');
}
aud.controls = !aud.controls;
console.log('ControlsList before overwrite:', aud.controlsList);
aud.controlsList = '';
console.log('ControlsList after overwrite:', aud.controlsList);
})();
Video: vid-toggle-ctrl.js
javascript: (() => {
const vid = document.querySelector('video');
if (!vid) {
return alert('No video tags found');
}
vid.controls = !vid.controls;
console.log('ControlsList before overwrite:', vid.controlsList);
vid.controlsList = '';
console.log('ControlsList after overwrite:', vid.controlsList);
})();
Changes the first audio/video's playback speed, should work with youtube/vimeo and etc, also shows the current playback speed.
Audio: aud-speed.js
javascript: (() => {
const aud = document.querySelector('audio');
if (!aud) {
return alert('No audio tags found');
}
const x = prompt(`Playback Speed? (Current: ${aud.playbackRate})`);
aud.playbackRate = parseFloat(x);
})();
Video: vid-speed.js
javascript: (() => {
const vid = document.querySelector('video');
if (!vid) {
return alert('No video tags found');
}
const x = prompt(`Playback Speed? (Current: ${vid.playbackRate})`);
vid.playbackRate = parseFloat(x);
})();
Useful if there are multiple audios/videos in a single page, changes the playback speed for all audios/videos.
Audio: aud-speed-all.js
javascript: (() => {
const aud = document.querySelectorAll('audio');
if (aud.length === 0) {
return alert('No audio tags found');
}
const x = prompt(`Playback Speed?`);
aud.forEach((a) => (a.playbackRate = parseFloat(x)));
})();
Video: vid-speed-all.js
javascript: (() => {
const vid = document.querySelectorAll('video');
if (vid.length === 0) {
return alert('No video tags found');
}
const x = prompt(`Playback Speed?`);
vid.forEach((v) => (v.playbackRate = parseFloat(x)));
})();
Able to play/pause the first audio/video, useful if audio/video controls are hidden but recommend to use the audio/video controller bookmarklet instead.
Audio: aud-play-pause.js
javascript: (() => {
const aud = document.querySelector('audio');
if (!aud) {
return alert('No audio tags found');
}
aud.paused ? aud.play() : aud.pause();
})();
Video: vid-play-pause.js
javascript: (() => {
const vid = document.querySelector('video');
if (!vid) {
return alert('No video tags found');
}
vid.paused ? vid.play() : vid.pause();
})();
Handy bookmarklet to check for iframes on a website.
Creates a set of buttons showing the iframe's source URL (opens in new tab when clicked) fixed to the top right side of the screen, click the bookmarklet again to remove the buttons. Note that the buttons will be affected by the website's existing CSS.
Note: Due to the use of innerHTML
, this bookmarklet will not work on sites that require TrustedHTML assignment (CSP). In such cases, use the other bookmarklets below instead.
iframe-panel.js
javascript: (() => {
const ipd = document.querySelector('#iframe-panel-div');
if (ipd) {
return ipd.remove();
}
const iframes = document.querySelectorAll('iframe');
if (iframes.length === 0) {
return alert('No iframes found');
}
const div = document.createElement('div');
div.id = 'iframe-panel-div';
div.style.zIndex = '9999';
div.style.position = 'fixed';
div.style.top = '0%';
div.style.right = '0%';
div.style.display = 'flex';
div.style.flexDirection = 'column';
div.style.gap = '0.2em';
div.style.padding = '0.1em';
div.style.userSelect = 'none';
div.style.maxWidth = '320px';
div.style.maxHeight = '320px';
div.style.overflow = 'auto';
let buttons = '';
iframes.forEach((i) => {
buttons +=
i.src === ''
? `<button style="pointer-events: none;">This iframe has no source</button>`
: `<button onclick="window.open('${i.src}', '_blank');" style="cursor: pointer; width: 100%; overflow-wrap: anywhere;">${i.src}</button>`;
});
div.innerHTML = `
<div style="display: flex;">
<button id="vc-s" style="pointer-events: none; flex-grow: 1;">\
${iframes.length} iframe(s) found, source(s) below
</button>
<button onclick="document.querySelectorAll('iframe').forEach(i => i.remove())" style="cursor: pointer; margin-left: auto;">
Remove all
</button>
</div>
<button id="vc-s" style="pointer-events: none; background: lightgray; border: none;">
Click the url(s) to open in new tab
</button>
${buttons}
`;
document.body.appendChild(div);
})();
Less versatile but works if the above bookmarklet doesn't.
iframe-alert.js
javascript: (() => {
const iframes = document.querySelectorAll('iframe');
if (iframes.length === 0) {
return alert('No iframes found');
}
let src = '';
iframes.forEach((i, idx) => (src += `${idx + 1}: ${i.src}, `));
alert(`${iframes.length} iframes found, ${src}`);
})();
Some bookmarklets that help with color sampling.
Uses the EyeDropper API, unfortunately it is not supported in Firefox and Safari at the time of writing (Dec 2023).
Also converts the HEX code to RGB and HSL values, code for converting RGB to HSL referenced from https://www.30secondsofcode.org/js/s/rgb-to-hsl/
color-eyedropper.js
javascript: (() => {
if (typeof window.EyeDropper === 'undefined') {
alert("Your browser doens't support the EyeDropper API");
return;
}
const x = new EyeDropper();
x.open()
.then((res) => {
const hex = res.sRGBHex;
const r = parseInt(hex.slice(1, 3), 16);
const g = parseInt(hex.slice(3, 5), 16);
const b = parseInt(hex.slice(5), 16);
const rgbToHsl = (r, g, b) => {
r /= 255;
g /= 255;
b /= 255;
const l = Math.max(r, g, b);
const s = l - Math.min(r, g, b);
const h =
s !== 0
? l === r
? (g - b) / s
: l === g
? 2 + (b - r) / s
: 4 + (r - g) / s
: 0;
return [
(60 * h < 0 ? 60 * h + 360 : 60 * h).toFixed(2),
(
100 * (s ? (l <= 0.5 ? s / (2 * l - s) : s / (2 - (2 * l - s))) : 0)
).toFixed(2) + '%',
((100 * (2 * l - s)) / 2).toFixed(2) + '%',
];
};
alert(
`Color is ${res.sRGBHex}, rgb(${r} ${g} ${b}), hsl(${rgbToHsl(
r,
g,
b
).join(' ')})`
);
})
.catch((e) => alert(`Error: ${e}`));
})();
Or alternatively, the bookmarklet below is an alternative if the EyeDropper API is not supported. It opens a color input element on a new popup window. Referenced from https://css-tricks.com/web-development-bookmarklets/#comment-1795325, lightly modified for readability and to set the popup on the bottom right corner.
color-popup.js
javascript: (() => {
const windowFeatures = `
popup,
width=100,
height=100,
left=${window.screen.availWidth},
top=${window.screen.availHeight},
`;
window.open('', '', windowFeatures).document.body.innerHTML =
'<input type="color">';
})();
Toggles designMode to make website editable.
toggle-designmode.js
javascript: (() => {
document.designMode = document.designMode === 'on' ? 'off' : 'on';
})();
Reads and displays your cookie data.
show-cookies.js
javascript: (() => alert(document.cookie || 'No cookies found'))();
Reads and displays your localStorage data.
show-localstorage.js
javascript: (() => {
if (window.localStorage.length === 0) {
return alert('No data in localStorage found');
}
let str = '';
for (let [k, v] of Object.entries(window.localStorage)) {
str += `key:${k}, val:${v}, `;
}
alert(str);
})();
Reads and displays your sessionStorage data.
show-sessionstorage.js
javascript: (() => {
if (window.sessionStorage.length === 0) {
return alert('No data in sessionStorage found');
}
let str = '';
for (let [k, v] of Object.entries(window.sessionStorage)) {
str += `key:${k}, val:${v}, `;
}
alert(str);
})();
Simple bookmarklet to center the webpage, limit the width, and change the line height. Usually only works on simple websites, might break certain websites.
simple-center.js
javascript: (() => {
b = document.body.style;
b.margin = '1em auto';
b.maxWidth = '80ch';
b.lineHeight = '1.5';
})();
Using html contenteditable to create an empty notepad to jot things down. To save your data, press Ctrl + S or save like a regular webpage, not the ideal but it works. Technically not a bookmarklet but a data URL instead.
Alternatively, you could use something like https://browserpad.org/ which saves your data to localStorage instead.
data:text/html, <html contenteditable='plaintext-only'>
data:text/html, <html contenteditable>
As the name implies, it's a bookmarklet that kills sticky content.
https://github.com/t-mart/kill-sticky
Here's a modified version I use that doesn't remove position fixed/sticky but makes them static instead.
kill-sticky-mod.js
javascript: (() => {
document.querySelectorAll('body *').forEach((node) => {
if (['fixed', 'sticky'].includes(getComputedStyle(node).position)) {
node.style.position = 'static';
}
});
document.querySelectorAll('html *').forEach((node) => {
const s = getComputedStyle(node);
if ('hidden' === s['overflow']) {
node.style['overflow'] = 'visible';
}
if ('hidden' === s['overflow-x']) {
node.style['overflow-x'] = 'visible';
}
if ('hidden' === s['overflow-y']) {
node.style['overflow-y'] = 'visible';
}
});
const htmlNode = document.querySelector('html');
htmlNode.style['overflow'] = 'visible';
htmlNode.style['overflow-x'] = 'visible';
htmlNode.style['overflow-y'] = 'visible';
})();
Cool bookmarklet that lets you 'destroy' websites.
Some useful bookmarklets for web development, more available in the comments section.
https://css-tricks.com/web-development-bookmarklets/
https://www.freecodecamp.org/news/what-are-bookmarklets/
https://gist.github.com/caseywatts/c0cec1f89ccdb8b469b1
https://make-bookmarklets.com/
If you would like to contribute to this project, feel free to:
- Raise an issue - Let me know if there's any bugs or bookmarklet request and I'll see what I can do.
- Create a pull request - If you want to get your hands dirty and fix/improve/add a new bookmarklet yourself, feel free to fork this repo and create a PR.
How to add a new bookmarklet to this repo:
- Fork or clone this repo and run
npm i
to install the required package, make sure you already have node.js installed. - Create a new
bookmarklets/bookmarklet-name.js
script for the bookmarklet you want to add. - Update
template/readme_template.md
to include a description and add@bookmarklet-name.js
on a new line after your description. - Run
npm run build
to generate the updatedREADME.md
andindex.html
with the new bookmarklet. - Create a PR.