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 itsSimpleUrlproperty.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 ;)





