Skip to main content

Command Palette

Search for a command to run...

How to get the SharePoint Footer Logo in SPFx

Updated
3 min read
How to get the SharePoint Footer Logo in SPFx

I'm currently developing a custom SPFx Application Customizer to replace the standard SharePoint footer. A key requirement for my custom footer was to include a logo, but I didn't want to use a static, hardcoded image. Instead, my goal was to dynamically use the same logo configured in the site's official footer settings.

The Investigation

I started by searching for an official API endpoint to get the footer logo URL. After scouring the internet and the official API documentation, I found that there was absolutely no information available - no articles, no forum posts, nothing.

So, I decided to take a closer look at the standard footer itself and analyze the API calls it makes. To my surprise, I found that it uses the well-known getMenuState function from the navigation API (PnPJS), but with a specific menu node key. In this case, the key is a static GUID: 13b7c916-4fea-4bb2-8994-5cf274aeb530.

The breakthrough: All data is stored in the navigation

It turns out SharePoint stores the entire footer configuration the logo, the footer name, and the navigation nodes as a “hidden” navigation menu. By querying this menu, I discovered that special items like the logo and name are identified by nodes with static GUIDs as their titles.

  • Footer Logo: The node for the logo always has the title 2e456c2e-3ded-4a6c-a9ea-f7ac4c1b5100. The URL to the image is stored in its SimpleUrl property.

  • Footer Name: The node for the footer's name has the title 7376cd83-67ac-4753-b156-6a7b3fa0fc1f.

  • Footer Links/Nodes: The "real" navigation links are stored as children under the node with the title 3a94b35f-030b-468e-80e3-b75ee84ae0ad.

Response JSON Example

To make it clearer, here is a shortened example of the JSON response from the getMenuState API call:

{
  "@odata.context": "https://sscwebdev.sharepoint.com/sites/arano/_api/$metadata#SP.MenuState",
  //...
  "Nodes": [
    {
      //...
      "Nodes": [
        {
          //...
          "OpenInNewWindow": null,
          "SimpleUrl": "",
          "Title": "Footer Name",
          "Translations": []
        }
      ],
      "Title": "7376cd83-67ac-4753-b156-6a7b3fa0fc1f", //ID for Footer Name
    },
    {
      //...
      "OpenInNewWindow": null,
      "SimpleUrl": "/sites/site1/SiteAssets/__footerlogo__site1.png",
      "Title": "2e456c2e-3ded-4a6c-a9ea-f7ac4c1b5100", //ID for Footer Logo
      "Translations": []
    },
    {
      //...
      "Nodes": [
        {
          "AudienceIds": [],
          "CurrentLCID": 1033,
          "CustomProperties": [],
          "FriendlyUrlSegment": "",
          "IsDeleted": false,
          "IsHidden": false,
          "IsTitleForExistingLanguage": false,
          "Key": "2018",
          "Nodes": [],
          "NodeType": 0,
          "OpenInNewWindow": false,
          "SimpleUrl": "http://google.de",
          "Title": "My Footer Nav Item 1",
          "Translations": []
        }
      ],
      "NodeType": 0,
      "OpenInNewWindow": null,
      "SimpleUrl": "/sites/site1",
      "Title": "3a94b35f-030b-468e-80e3-b75ee84ae0ad", //ID for all other Nodes for Footer as "Subnodes"
      "Translations": []
    }
  ],
  "SimpleUrl": "/sites/site1",
}

PnPJS Implementation

With this knowledge, it's easy to create a function using PnPJS to fetch and parse this data. Here is a simplified example without full error handling:

//All other imports...
import { ISPFXContext, spfi, SPFI, SPFx } from '@pnp/sp';
import '@pnp/sp/webs';
import '@pnp/sp/navigation';

export default class FooterApplicationCustomizer extends BaseApplicationCustomizer<IFooterApplicationCustomizerProperties> {
    //All other Code
    public async onInit(): Promise<void> {
        await super.onInit();
        const sp: SPFI = spfi().using(SPFx(this.context as ISPFXContext));
        const footerNodes = await sp.navigation.getMenuState('13b7c916-4fea-4bb2-8994-5cf274aeb530');
        const footerLogoNode = footerNodes.Nodes[0].find(node => node.Title === '2e456c2e-3ded-4a6c-a9ea-f7ac4c1b5100');
        const footerLogoUrl = footerLogoNode ? footerLogoNode.SimpleUrl : null;
    }
}

Of course, you don't need PnPJS for this. The whole thing also works with a direct REST API call.

To do this, simply call the following endpoint, which you can also paste directly into your browser to test it:

[your-sharepoint-site]/_api/navigation/MenuState?menuNodeKey='13b7c916-4fea-4bb2-8994-5cf274aeb530'

Happy Coding ;)

Add Footer Logo in SharePoint SPFx