Expand my Community achievements bar.

Applications for the 2024-2025 Adobe Experience Manager Champion Program are open!

AEM Cloudservice - React SPA with Sling Vanity URLs | AEM Community Blog Seeding




AEM Cloudservice - React SPA with Sling Vanity URLs by Sreekanth Choudry Nalabotu


Adobe Experience Manager 2021.9.5899.20210929T093525Z-210800 (Sep 29, 2021)

Create a AEM React SPA supporting Vanity Urls. Otb Vanity Urls are added in Page Properties, saved as jcr:content/sling:vanityPath

1) Add the function getVanityUrls() to get the list of vanity urls using querybuilder before loading the app. VanityURLModelClient extending ModelClient was added as a workaround to not request model.json using the vanity url (eg. this is invalid request http://localhost:4502/eaem-home.model.json). Code in eaem-spa-vanity-urls\ui.frontend\src\index.js facilitates loading of vanity urls into the app...

import 'react-app-polyfill/stable';
import 'react-app-polyfill/ie9';
import 'custom-event-polyfill';

import { Constants, ModelManager } from '@adobe/aem-spa-page-model-manager';
import { createBrowserHistory } from 'history';
import React from 'react';
import { render } from 'react-dom';
import { Router } from 'react-router-dom';
import {ModelClient} from '@adobe/aem-spa-page-model-manager';
import App from './App';
import LocalDevModelClient from './LocalDevModelClient';
import './components/import-components';
import './index.css';

const getVanityUrls = async () => {
const QUERY = "/bin/querybuilder.json?path=/content/eaem-spa-vanity-urls&property=jcr:content/sling:vanityPath&property.operation=exists" +

const response = process.env.REACT_APP_PROXY_ENABLED ? await fetch(QUERY, {
credentials: 'same-origin',
headers: {
'Authorization': process.env.REACT_APP_AEM_AUTHORIZATION_HEADER
}): await fetch(QUERY);

const data = (await response.json()).hits.reduce((current, next) => {
return { ...current, ...{ [next["jcr:path"]]: next["jcr:content"]?.["sling:vanityPath"] } }
}, {});

return data;

class VanityURLModelClient extends ModelClient{
fetch(modelPath) {
//if the path does not start with /content (page editing) or /conf (template editing) return empty model
if (modelPath && !/^\/content|^\/conf/.test(modelPath)) {
return Promise.resolve({});
return super.fetch(modelPath);

const modelManagerOptions = {};

if(process.env.REACT_APP_PROXY_ENABLED) {
modelManagerOptions.modelClient = new LocalDevModelClient(process.env.REACT_APP_API_HOST);
modelManagerOptions.modelClient = new VanityURLModelClient(process.env.REACT_APP_API_HOST);

const renderApp = (vanityUrls) => {
ModelManager.initialize(modelManagerOptions).then(pageModel => {
const history = createBrowserHistory();


document.addEventListener('DOMContentLoaded', () => {
getVanityUrls().then((vanityUrls) => {
}, (err) => {
console.log("Error getting vanity urls", err);

2) Pass the page full url to vanity url mapping object loaded in step above to child pages in eaem-spa-vanity-urls\ui.frontend\src\App.js

Read Full Blog

AEM Cloudservice - React SPA with Sling Vanity URLs


Please use this thread to ask the related questions.

Kautuk Sahni
0 Replies