Sometimes I want to see all of the comments in a LinkedIn thread, for example to paste it into ChatGPT (or print or save it as a PDF and upload that) for analysis.
Update 28.Dec.2025: Replaced with:
https://www.jpw3.com/articles/2025/November/linkedin-control.html
Update 28.Nov.2025: See also:
To do this, first create a bookmarklet that will expand all the “More…” links for long comments. I got instructions and code here:
Register the bookmarklet (do this only once). For example, in Chrome:
- Press Ctrl+Shft+O to show the bookmark manager.
- Click the three dots at the top right to show the bookmark manager menu.
- Add a new bookmark named something like “Expand LinkedIn Comments” with the following for URL (code copied from adsmiths page linked above):
javascript:(function(){function simulatePointerClick(el){if(!el)return;el.focus();["pointerover","pointerenter","pointerdsomething own"ana,"pointerup","click"].forEach(evtName=>{var pe=new PointerEvent(evtName,{bubbles:true,cancelable:true,pointerType:"mouse",view:window});el.dispatchEvent(pe)})}function clickMoreButtons(){var buttons=document.querySelectorAll("button.feed-shared-inline-show-more-text__see-more-less-toggle");buttons.forEach(button=>{if(button.offsetParent===null)return;var span=button.querySelector("span");if(span){var txt=span.textContent.trim().toLowerCase();if(txt.indexOf("more")!==-1&&txt.indexOf("less")===-1){button.scrollIntoView({behavior:"smooth",block:"center"});setTimeout(()=>{console.log("Clicking button:",button);simulatePointerClick(button)},300)}}})}clickMoreButtons();var observer=new MutationObserver(mutations=>{mutations.forEach(mutation=> task {mutation.addedNodes.forEach(node=>{if(node.nodeType===Node.ELEMENT_NODE){if(node.matches&&node.matches("button.feed-shared-inline-show-more-text__see-more-less-toggle")){setTimeout(()=>{console.log("Clicking newly added button:",node);simulatePointerClick(node)},300)}else{var btns=node.querySelectorAll?node.querySelectorAll("button.feed-shared-inline-show-more-text__see-more-less-toggle"):[];btns.forEach(btn=>{setTimeout(()=>{console.log("Clicking newly added button (subtree):",btn);simulatePointerClick(btn)},300)})}}})})});oadsmithsbserver.observe(document.body,{childList:true,subtree:true});var interval=setInterval(clickMoreButtons,1000);setTimeout(()=>{clearInterval(interval);observer.disconnect();console.log("Stopped auto-clicking more buttons.")},300000)})();m
When you access this bookmarklet, the browser should invoke this JavaScript, which should expand all of the “More…” links.
Then:
- Open the LinkedIn post that you want to see. You can use the menu that appears when you click the three dots at the top of the post to copy its URL and then paste that into the address bar of a new browser tab.
- Click “Most relevant” and change it to “Most recent” so that LinkedIn will allow all of the comments to load.
- Repeatedly scroll to the bottom of the page until all comments load, possibly by holding the PageDown button on the keyboard. Update 20.Nov.2025: this step may be optional; the bookmarklet may do this automatically sometimes. Extensions can be dangerous, but I’m trying
https://chromewebstore.google.com/detail/auto-scroll-extension/ppkbgpllhklbjlmmncjjgogcdphkaaho now. - You may need to search for “previous replies” and/or “more replies” to expand those links.
- Press Ctrl+Shift+B to show the bookmarks bar, or otherwise trigger the bookmarklet.
Someone that knows front-end coding could probably add steps 2 through 4 to the bookmarklet.
Update 20.Nov.2025: I had ChatGPT write some code in an attempt to enhance this bookmarklet to:
- Change the “Most relevant” dropdown to “Most recent” before proceeding. If this is not possible, then generate a warning and halt if it is not already set to “Most recent”.
- Continually scroll to the bottom of the page and/or activate the “Load more comments” link until it stops appearing (all comments loaded).
- Activate any “See previous replies” and/or “More replies” links until none appear.
- Activate any “…more” links until none appear (existing logic to expand comments).
- If possible, hide everything on the page except the post and comments, preferably using entire page width (I want to print or copy without the sidebars)
- You can include “print now” and “pause” buttons, but print is not important and these should not appear on print output.
- Show a running count of clicks or comments loaded (optional)
Whoever does this work is welcome to implement additional enhancements that seem appropriate. At the very least, the existing “Stop” in this version should be “Pause”, and I haven’t tested much. The UI gets weird if I run the bookmarklet again, so maybe it should do nothing if Pause already appears.
- Short test case: https://www.linkedin.com/posts/yann-lecun_as-many-of-you-have-heard-through-rumors-activity-7397020300451749888-2lhA
- Long test case: https://www.linkedin.com/feed/update/urn%3Ali%3Aactivity%3A7269737472706703360
The updated code combined with the LinkedIn DOM seems to get bogged down on the long test case, which I leave running in a browser on a second monitor while working on my primary monitor. The long test case seems to take more time to load than the timeout allowed. Eventually, I think it crashed the browser (that thread has over 7,000 comments). It might be best to load all of the comments first and then expand links.
The margins still wider than they need to be.
It might be good to eliminate the arbitrary timeouts or make them shorter instead of waiting so long between. I would repeatedly try to load comments, wait maybe 100ms and try again until there is no “load comments” link for several seconds, and then load the previous and following comments, and then expand the more links.
If there is word-break: break-all anywhere, remove it.
Note: google gemini said that this script modifies the DOM often, and that might be what causes the browser to crash after loading many comments. It couldn’t fix it; attempts to do so just made it worse.
To reduce memory load in the browser for the long test case, the script might remove unnecessary things from the DOM, such as any images that appear in all comments.
I do not have a test case that shows the “More replies” links, so that may be irrelevant. Maybe when comments are sorted by date (“Most recent”), the most recent comments always appear first, in which case “More replies” might not be relevant. “More replies” may appear only before selecting “Most recent”. If this is the case, and the bookmarklet cannot change “Most relevant” to “Most recent”, then the bookmarklet could alert the user to change it and do nothing.
Maybe only enable Print Now after loading and expanding all comments or while paused.
javascript:(function(){
/* ============================================================
GLOBAL STOP FLAG
============================================================ */
let STOP=false;
/* ============================================================
BUTTON BAR (STOP + PRINT)
============================================================ */
function createControlButtons(){
const bar=document.createElement("div");
bar.style.cssText=`
position:fixed;
top:10px;
right:10px;
z-index:999999999;
display:flex;
gap:8px;
`;
const stopBtn=document.createElement("button");
stopBtn.textContent="STOP";
stopBtn.style.cssText=`
background:red;
color:white;
font-weight:bold;
border:none;
padding:10px 16px;
border-radius:6px;
cursor:pointer;
font-size:16px;
box-shadow:0 0 6px rgba(0,0,0,.3);
`;
stopBtn.onclick=function(){
STOP=true;
if(observer) observer.disconnect();
clearInterval(loopInterval);
stopBtn.style.background="#555";
stopBtn.textContent="Stopped";
};
const printBtn=document.createElement("button");
printBtn.textContent="PRINT NOW";
printBtn.style.cssText=`
background:#0066ff;
color:white;
font-weight:bold;
border:none;
padding:10px 16px;
border-radius:6px;
cursor:pointer;
font-size:16px;
box-shadow:0 0 6px rgba(0,0,0,.3);
`;
printBtn.onclick=function(){
STOP=true;
if(observer) observer.disconnect();
clearInterval(loopInterval);
window.print();
};
bar.appendChild(stopBtn);
bar.appendChild(printBtn);
document.body.appendChild(bar);
}
/* ============================================================
UTILITIES
============================================================ */
function simulatePointerClick(el){
if(!el) return;
el.focus();
["pointerover","pointerenter","pointerdown","pointerup","click"].forEach(evt=>{
el.dispatchEvent(new PointerEvent(evt,{bubbles:true,cancelable:true,pointerType:"mouse"}));
});
}
function clickIfVisible(selector, textMatch){
[...document.querySelectorAll(selector)].forEach(el=>{
if(STOP) return;
if(el.offsetParent===null) return;
const t=el.textContent.trim().toLowerCase();
if(!textMatch || textMatch(t)){
el.scrollIntoView({behavior:"smooth",block:"center"});
setTimeout(()=>simulatePointerClick(el),150);
}
});
}
/* ============================================================
1. MOST RECENT
============================================================ */
function setMostRecent(){
const btn=document.querySelector("button[aria-controls*='sort']") ||
document.querySelector("button.comments-sort-order-toggle");
if(btn){ simulatePointerClick(btn); }
setTimeout(()=>{
clickIfVisible("div[role='menuitem'],li[role='menuitem']",t=>t.includes("recent"));
},500);
}
/* ============================================================
2. AUTO-SCROLL + LOAD MORE COMMENTS
============================================================ */
function autoScrollAndLoad(){
if(STOP) return;
window.scrollTo(0,document.body.scrollHeight);
clickIfVisible("button",t=>t.includes("load more"));
}
/* ============================================================
3. EXPAND REPLIES
============================================================ */
function expandReplies(){
if(STOP) return;
clickIfVisible("button",t=>(
t.includes("previous replies") ||
t.includes("more replies") ||
t.includes("see more replies")
));
}
/* ============================================================
4. EXPAND “…MORE” INSIDE COMMENTS
============================================================ */
function expandMore(){
if(STOP) return;
const buttons=[...document.querySelectorAll("button.feed-shared-inline-show-more-text__see-more-less-toggle")];
buttons.forEach(btn=>{
if(btn.offsetParent===null) return;
const span=btn.querySelector("span");
if(span){
const t=span.textContent.trim().toLowerCase();
if(t.includes("more") && !t.includes("less")){
btn.scrollIntoView({behavior:"smooth",block:"center"});
setTimeout(()=>simulatePointerClick(btn),150);
}
}
});
}
/* ============================================================
5. CLEAN PRINT MODE — Remove Everything Except Thread
============================================================ */
function simplifyLayout(){
const css=`
body, html { overflow-x:hidden !important; background:white !important; }
/* Remove all junk */
header, nav, footer,
.global-nav,
.scaffold-layout__sidebar,
.scaffold-layout__aside,
.scaffold-layout__nav,
.msg-overlay-container,
#global-alert-container,
.application-outlet aside,
.right-rail, .left-rail,
.share-box-feed-entry__wrapper,
[data-test-global-nav-link],
.artdeco-toasts,
.artdeco-modal,
.modal,
.ember-view[role='dialog'] {
display:none !important;
visibility:hidden !important;
}
/* Main column to full width */
.scaffold-layout__main,
main {
width:100% !important;
max-width:100% !important;
flex:1 !important;
padding:0 20px !important;
}
`;
const style=document.createElement("style");
style.textContent=css;
document.head.appendChild(style);
}
/* ============================================================
MUTATION OBSERVER
============================================================ */
const observer=new MutationObserver(()=>{
if(STOP) return;
expandMore();
expandReplies();
autoScrollAndLoad();
});
/* ============================================================
ACTIVATE EVERYTHING
============================================================ */
createControlButtons();
simplifyLayout();
setMostRecent();
observer.observe(document.body,{childList:true,subtree:true});
const loopInterval=setInterval(()=>{
if(STOP) return;
expandMore();
expandReplies();
autoScrollAndLoad();
},1200);
/* Safety off-switch after 5 minutes */
setTimeout(()=>{
STOP=true;
observer.disconnect();
clearInterval(loopInterval);
},300000);
})();
https://deliverystack.net/2025/11/26/format-text-in-linkedin-comments/
LikeLike