To use Joplin as a knowledge base it would be useful to have a “what links here”?

What do you think?


I think this might be quite some effort and additionally there will be ongoing maintenance required. To do this you basically have to create a separate table and maintain a source - target list. Thus every time you touch a link, maintenance has to be done on that table.

I was thinking that this could be implemented like a plugin, so every time you want backlink info a script would run over all of your notes and find backlinks. This could be slow for a lot of notes, but will otherwise work. I don’t see this being a core feature in Joplin however.

1 Like

Using Python and Joplin API, I was able to add backlinks automatically. Following the script I wrote and used:

import requests, re
resp = requests.get(""+token+"&fields=id,title,body")
# Loop on all notes
for item in resp.json():
    # Find link to note '[anything](:/anything)' in note body, excludes links start with '!' or 'backlink:'
    links = re.findall("(?<=[^\!backlink:])\[.*\]\(:\/.*\)", item['body'])
    # If list 'links' is not empty
    if links:
        # Loop on links
        for link in links:
            # Get target node id
            target_node_id ="\(:\/(.*)\)",link)
            # Get target node body
            output_dict = [x for x in resp.json() if x['id'] ==]
            # Add backlink at the end of the target node body
            new_body={"body": output_dict[0]['body']+'\n* * *\n'+'backlink:[{}](:/{})'.format(item['title'], item['id'])}
            # Update target node
            update_resp = requests.put(''"?token="+token,json=new_body)


  1. Keep the work backlink: before the backlink, that’s to avoid backlinks endless cycle. You can change it though in the code before first run.
  2. Take backup before running this script. I only run it on my Joplin notes and it works without errors but still need more tests. Your feedback will helpful to fix any error if any.

2 problems still:

  1. If the title of original note changed, the backlinks’ title will not be updated unless removed and rerun the script! May be another script should be written to update backlinks only.
  2. Running it again will duplicate backlinks, that need extra coding to check if backlink is already exist.

I just thought I will post this initial code, may someone would like to pick it up and resolve above 2 issues and improve it.


Are you saying links (and hence backlinks) are not primary citizens in Joplin? So I should organize my notes in a hierarchy, rather than link relevant pieces?

Okay, new idea here.

To implement “What links here” you just need one thing: the id of the note.

Proposed workflow:

  • right-click on the node
  • choose What links here (new menupoint) (could also be a “Show incoming links” menupoint in Edit below Search in all notes)
  • and you find yourself as if you have typed the note id after choosing “Search in all notes”

I think this “search for node id” is straightforward to implement, yet useful enough to consider in this form.
What do you think, @tessus and @laurent?

1 Like

At first, I was thinking scripting it (as Rami stated and started)

  • searching using the API for each note ID, notes which contains the ID in their bodies
  • writing (as a footer for example), in the target note all (source)-notes pointing to it

To optimize the search part (searching directly in the body using the API), I read (again :slight_smile: ) the documentation and stumbled upon specifically the Field restricted part. Yes, it's for the client (desktop or Android from what I tested) but instead of backlinks (and having to manage them), what about smart backlinks ? A syntax which would trigger a search using a note ID for instance...

Let me rephrase ...

Given 2 notes (SOURCE and TARGET),

  • in SOURCE, quite obviously, I have somewhere in the body: [TARGET](:/TARGET_ID)
  • in TARGET, I add, manually or programmatically, at the end (as a footer, you can guess my preference): [Backlinks](:/search:body:TARGET_ID)
    , which would then update the notes list, given the search (in the search box): body:TARGET_ID

What do you think?
Have I missed something in the documentation?

1 Like