Read LinkedIn Feed Posts and Post URLs

Site linkedin.comTask read-linkedin-feed-postsVersion v4Updated Oct 16, 2026Category social

Read visible LinkedIn feed posts or supplied activity and share URLs, returning post text, canonical activity URLs, author metadata, media references, and visible engagement counts. This skill was captured from a live agent session on linkedin.com and is published here as a reusable recipe for agents.

NoteSelectors and URL schemes drift as sites change. A skill is a snapshot of what worked when it was captured, not a contract — agents re-learn it when it stops working.

Read visible LinkedIn posts from the caller's approved authenticated browser profile. The caller may request the first {limit} eligible home-feed posts or provide exact activity URLs, including /feed/update/urn:li:activity:{id}/ and /posts/{author-slug}-...-share-{activity-id}-{token}/ URLs. Return canonical activity URLs, visible author metadata, complete currently rendered text, image references, video posters, and visible engagement counts. This is read-only; it does not like, share, comment, follow, connect, or publish.

Use Cases

Use when the caller wants to read post text and optionally preserve visible media or engagement data from exact LinkedIn posts or the rendered feed. For feed mode, interpret “top” as the first {limit} eligible posts in rendered order, not as a claim that they have the highest global engagement. Use supplied post URLs directly; never guess an activity ID or share token.

Automation Flow

  1. Use the caller's approved authenticated LinkedIn browser profile. Never enter credentials. Treat login redirects, consent gates, CAPTCHA, checkpoints, and security challenges as access failures.
  2. If {activity-urls} are supplied, navigate directly to each supplied canonical activity or /posts/ URL. Do not visit the feed or search for the posts. After domcontentloaded and a brief settling wait, run the evaluator below on each page and union results by activityUrn, preserving caller URL order.
  3. Otherwise navigate directly to https://www.linkedin.com/feed/ with waitUntil: "domcontentloaded". In the same browser-agent call, wait briefly, scroll in bounded increments to trigger lazy loading, and run the evaluator with {limit}. Stop after the requested number of eligible posts or when no more visible cards are available.
  4. If full text is explicitly required and a visible More or See more control exists, expand only that visible control before evaluation. Return only currently visible or page-metadata text and media references.

Evaluator for a loaded feed, /feed/update/, or /posts/ page:

