Menu Home

How to detect if an App for Office is opened from Office

Apps for Office whether it is for Outlook, Excel, Word or PowerPoint are all standard HTML pages with JavaScript. I just finished building an app where I wanted some of my app pages to be accessible from a web browser outside the Office context.

Apparently that is a very uncommon scenario, because I wasn’t able to find any documentation on how to accomplish it. Of course I could just have made a separate copy of the page without Office.js and not relying on Office.initialize to call my initialization function. But I really dislike maintaining two copies of the same page/javascript, so I digged a little deeper in a attempt to find a solution. Being able to access the app page directly in a browser without going through the Office client is also very usable while debugging, especially if you have a lot of functionality that is independent of the Office context.

My app was an Outlook app, but this concept should work for any type of Office app. First I thought I could check whether Office.context.mailbox was defined and if not I would know that my page was access from outside an Office context. Unfortunately that approach was not reliable, because the mailbox object might not be initialize right away when the app loads in Outlook.

The best thing I could find while looking through the Office.js implementation, was a call to window.external.GetContext() that is made to get the version info of the Office client. If this call doesn’t return anything usable, the Office.js library will never call Office.initialize, and our initialization code will never run. In that case we know it’s safe to call the initialization ourselves. For the standard Outlook App the javascript code to do so, could look like this.

   var init = function (reason) {
        $(document).ready(function () {
            app.initialize();

            $('#set-subject').click(setSubject);
            $('#get-subject').click(getSubject);
            $('#add-to-recipients').click(addToRecipients);
        });
    };
    // The initialize function must be run each time a new page is loaded
    Office.initialize = init;
    try {
        if (!window.external.GetContext) {
            console.log('Not in office context');
            init();
        }
    } catch (e) {
        // when in office context unable to access external.
    }

This is completely undocumented and could change if Microsoft want to, but it’s highly unlikely as it would break existing Office apps. Also please note that I have wrapped the call to window.external in a try/catch statement because it will fail when called when running in a Office context.

Another cool trick to figure out if the app is opened in the Outlook client or in OWA in a webbrowser is posted by Elio Struyf on his blog.

Categories: Office

Tagged as:

Simon J.K. Pedersen

2 replies

  1. Thanks for posting this. This didn’t quite work for me, but I don’t know if this is because of changes to the latest version of office.js or what.

    However, it pointed me in the right direction.

    What worked for me was the code below. I was getting the init running twice as the try/catch was running before office.js fully had time to initialize and then a few hundred milliseconds later, it would initialize, and I’d get two copies of init running which was causing all sorts of DOM issues.

    So, I set a timeout to delay the try/catch by 250 milliseconds and I check to see for the office.js callback reason and if it’s undefined, I throw an error and proceed to call the init.

    code:

    var officeReason;

    var init = function (reason) {
    ‘use-strict’;
    officeReason = reason;

    $(document).ready(function () {

    });
    }

    // The initialize function must be run each time a new page is loaded
    Office.initialize = init;

    setTimeout(function () {

    try {
    if (officeReason == null || officeReason == ” || officeReason == ‘undefined’)
    throw ‘Not in office context’;
    }
    catch (e) {
    console.log(‘here is the error: ‘ + e);
    init();
    }

    }, 250);

Leave a Reply

Your email address will not be published. Required fields are marked *