Timestamps and LinkedIn
I recently attended an interesting talk about the challenge of identifying the timestamp of social media publications and this made me look more in depth at LinkedIn timestamps.
LinkedIn Timestamps#
LinkedIn is quite frustrating in Open Source Investigations as it only provides a rough estimation of when a post or comment was published, like here just with a “1d” which means “1 day ago”:
That is of course not enough for investigations where the exact publication time is critical to establish a timeline of facts. Thankfully, Ollie Boyd made a really interesting discovery in the format of LinkedIn post’s URL.
You can get the specific URL of a publication by clicking on it and selecting “Copy Link to Post”. This gives you a URL like https://www.linkedin.com/posts/rightscon_the-call-for-proposals-for-rightscon-2026-activity-7357083005376458752-Lh8d/. What Ollie Boyd realized is that the number at the end of this URL contains a timestamp: if you take that number, and keep only the first 41 bits of it, you will get a Unix format timestamp. Let’s try that in python based on the code he provides on his repository:
In [1]: from datetime import datetime
In [2]: _id = 7357083005376458752
In [3]: first_41_bits = bin(_id)[2:43]
In [4]: timestamp_ms = int(first_41_bits, 2)
In [5]: print(datetime.fromtimestamp(timestamp_ms/1000))
2025-08-01 18:21:16.474000
This date is in local timezone and is around one day before the time at which I am writing this article.
Ollie published code in python and javascript and even made a little tool available to extract the timestamp from a URL:
Looking at LinkedIn DOM#
Now, it would be great to see if this date is available elsewhere than in the URL, let’s look at LinkedIn DOM. First we see that the part that contains the time itself doesn’t contain anything else than the mention of the relative date:
But looking above at the publication structure, we can see that this timestamp is also available in the attributes of the publication:
This is promising, we could maybe extract the data directly from there. After some testing (and some comments from the Bellingcat community), it turns out that this date is not always the publication date, but can also be date at which the post was republished by another account in the activity feed. The only way to be sure that it is the publication date is to be on a post page, and not in the activity feed. Sadly, I haven’t yet found any workaround to help with that issue. Technically it should be possible to reconstruct the post URL in the same way than the LinkedIn app is doing, but it is still not clear to me if this URL is generated from local data loaded with the activity feed or through a GraphQL query.
That said, we can also look at comments and see if they use the same kind of timestamp. Looking at a comment structure, we find here a pretty similar data parameter but that contains both the post id (that as seen above could be the republication time) and the comment id:
As there is no way to republish a comment, this comment id always gives us the comment publication time.
Adding LinkedIn to Uniform Timezone Extension#
Bellingcat has developed an interesting Chrome extension called Uniform Timezone that allows to extract timestamps in an easy and precise way from social media applications. Based on the information above, I have added support for LinkedIn publications (only in the publication page to avoid mistakes between publication and republication) and comments.
The structure of the plugin is really neat as it already provides an easy to use structure called Fixer to select timestamp objects in the DOM and extract their value. I first added a Fixer for the publication page:
{
name: 'Publication Timestamp',
selector: 'span.update-components-actor__sub-description > span',
attachTo: node => node,
timestamp: getPublicationTimestamp,
filterSelected: checkPostUrl,
label: 'publication',
url: _ => window.location.origin + window.location.pathname,
},
This Fixer will select the span element that contains the publication timestamp, and when the user hover over, it will run the getPublicationTimestamp code to extract the timestamp from the URL:
function getPublicationTimestamp(_) {
if (document.URL.startsWith('https://www.linkedin.com/posts/')) {
const linkedinURL = document.URL;
const regex = /(\d{19})/;
const postId = regex.exec(linkedinURL)?.pop();
if (postId !== undefined) {
const first41Bits = Number.parseInt((Number.parseInt(postId, 10)).toString(2).slice(0, 41), 2);
return moment.unix(first41Bits / 1000);
}
}
return null;
}
In order to avoid mistakes between publication and republication time, I have limited this fixer to the publication page itself (and not the activity feed):
function checkPostUrl(_) {
return document.URL.startsWith('https://www.linkedin.com/posts/');
}
For comments, the Fixer works in a similar way except this time I am extracting the timestamp from the DOM:
{
name: 'Comment Timestamp',
selector: 'time.comments-comment-meta__data',
attachTo: node => node,
timestamp: getCommentTimestamp,
label: 'comment',
url: getCommentUrl,
},
And the timestamp is extracted in the following function:
function getCommentTimestamp(node) {
const parnt = node.closest('.comments-comment-entity');
if (parnt.getAttributeNames().includes('data-id')) {
const _id = Number.parseInt(parnt.dataset.id.split(':')[4].split(',')[1], 10);
const first41Bits = Number.parseInt((_id).toString(2).slice(0, 41), 2);
return moment.unix(first41Bits / 1000);
}
return null;
}
After some testing, it gives us this:
This code has been pushed to the Chrome extension repository, so you can install it directly there here.
Have fun!