Bookmarklets

Bookmarklets are bookmarks that do something other than just linking to a web page (though they sometimes do that as well). They are pieces of software that run in your browser on the web page that is open when you click them. Like regular bookmarks, you can simply drag and drop the link to your bookmarks bar for use later, perhaps on a different web page.

Bookmarklet links always start with "javascript:" and, on this page, they have this pic beside them: For example, this link: Alert Title will popup an alert displaying the web page's title, which is useful if you want to copy it.

Isolation matters

I create & test bookmarlets in the console (F12) - refresh (F5), paste, execute, edit, repeat - but globally scoped variables can interfere with other scripts.

javascript: {/* linearized/minified code is safely scoped here */};

IF you use let not var. See also, this old PITA:(function(){})()

DoStuff(ThisURL) - location.href

Show on Remove Paywall
javascript:location.href='https://www.removepaywall.com/search?url='+location.href;
Show page in Steam
javascript:location.href='steam://openurl/'+location.href;
[-] Decrement url
javascript:let f=location.href.match(/^(.*?)(0*(\d+))([^\d]*)$/);if(f){location=(f[1]+(f[3]*1-1+'').padStart(f[2].length,'0')+f[4]);}
[+] Increment url
javascript:let f=location.href.match(/^(.*?)(0*(\d+))([^\d]*)$/);if(f){location=(f[1]+(f[3]*1+1+'').padStart(f[2].length,'0')+f[4]);}
[up] Parent path url
javascript:location.href=location.href.replace(/\/[^\/]+$/,'')
Deviantart Gallery -> RSS feed
javascript:location.href='https://backend.deviantart.com/rss.xml?q=gallery:'+location.href.match(/^(?:https:\/\/www\.deviantart\.com\/(?:watch\/)?)(\w+)/)[1]

Alert => can copy alert(location.href);

Reddit short link
javascript:alert('https://redd.it/'+location.href.split('/')[6]);
Alert Title
javascript:alert(document.title);

New Window(Stuff(ThisURL))

javascript:window.open(
  'https://DoStuff?q='+location.href,
  'window name/key'
);
Wayback Machine
javascript:window.open('https://web.archive.org/web/*/'+location.href,'waybackmachine');
TinEye search images
javascript:{window.open('http://tineye.com/search?url=location.href');}
Tumblr Gallery
... window.open('http://stone.dialog.jp/tumblr/gallery.html?user='+location.hostname.split('.',1)[0]+'&small=250&large=400&start=0#');
Tumblr Thumbnails
... window.open('http://tumb.la/'+location.hostname.split('.',1)[0]);

URL substitution

let a='URL1',
    b='URL2',
    l=location.href;
location.href=l.replace(b,a);
Youtube (new window)
javascript:{let a='watch?v=',b='embed/' ... window.open(l.replace(b,a));}

bi-directional ... location.href=( l.includes(b)? l.replace(b,a) : l.replace(a,b) );

Youtube <-> full frame
javascript:{let a='watch?v=',b='embed/';l=location.href;location.href=(l.includes(b)?l.replace(b,a):l.replace(a,b));}

Extracting(scraping) data

Open Inoreader article
javascript:window.open('https://www.inoreader.com/article/'+document.querySelector('div[data-oid].article_current').getAttribute('data-oid'));

InoReader uses jQuery => we can too javascript:window.open('https://www.inoreader.com/article/'+$('div[data-oid].article_current').attr('data-oid'));

Open multi-reddit of follows. (Old Reddit)
javascript:window.open('https://old.reddit.com/r/'+[...document.querySelectorAll('li>a.choice[href*="/user/"]')].map(e=>e.textContent.replace('/','_')).join('+'));
Open multi-reddit of follows. (New Reddit - open the list of feeds/follows first if not already docked to the left)
javascript:window.open('https://old.reddit.com/r/'+[...document.querySelectorAll('a[role="menuitem"][aria-label^="u/"]')].map(e=>e.textContent.replace('/','_')).join('+'));
Open multi-reddit of follows. (Both)
javascript:window.open('https://old.reddit.com/r/'+[...document.querySelectorAll(typeof header=='object'?'li>a.choice[href*="/user/"]':'a[role="menuitem"][aria-label^="u/"]')].map(e=>e.textContent.replace('/','_')).join('+'));

