Omit the user from shared links

The sharing links that Discourse (or this Discourse instance?) uses all seem to have the user id appended as a query parameter. For example, if I go to the Racket 8.6 release thread and click on the link symbol of the first post, I get the link

What I would like to get instead is

Is it possible to switch off the addition of the user name? I don't think it's that useful to know who copied the link originally, especially if the link is forwarded further.

At the moment, my workaround is to remove the ?u=sschwarzer manually.

1 Like

I don't have a strong opinion on this topic.
Here are two posts on the meta site that I found on the topic:

This post from the second topic seems to suggest that they would be open to a feature being added as a PR (In other posts they say that no paying customer has wanted it):

Having it as a global site setting seems too much, because different users would probably prefer it differently. Personally I think there should be a user setting to disable it, maybe that could be added via PR.

Alternatively it might be possible to create a browser local user script with some extension like but I guess that is more of a last resort solution, if no PR would be accepted.

Also I am not sure what settings there are, I haven't explored that in depth.

Considering that it is quite easy to write that script maybe it is a good solution and the good thing about it is that you can even customize it to your liking and different users can make it do what they want, I haven't tested it extensively, but it seems to work (almost):

It works the first time, after that it always shows the rewritten text from the first opening even for other posts, but I am currently too tired to figure out why / what kind of state keeps hanging around, or if it somehow blocks some code from setting the new value...
I guess I hate working with the DOM, too much state and stuff and no way to sensibly compose programs, or easily find out how one thing breaks some other code.
Maybe someone else finds the solution, I don't want to waste any more time on this...

// ==UserScript==
// @name         share link username remover
// @namespace
// @version      0.1
// @description  removes the username from sharelink on discourse websites
// @author       You
// @match        **
// @icon
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    let container = document.querySelector("#discourse-modal");
    new MutationObserver(function() {
        if(container.classList.contains("hidden")) {
            container.removeAttribute("removed-username"); // reset the class
        } else if(!container.getAttribute("removed-username")) {
            // only remove the username once per opening of the modal
            let node = document.querySelector(".link-share-container .invite-link");
            let url = new URL(node.value);
   = "";
            let new_value = url.toString();
            node.value = new_value
            // reselect all the text
            node.setSelectionRange(0, new_value.length);
    }).observe(container, {"attributes":true, "attributeFilter":["class"]});
    // uses attributeFilter to avoid infinite mutation observation loops
    // where after observation we generate the next mutation

1 Like

I don't have a strong opinion on this topic.

I do have a strong opinion: The best default value for anything is whatever tends to preserve privacy and/or minimize future interactions. People should explicitly opt in to identity disclosures, tracking, notifications, etc.

However it seems N/A for me in this case:

  • I usually copy the URL from the browser address bar (I just don't love site "share" buttons).

  • I review the URL to cleanse and simplify:

    • Of course I zap stuff like Google Analytics query parameters.

    • Amusingly, what also reinforced this habit was years of sharing Racket doc URLs. These used to append the search phrase as a query param. (I don't want people to see the boneheaded phrase I used. I want it to look like I knew the answer already. :smile:)


Well said! :slight_smile:

I do that if I want to link to a discussion thread as a whole, but I use the "share" link when I want to link to a specific post in the thread.

I usually do this, too, but it would be nice if I didn't have to. :wink:

I've discovered that for all the sites I use, there is usually some link on each comment/post -- usually with its datetime -- where I can right click and choose Copy Link. Then the usual paste + cleanup.

On Discourse it's at the top of each post, on the same line as the user name, right-aligned. e.g. "6m" or "3h" or "2d" or "Jul 7".

Something similar on Slack, GitHub issues, and so on.

Having said that, I agree 100% that Discourse should have an option to exclude this. With what we agree is the proper default. :smile:

Then you really could just trust and use the share button.

I definitely agree with this in general. The Discourse shared links bother me less than many things because they seem reasonably transparent about what they're doing. When I click on the share button, I see something like this:

The actual URL is displayed in the UI; the one and only query parameter is my user name, so it's clear exactly what information it is I'd be disclosing; and the text box is even scrolled to the right, so that the query parameter is visible.

Nonetheless, I usually remove the query parameter, and I'd be glad to have a setting to do so by default. (The Racket documentation search parameters also helped reinforce this habit for me!) Just, if people, generally, were to find the sharing-related badges fun or whatever (I don't know if that's the case!), I wouldn't be especially bothered about the default value for this particular standing.

Tangentially, if you want a short link to share, you can also remove the name and just use e.g.

1 Like

I noticed something interesting, as you scroll through the posts, discourse updates the current url to have the number of the post that is currently at the top of the screen.

So scrolling to the wanted post and then using a browser keyboard shortcut to copy the current url would work too.

This gave me the idea to change the user script to manipulate that number link, so that it just copies the link to the clipboard without opening a modal window. I like that idea because that link in itself isn't that useful anyway and this way you can still access the modal window through the share button, but use the minutes as a copy uri to clipboard shortcut.

I think I will actually use this version because it allows me to avoid needing multiple clicks.
It suppresses the original event, to prevent the modal from opening, sadly because of this you also lose the proper aligned scrolling of the post to the top and the blink/fade effect, but considering that this happens on page load automatically maybe it doesn't matter.

Instead I added a custom animation so that there is some kind of visual feedback, (if you use light mode) you need to change the colors to your liking.

// ==UserScript==
// @name         share link username remover
// @namespace
// @version      0.1
// @description  removes the username from sharelink on discourse websites
// @author       You
// @match        **
// @icon
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    const dummy_base = "rel://rel.rel";
    const dummy_len = dummy_base.length;
    const remove_username_rel = (s) => {
        const url = new URL(s, dummy_base); = "";
        return url.toString().substring(dummy_len);
    const update_attribute = (node, attr, update) => {node.setAttribute(attr, update(node.getAttribute(attr)))};
    const copy_animation = [
    const save_link_to_clipboard = (event) => {
        window.navigator.clipboard.writeText(origin + event.currentTarget.getAttribute("href"));
        event.currentTarget.closest(".topic-body").animate(copy_animation, {duration:500, iterations:1});
    const add_click_handler = (node) => {
        update_attribute(node, "href", remove_username_rel);
        node.addEventListener("click", save_link_to_clipboard, true);

    const state = {running:false};
    const remove_usernames = () => {
        state.running = true;
        const dateLinks = document.querySelectorAll(".topic-post .post-date a");
        for(let l of dateLinks) add_click_handler(l);
        state.running = false;

    const username_remover = new MutationObserver(remove_usernames);
    username_remover.observe(document.querySelector("#topic"), {childList:true, subtree:true});