# 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:

```json
{
  "@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:

```typescript
//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 ;)