(async ({limit=5}={})=>{
const sleep=ms=>new Promise(r=>setTimeout(r,ms)),clean=s=>(s||'').replace(/\s+/g,' ').trim(),visible=e=>!!e&&(e.offsetWidth||e.offsetHeight||e.getClientRects().length)>0;
const parseNum=v=>{const m=clean(v).match(/([\d,.]+)\s*([KkMm])?/);if(!m)return null;let n=parseFloat(m[1].replace(/,/g,''));if(!Number.isFinite(n))return null;const u=(m[2]||'').toLowerCase();if(u==='k')n*=1000;if(u==='m')n*=1000000;return Math.round(n)};
const meta=p=>document.querySelector(`meta[property="${p}"],meta[name="${p}"]`)?.content||null;
if(location.pathname==='/feed/'||location.pathname==='/feed')for(let i=0;i<4;i++){window.scrollBy(0,900);await sleep(700)}
const nodes=[...document.querySelectorAll('div.feed-shared-update-v2,article[data-urn*="activity"],[data-urn*="activity"]')],posts=[],seen=new Set();
for(const card of nodes){if(posts.length>=limit||!visible(card))continue;const raw=card.getAttribute('data-urn')||card.getAttribute('data-id')||card.querySelector('[data-urn*="activity"]')?.getAttribute('data-urn')||'',activityId=(raw.match(/urn:li:activity:(\d+)/)||raw.match(/(?:^|\D)(\d{15,})(?:\D|$)/)||[])[1]||([...card.querySelectorAll('a[href]')].map(a=>a.getAttribute('href')||'').join(' ').match(/-share-(\d{15,})-/)||[])[1]||null,activityUrn=activityId?('urn:li:activity:'+activityId):null;if(activityUrn&&seen.has(activityUrn))continue;if(activityUrn)seen.add(activityUrn);const actorMeta=clean(card.querySelector('.update-components-actor__sub-description,.update-components-actor__description')?.innerText).toLowerCase();if(/promoted|sponsored/.test(actorMeta))continue;const link=card.querySelector('a[href*="/feed/update/"],a[href*="/posts/"]'),time=card.querySelector('time,.update-components-actor__sub-description');const imgs=[...card.querySelectorAll('img')].map(i=>({src:(i.currentSrc||i.src).split('?')[0],width:i.naturalWidth||0,height:i.naturalHeight||0,alt:clean(i.alt)})).filter(x=>x.src&&!x.src.startsWith('data:')&&(x.width>=200||x.height>=200));const videos=[...card.querySelectorAll('video')].map(v=>v.poster||v.currentSrc||v.src).filter(Boolean);const reaction=clean(card.querySelector('.social-details-social-counts__reactions-count,.social-details-social-counts__social-proof-fallback-number,[aria-label*="reaction" i]')?.innerText),comments=clean(card.querySelector('[aria-label*="comment" i],.social-details-social-counts__comments button')?.innerText),reposts=clean(card.querySelector('[aria-label*="repost" i],.social-details-social-counts__item--truncated button')?.innerText);posts.push({activityUrn,url:activityUrn?`https://www.linkedin.com/feed/update/${activityUrn}/`:link?.href?.split('?')[0]||null,author:clean(card.querySelector('.update-components-actor__title span[aria-hidden="true"],.update-components-actor__name,.feed-shared-actor__name')?.innerText)||null,authorHeadline:clean(card.querySelector('.update-components-actor__description')?.innerText)||null,authorUrl:card.querySelector('a[href*="/in/"]')?.href?.split('?')[0]||null,postedAt:time?.getAttribute('datetime')||clean(time?.innerText)||null,text:clean(card.querySelector('.update-components-text,.feed-shared-update-v2__description,.feed-shared-text')?.innerText||card.innerText).slice(0,10000)||null,images:imgs,videoPosters:videos,engagement:{reactions:parseNum(reaction),reactionsRaw:reaction||null,comments:parseNum(comments),commentsRaw:comments||null,reposts:parseNum(reposts),repostsRaw:reposts||null}})}
if(!posts.length){const body=clean(document.body?.innerText||''),ogImage=meta('og:image'),ogTitle=meta('og:title'),ogDesc=meta('og:description'),m=location.href.match(/(?:activity:|share-)(\d+)/),id=m?.[1]||null,blocked=/uas\/login|authwall|sign in|join linkedin|checkpoint|captcha|security verification|consent/i.test(location.href+' '+body.slice(0,2000));if(id&&!blocked&&(ogTitle||ogDesc||ogImage)){const imgs=ogImage?[{src:ogImage.split('?')[0],width:0,height:0,alt:ogTitle||''}]:[];posts.push({activityUrn:`urn:li:activity:${id}`,url:`https://www.linkedin.com/feed/update/urn:li:activity:${id}/`,author:null,authorHeadline:null,authorUrl:null,postedAt:null,text:ogDesc||ogTitle||null,images:imgs,videoPosters:[],engagement:{reactions:null,reactionsRaw:null,comments:null,commentsRaw:null,reposts:null,repostsRaw:null}})}}
const body=clean(document.body?.innerText||'').slice(0,2000),blocked=/uas\/login|authwall|sign in|join linkedin|checkpoint|captcha|security verification|consent/i.test(location.href+' '+body)&&posts.length===0;return{success:!blocked,pageUrl:location.href.split('?')[0],count:posts.length,posts,blocked};
})({limit:{limit}})

Possible Friction Points

  • The direct feed route is https://www.linkedin.com/feed/; exact activity pages use https://www.linkedin.com/feed/update/urn:li:activity:{activity-id}/.
  • LinkedIn share pages use /posts/{author-slug}-...-share-{activity-id}-{token}/. Navigate directly when supplied and derive the activity ID only from the URL or rendered metadata; never invent the numeric ID or token.
  • Activity IDs are opaque. Construct an activity URL only from a caller-supplied URL or an activity URN read from the rendered DOM.
  • Feed cards are dynamically rendered, so bounded scrolling is needed in feed mode; direct activity and post pages need a short settling wait.
  • The same activity may match multiple selectors; deduplicate by urn:li:activity:{id}. Promoted or sponsored cards are excluded using visible actor metadata.
  • Text may be truncated behind a visible More or See more control. Expand only visible controls when full text is required, then rerun extraction.
  • The metadata fallback handles /posts/ pages that expose Open Graph fields without a rendered feed card; it returns only og:title, og:description, and og:image evidence.
  • Image URLs may contain resizing query parameters; removing the query preserves a stable LinkedIn-hosted media reference when possible. Do not fetch media from another origin.
  • Engagement values may be abbreviated or absent; retain raw visible strings and do not infer missing counts.
  • A login wall, consent page, CAPTCHA, checkpoint, or anti-automation challenge is an access failure, not an empty post.
  • Keep navigation and extraction read-only and same-origin. Do not collect credentials, cookies, tokens, private messages, or unrelated page content.

Call it

GET https://production-sfo.browserless.io/skills?token=TOKEN-HERE&domain=linkedin.com&task=read-linkedin-feed-posts