How Bookmarklets Work: Injecting Code into Any Webpage
In the previous article, I showed you this mysterious one-liner:
javascript:(function(){var s=document.createElement('style');s.innerHTML='*{background:#000!important;color:#0f0!important;outline:solid #f00 1px!important}';document.head.appendChild(s);})();
Save it as a bookmark, click it, and suddenly your page has debug outlines everywhere. But how does this actually work? And why does JavaScript code live in a bookmark?
Let's break it down.
What is a Bookmarklet?
A bookmarklet is executable JavaScript code stored as a browser bookmark. Instead of navigating to a URL, clicking the bookmark executes code on the current page.
The secret is the javascript: protocol prefix. According to MDN, these are "fake navigation targets that execute JavaScript when the browser attempts to navigate."
// Normal bookmark
https://example.com
// Bookmarklet
javascript:alert('Hello from a bookmark!')
That's it. Any valid JavaScript after javascript: will run in the context of the current page.
How the Browser Processes javascript: URLs
When you execute a javascript: URL, the browser:
- Parses and executes the script
- Evaluates its completion value (similar to
eval()) - If the completion value is a string, treats it as HTML and navigates to it
- If it's not a string, just executes the code without navigation
This is why simple expressions can replace your page content, while IIFEs (which return undefined) don't.
Breaking Down the Debug Bookmarklet
Let's dissect the CSS debug bookmarklet piece by piece:
1. The Protocol Prefix
javascript:
Tells the browser "execute this as JavaScript, don't navigate anywhere."
2. The IIFE Wrapper
(function(){
// code here
})();
An Immediately Invoked Function Expression (IIFE). This pattern:
- Keeps variables scoped (doesn't pollute the global namespace)
- Executes immediately
- Returns nothing (important - we don't want to navigate)
Without the IIFE, any return value would replace the page content. Try this:
javascript:'Hello'
Your page gets replaced with the text "Hello". The IIFE prevents this.
3. Creating a Style Element
var s = document.createElement('style');
Creates a new <style> element in memory. Not yet attached to the page.
4. Adding CSS Rules
s.innerHTML = '*{background:#000!important;color:#0f0!important;outline:solid #f00 1px!important}';
Sets the inner content of the <style> element to our CSS rules. This is the actual debug styling from the previous article.
5. Injecting into the Page
document.head.appendChild(s);
Appends the style element to <head>, making the CSS active immediately. The browser applies the styles and you see red outlines everywhere.
Why This Works
Bookmarklets have access to the same DOM and JavaScript APIs as the page itself. They run in the same security context, meaning they can:
- Access and modify the DOM
- Create and inject elements
- Read and modify variables
- Call functions defined on the page
- Access cookies and localStorage
- Make network requests
This makes them incredibly powerful for debugging, testing, and quick modifications.
The Full Flow
javascript: // 1. Tell browser to execute JS
(function(){ // 2. Start IIFE (prevents return value issues)
var s = document.createElement('style'); // 3. Create style element
s.innerHTML = '*{...}'; // 4. Add CSS rules
document.head.appendChild(s); // 5. Inject into page
})(); // 6. Execute immediately
Click the bookmark → Browser executes → Style injected → Debug outlines appear.
Creating Your Own Bookmarklets
Here are some interesting examples:
Remove All Images
javascript:(function(){document.querySelectorAll('img').forEach(img=>img.remove());})();
Outline All Links
javascript:(function(){document.querySelectorAll('a').forEach(a=>a.style.outline='2px solid red');})();
Edit Any Page
javascript:document.body.contentEditable=true;
This one doesn't even need an IIFE since it doesn't return a value.
Extract All Links
javascript:(function(){console.log([...document.querySelectorAll('a')].map(a=>a.href));})();
Logs all links to the console. Open DevTools to see the output.
Best Practices
1. Always use an IIFE
// Good
javascript:(function(){ /* code */ })();
// Bad - might replace page content
javascript:someCode()
2. Minify your code
Bookmarklets are stored as URLs. Keep them compact:
// Before minification
javascript:(function() {
var style = document.createElement('style');
style.innerHTML = '* { outline: 1px solid red }';
document.head.appendChild(style);
})();
// After minification
javascript:(function(){var s=document.createElement('style');s.innerHTML='*{outline:1px solid red}';document.head.appendChild(s);})();
3. Handle errors gracefully
javascript:(function(){
try {
// your code
} catch(e) {
alert('Error: ' + e.message);
}
})();
4. Use void operator for simple statements
MDN recommends using the void operator to prevent accidental navigation if a function returns a string:
// Without void - might navigate if someFunction() returns a string
javascript:someFunction()
// With void - guarantees no navigation
javascript:void someFunction()
// Also works with inline expressions
javascript:void(document.body.style.background='red')
The void operator evaluates the expression and returns undefined, ensuring the completion value is never a string.
Security Considerations
Bookmarklets run with full access to the current page. This means:
Safe:
- Bookmarklets you write yourself
- Bookmarklets from trusted sources that you've reviewed
Dangerous:
- Random bookmarklets from the internet
- Bookmarklets you haven't inspected
A malicious bookmarklet could:
- Steal cookies and session tokens
- Submit forms on your behalf
- Send your data to external servers
- Modify page behavior
Always review bookmarklet code before adding it to your bookmarks. It's just JavaScript - read it first.
Content Security Policy (CSP)
Some websites implement Content Security Policy headers that may block javascript: URLs from executing. If a site has a strict script-src directive, your bookmarklet might not work.
This is actually a security feature protecting users from XSS attacks, but it can also prevent legitimate bookmarklets. Most sites don't block them, but enterprise apps and security-focused sites might.
If your bookmarklet doesn't work on a particular site, check the browser console for CSP violations.
Browser Compatibility
Bookmarklets work in all major browsers:
- Chrome ✅
- Firefox ✅
- Safari ✅
- Edge ✅
Some mobile browsers restrict bookmarklets for security reasons, but desktop browsers fully support them.
Advanced: Multi-line Bookmarklets
For complex bookmarklets, write readable code first, then minify:
// Development version
(function() {
const debug = {
outline: () => {
const style = document.createElement('style');
style.innerHTML = '* { outline: 1px solid red !important }';
document.head.appendChild(style);
},
grid: () => {
document.body.style.backgroundImage =
'linear-gradient(rgba(0,0,0,.05) 1px, transparent 1px)';
document.body.style.backgroundSize = '10px 10px';
}
};
const action = prompt('Choose: outline or grid');
if (debug[action]) debug[action]();
})();
// Minified for bookmark
javascript:(function(){const debug={outline:()=>{const s=document.createElement('style');s.innerHTML='*{outline:1px solid red!important}';document.head.appendChild(s);},grid:()=>{document.body.style.backgroundImage='linear-gradient(rgba(0,0,0,.05) 1px, transparent 1px)';document.body.style.backgroundSize='10px 10px';}};const action=prompt('Choose: outline or grid');if(debug[action])debug[action]();})();
Use a JavaScript minifier or do it manually.
Conclusion
Bookmarklets are a powerful, underrated browser feature. They're essentially JavaScript snippets you can run on any page with a single click.
The debug outline bookmarklet from the previous article demonstrates the core concept: create an element, modify it, inject it into the DOM. But you can do so much more:
- Automate repetitive tasks
- Debug production sites
- Test responsive designs
- Extract data from pages
- Modify behavior without browser extensions
Next time you find yourself doing the same DevTools commands repeatedly, consider making a bookmarklet. It's JavaScript you already know, just packaged differently.
And remember: always review bookmarklet code before using it. You're giving it full access to the current page.