Fixes

Rotate Image
javascript:var a=prompt('Clockwise angle?','90');document.getElementsByTagName('img')[0].setAttribute('style','transform:rotate('+a+'deg);margin:auto;');
Fit image to width/height
javascript:{let i=document.getElementsByTagName('img')[0],b=document.body,r=b.clientWidth/i.width;if(r.toFixed(1)==1){r=b.clientHeight/i.height};i.width*=r;i.height*=r;}
Add links to Mitre 10 Search results
javascript:[...document.querySelectorAll('input[name=productSkuId]')].forEach(n=>n.insertAdjacentHTML('beforebegin', '<a href="https://www.mitre10.co.nz/shop/p/'+n.value+'">link</a>'));
Zap stylesheets
javascript:{[...document.styleSheets].forEach(x=>{x.disabled=true;})};

Blah selection in Blag

This is a pattern that's used a lot. E.g. "search for the selected text in <SearchEngine>" is so common, that it's in the context menu for most(all?) browsers.

//this get selection boilerplate covered a bunch of browser types and is probably not needed anymore.
let text = (
    ( window.getSelection && window.getSelection() )
  || 
    ( document.getSelection && document.getSelection() )
  ); 
if (text == '') {
  text = prompt('Blah?')
};
if (text) {
  DoStuff
}
else {
  DoOtherStuff
};

↪ (concise)

let w = window,
    g = w.getSelection,
    d = document.getSelection,
    t = ((g && g()) || (d && d()));
if (t == '') {
  t = prompt('Blah?')
};
if (t) {
  DoStuff
} else {
  DoOtherStuff
};

Whitespace is only needed to seperate letters (and readability).

↪ (linearized) javascript:{let w=window,g=w.getSelection,d=document.getSelection,t=((g&&g())||(d&&d()));if(t==''){t=prompt('Blah?')};if(t){DoStuff}else{DoOtherStuff}};

Regex replace: /s/(?<=\w)\s(?!\w)|(?<!\w)\s(?!\w)|(?<!\w)\s(?=\w)//

Code Beautify JS minifier

↪ (minified) javascript:{let w=window,g=w.getSelection,d=document.getSelection,t=g&&g()||d&&d();""==t&&(t=prompt("Blah?")),t?DoStuff:DoOtherStuff}

(original minified) javascript:{let text=window.getSelection&&window.getSelection()||document.getSelection&&document.getSelection();""==text&&(text=prompt("Blah?")),text?DoStuff:DoOtherStuff;}

No selection? => Prompt for parameter let t=((g&&g())||(d&&d())) ... if(t==''){t=prompt('Query?')};

Confirm address => can copy and/or not open let p = 'address' ... if(confirm(p)){window.open(p)};

encodeURIComponent = safe parameters let p = 'address' ... p = p+encodeURIComponent(t) ... if(confirm(p)){window.open(p)};

