Going to a Real Web Page from Tridion with a Bookmarklet

I’ve been working in a particular Tridion implementation for quite some time now. It doesn’t have Site EditExperience Manager set up. So when I find a page, I have to sort out in my own brain what the actual url is. And then I have to type it into a browser and actually go there.

That’s a pain. My brain is busy. It’s annoying trying to sort out what the actual url is from Tridion. So I made a bookmarklet. It makes a few assumptions, but it means I can click on a button in my bookmarks bar in my favorite browser, and get to the real page.

The Other Ways of Skinning this Cat

This doesn’t have to be a bookmarklet. Ideally, someone with control over Tridion would whip up an Alchemy extension that does this.

If not that, there’s always the good ol’ fashioned GUI extensions that only require the sacrifice of small woodland creatures.

Or, if you have Experience Manager installed, it’s a piece of cake to get to the “actual page”. But setting up XPM usually requires much larger effigies.

Starting in Anguilla

My first round of writing this bookmarklet involved reading the DOM and lots of string magic
Then I remembered, “you’ve done bookmarklets before”.

When I did that previous bookmarklet, I’d relied on a small utility I’d created, called an “Anguilla Mediator” to make it easy to find the things I was looking for. Turns out, things have moved around a bit in Tridion 8; Anguilla Mediator ain’t gonna mediate nuthin’.

Accomplishing this bookmarklet is a few steps:

  1. Get information about the page
  2. From that information, get the “page file name”
  3. From that information, get the page file extension
  4. From that information, get the page’s file path
  5. Get information we can’t find or assume from Tridion (domain, additional paths in url)
  6. Assemble it as root stuff + page path + page title + page file extension
  7. Open a page with that url

Getting information about the page

I cheated a little bit at the beginning. In order to get the current item, I read the current url for the TCM id. Then, I use something that wasn’t there a few years ago: $models . That appears to be right there as a global variable, whereas in years passed, I had to look through window frames to find it nested a few layers deep in another global. So getting the current page (and information that goes with it) looks a bit like this:

function getTCM(locationURL) {
    return locationURL.replace('#id=','');

function getItem(tcm) {
    return $models.getItem(tcm);

const tcm = getTCM(window.location.hash);
const item = getItem(tcm);


Getting title, extension, and path

Getting page title, extension, and path with Anguilla amounts to using some helpful methods that exist on our $models object. So we start with the file name by using a very well-named method:

const fileName = item.getFileName();


Getting the file extension for the page takes a bit of extra digging. That information is returned as a property in the object that getPageTemplate() returns:

const pageTemplate = item.getPageTemplate();


Now I want the file path for this page. This is accessed via the getInfo() method on the item. Once I assign that to a variable, I should have something like this:
const tcm = getTCM(window.location.hash);
const item = getItem(tcm);
const fileName = item.getFileName();
const pageTemplate = item.getPageTemplate();
const info = item.getInfo();


Assembling the Path

With all this information, I can create a function that will assemble the path for me. This is where I make some assumptions on my implementation. Chief amongst those assumptions is that pages are published to the website with directories that match the structure group organization in Tridion; I’m assuming that itemInfo.FilePath is reliable.

My getPath() function will take three arguments: fileName, itemInfo, fileExtension. As you can see, the fileExtension is found in

function getPath(fileName,itemInfo, fileExtension) {
    let result;
    const path = itemInfo.FilePath.replace('\\','/');

    if (itemInfo.IsPublished ) {    
        result = `${path}/${fileName}.${fileExtension}`;
    return result;

    path = getPath(fileName,info,;


I access the FilePath that’s located on itemInfo and I set those slashes facing the other direction.

Then I check if the page is published! This is important. If it’s not published, I don’t want to get taken to a 404!

Even if the page isn’t published, I still want to return something. In this case, if the page isn’t published, what will be returned is undefined — which is a falsy value.

Getting Information I can’t assume

I could expend a lot of effort to use Anguilla to its fullest powers, and try to sort out what the fully qualified URL would be. But I’m lazy. So I figure I might as well just ask an expert what the rest of the URL should be. And I’m an expert. So, I used our old friend window.prompt to ask me what I know:

function getRoot(knownPath, shouldPrompt = false) {
    let storedRoot = localStorage['gotopage-root'] && localStorage.getItem('gotopage-root');
    let root;

    if (!storedRoot || shouldPrompt) {
        root = window.prompt(`Looks like the root part of the URL isn't stored. What comes in front of ${knownPath}?`);
        localStorage.setItem('gotopage-root', root);

    return storedRoot || root;      

    root = getRoot(path);


I don’t want to have to enter in this “unknown bit” every time. I’d rather have it sitting in localStorage. So, before I set it to localStorage, I’ll first get it from localStorage.

let storedRoot = localStorage['gotopage-root'] && localStorage.getItem('gotopage-root')
is a great example of “fun JavaScript Tricks”. In JavaScript, logic operators don’t return booleans; they return values. So the left side of that && checks to see if the key, gotopage-root, exists in localStorage. The right hand side of the && returns the value of that key. The result is that my storedRoot is either the value pulled from localStorage, or it’s undefined.

You’ll see that I also rely on a default parameter in my function. This my way of being a little forward thinking: what if I want to be prompted every time — regardless of whether this is stored? An easy way to make sure I always get that prompt is to set shouldPrompt = true .

Now, I should mention that this is all fairly weak, in terms of validations. If "undefined" or "null" gets set to localStorage, or an otherwise “not working url fragment”, this won’t know. So…GiGo and stuff.

Open a Page with the URL

Again, I’m not doing a ton of validation here. I don’t throw any messages if parts don’t work.

I’ll take all these fun variables we’ve been playing with and put them in a function. Provided I get something assembled, I’ll open a window.

function getURL() {
    let result;
    const tcm = getTCM(window.location.hash);
    const item = getItem(tcm);
    const fileName = item.getFileName();
    const pageTemplate = item.getPageTemplate();
    const info = item.getInfo();
    const path = getPath(fileName,info,;        
    const root = getRoot(path);

    if (root && path) {
        result =  `${root}${path}`;

    return result;

getURL() &&;


So long as getURL() can return something other than undefined, a window will open with the URL.

Code or it didn’t happen

Take a look at the whole gist, in un-bookmarkletified form.

If you want to make any changes, fork it, post it, or whatever. Then hop on over to a bookmarklet converter To whip it up.

If you’re happy with what you see, and want to use it as is, then drag this link below up into your bookmarks toolbar. When you open a page in Tridion, hit that bookmarklet, and it’ll take you to the page.

Go To Page


  1. // Reply

    Definitely useful on existing or older set ups.

    One more option is the view on site feature. :-)

  2. // Reply

    You, Sir, have aquired the gift of gab – Merry Christmas! BTY:;,- THEREExists: In English; a similar device by order of Punctuation, and if I may opine, it is adequate at associative addressing and such, and it is native to a unique programming architecture. Why doesn’t thedamnthing understand it?

Leave a Reply to Alvin Reyes Cancel reply