(select query) Let me Google that for you
javascript:{let p='https://letmegooglethat.com/?q=',w=window,g=w.getSelection,d=document.getSelection,t=((g&&g())||(d&&d()));if(t==''){t=prompt('Query?')};p=p+encodeURIComponent(t);if(confirm(p)){w.open(p)};}
(select query) DuckDuckGo
... p='https://duckduckgo.com/?q=' ...
(select query) The Movie Database
... p='https://www.themoviedb.org/search?query=' ...
Blah selection in Blag
->
↪ (select query) Blah selection in Blag
javascript:{let p='input',w=window,g=w.getSelection,d=document.getSelection,t=((g&&g())||(d&&d()));if(t==''){t=prompt('Query?')};p=p+encodeURIComponent(t);if(confirm(p)){w.open(p)};}
(select text) Create link to highlight text
... p=location.href+'#:~:text=' ... {t=prompt('Highlight text?')}; ...
(select hash) Create magnet link
... p='magnet:?xt=urn:btih:',n=prompt('Name?') ... {t=prompt('Hash?')};p=p+t+'&dn='+n; ...
(select text) Speak selection (TTS)
DoStuff: let s=w.speechSynthesis,m=new SpeechSynthesisUtterance(),f=function(){m.voice=s.getVoices().filter(function(voice){return /UK.*Fem/.test(voice.name)})[0];s.speak(m)};m.rate=m.pitch=1;m.text=t;if(!s.getVoices().length){setTimeout(f,500)}
or do something based on what is selected... Jira/CASD
javascript:{
  var f='PPPT-',
    p='Ticket Number?',
    w=window,
    x=w.getSelection,
    y=document.getSelection,
    z=((x&&x())||(y&&y())).toString().trim(),
    j='https://mohits.atlassian.net/browse/',
    c='https://servicescentre.moh.govt.nz/CAisd/pdmweb.exe',
    b='?OP=SEARCH+FACTORY=',
    a='+SKIPLIST=1+QBE.EQ.',
    s='ref_num=',
    d='chg';
  if(z==''){z=prompt(p)};
  if(!z){j=c};
  if(/^(\d{1,4})$/.test(z)){z=f+z;};
  if(/^(\d{5})$/.test(z)){j=c+b+d+a+d+'_'+s;};
  if(/^(\d{6})$/.test(z)){j=c+b+'cr'+a+s;};
  p=j+encodeURIComponent(z);
  if(confirm('Open? '+p)){
    w.open(p);
  };
}
  • Misc

    Edit page (Stop editing)
    javascript:document.body.contentEditable='true';document.designMode='on';
    Index of / gallery
    javascript:{
      let d=document,
          l=d.links,
          re=/.+\.(bmp|gif|jfif|jpe?g|png|svg|tiff|webp)/,
          h='<html><head><title>'+d.title
      +' gallery</title><style>img{max-width:15%;}</style></head><body><div>';
      for(i=0;i<l.length;i++){
        let p=l[i].href;
        if(p.toLowerCase().match(re)){
          h+='<img src="'+p+'"/>'
        }
      }
      h+='</div></body></html>';
      d.body.innerHTML=h;
    }
    Index of / full filenames
    javascript:[...document.links].forEach(a =>{
      if( a.text.endsWith('>') ) a.innerText=decodeURIComponent( a.href.split('/').pop() )
    })

    data: URI Bookmarklets

    These fit whole files into a bookmark - even a whole website. But you can't click them as links here, you need to drag them to your bookmark bar first. Browsers don't allow data: URIs in links anymore (for very valid security reasons!)

    Bookmark my Wiki Enter the encoded data (from PGh to D4=) into the base64 decoder here to see the html of the wiki itself.
    data:text/html;base64,PGh0bWw+PGhlYWQ+PHRpdGxlPkJvb2ttYXJrIG15IFdpa2k8L3RpdGxlPjxzY3JpcHQ+d2luZG93Lm9ubG9hZD1mdW5jdGlvbigpe2RvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdjJykuY29udGVudEVkaXRhYmxlPSd0cnVlJzt9PC9zY3JpcHQ+PHN0eWxlPiNje3BhZGRpbmc6LjVlbX08L3N0eWxlPjwvaGVhZD48Ym9keT48YSBocmVmPSJqYXZhc2NyaXB0OndpbmRvdy5sb2NhdGlvbj0nZGF0YTp0ZXh0L2h0bWw7YmFzZTY0LCcrYnRvYShkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQub3V0ZXJIVE1MKSI+ZW5jb2RlPC9hPiA8ZGl2IGlkPSJjIiBjb250ZW50ZWRpdGFibGU9InRydWUiPjxoMT5UaGlzIGlzIGVkaXRhYmxlLjwvaDE+PGRpdj5TdHVmZiBnb2VzIGhlcmUuPC9kaXY+PC9kaXY+PC9ib2R5PjwvaHRtbD4=

    Third-party JS injection.

    Just do the thing. Loads the do.js from this website and does whatever that does, which is a whole bunch of things depending on what webpage is open and/or what is selected. Most of which are described above but I only need to click one bookmark. 😎

    Do
    javascript:{
      let d=document,s;
      [
        'https://www.gible.net/do.js'
      ].forEach(
        u=>{
          s=d.createElement('script');
          s.src=u;
          d.body.appendChild(s);
        }
      )
    };
    do.js source: