For AI agents: the complete documentation index is available at https://nhanbe.id.vn/llms.txt, the full documentation bundle is available at https://nhanbe.id.vn/llms-full.txt, and this page is available as Markdown at https://nhanbe.id.vn/aem/foundation/jcr-page-properties.md.

All properties on the jcr:content node of an AEM page

JCR Page Properties & jcr:content Node

Learning Objectives

By the end of this page, you will be able to:

  • Understand the two-node structure of an AEM page (cq:Page + jcr:content)
  • Identify and use the most common JCR properties for page rendering, SEO, and replication
  • Distinguish between similar properties (e.g., jcr:title vs pageTitle vs navigationTitle)
  • Read page properties programmatically using Java and Groovy

What is jcr:content?

Think of an AEM page as a folder with a single file inside it. The folder is the container; the file holds all the actual data. In JCR terms:

/content/mysite/en/home          ← cq:Page node (container)
└── jcr:content                  ← cq:PageContent node (actual data)
    ├── jcr:primaryType
    ├── jcr:title
    ├── cq:template
    ├── sling:resourceType
    ├── ... (all properties)
    └── par/                     ← child nodes (components)

cq:Page is just a wrapper. All data lives in jcr:content.

This two-node pattern is fundamental to how AEM works. Every page you create in the Sites console follows this structure. Understanding it is the key to reading, writing, and debugging page content.


Core JCR Properties

These are the properties that AEM and Sling use most frequently to render pages.

jcr:primaryType

Defines the node type. The value determines what the node is and what it can contain.

ValueMeaning
cq:PagePage container node
cq:PageContentjcr:content node holding data
nt:unstructuredFree-form node, no schema (used for components)
sling:FolderFolder that can contain resources
sling:OrderedFolderFolder that preserves child node order
oak:UnstructuredSame as nt:unstructured, Oak-specific variant
jcr:primaryType = "cq:PageContent"

jcr:title

The title displayed in the AEM UI (Sites console, breadcrumb). This is not the HTML <title> tag.

jcr:title = "Home Page"
[pageTitle vs navigationTitle vs jcr:title]
  • jcr:title → Sites console UI display
  • pageTitle → HTML <title> tag (if the component uses it)
  • navigationTitle → Menu/nav label

If you only set jcr:title, most components use it as a fallback for all three.


jcr:description

The meta description for the page. Used by the SEO head component.

jcr:description = "Homepage of mysite"

sling:resourceType

Points to the component that renders jcr:content. The most important property for Sling rendering.

sling:resourceType = "mysite/components/page"

Sling resolves this by looking up /apps/mysite/components/page/ and finding page.html or the appropriate script.

[AMS Override]

On AMS (Adobe Managed Services), /libs is not editable. Your custom sling:resourceType must point to /apps, not /libs.


cq:template

The template used to create the page. Affects editable regions when using Editable Templates.

cq:template = "/conf/mysite/settings/wcm/templates/content-page"
Template typePath
Static template/apps/mysite/templates/content-page
Editable template/conf/mysite/settings/wcm/templates/...
Note

cq:template is only a reference. If the template is deleted, the page still renders normally because sling:resourceType is more important for rendering.


cq:lastModified / cq:lastModifiedBy

cq:lastModified = "{Date}2024-01-15T10:30:00.000+07:00"
cq:lastModifiedBy = "[email protected]"

Set automatically when an author saves a page. Used for:

  • Displaying "Last modified" in the UI
  • Dispatcher cache invalidation (if statfileslevel is configured)
  • Audit trail

jcr:lastModified / jcr:lastModifiedBy

JCR-level modification, different from CQ-level. Usually equal, but can differ if a node is modified directly via API without going through a CQ workflow.

jcr:lastModified = "{Date}2024-01-15T10:30:00.000+07:00"
jcr:lastModifiedBy = "admin"

jcr:created / jcr:createdBy

jcr:created = "{Date}2024-01-10T08:00:00.000+07:00"
jcr:createdBy = "admin"

Read-only after the node is created. Set once and never changes.


Page Metadata Properties

These properties control how the page appears in navigation, search results, and social sharing.

pageTitle

Overrides jcr:title for the HTML <title> tag. If not set, most components fall back to jcr:title.

pageTitle = "Home | MyBrand"

Overrides the label shown in navigation components.

navigationTitle = "Home"

hideInNav

Boolean. Hides the page from navigation components (e.g., the Nav component in Core Components).

hideInNav = {Boolean}true

SEO & Social Properties

cq:tags

Array of tag references pointing to /content/cq:tags/.

cq:tags = [
  "mysite:category/news",
  "mysite:region/vietnam"
]

Used with the TagManager API to filter pages and display them in Search.

// Java: get tags from a page
Tag[] tags = page.getTags();

sling:vanityPath

Vanity URL redirect. /content/mysite/en/home → /home.

sling:vanityPath = "/home"
[Performance Warning]

Sling reads ALL vanity paths at startup and caches them in memory. Too many vanity paths (~10k+) cause slow startup and memory pressure. On AMS, consider using Dispatcher rewrite rules instead.

redirectTarget

Redirects the page to a different URL. Used with RedirectServlet.

redirectTarget = "/content/mysite/en/new-home"

Replication Properties

Set by the Replication Agent after publishing or unpublishing. Used to check whether a page has been published and to audit replication history.

cq:lastReplicated / cq:lastReplicatedBy / cq:lastReplicationAction

cq:lastReplicated = "{Date}2024-01-15T11:00:00.000+07:00"
cq:lastReplicatedBy = "admin"
cq:lastReplicationAction = "Activate"   # or "Deactivate"
// Check if a page is published
ValueMap vm = resource.getValueMap();
Calendar replicated = vm.get("cq:lastReplicated", Calendar.class);
String action = vm.get("cq:lastReplicationAction", String.class);
boolean isPublished = "Activate".equals(action) && replicated != null;

Design & Styling Properties

cq:designPath

Design path override for static templates (legacy).

cq:designPath = "/etc/designs/mysite"
Note

Editable Templates do not use cq:designPath. This property is only needed for Static Templates.


Versioning Properties

jcr:isCheckedOut

Workspace versioning. If true, the node is locked by a user.

jcr:baseVersion

Reference to the current version in the version history.


Workflow Properties

cq:wfStatus / cq:wfId

Set by AEM Workflow when a page is in a workflow process.

cq:wfStatus = "RUNNING"
cq:wfId = "..."

Custom / App-Specific Properties

Custom properties are defined in component dialogs. Convention:

# Avoid reserved namespaces (jcr:, sling:, cq:, nt:)
# Use plain names or a custom namespace

heroImage = "/content/dam/mysite/hero.jpg"
ctaLabel   = "Learn More"
ctaLink    = "/content/mysite/en/about"

Common Node Types in jcr:content

jcr:content                    (cq:PageContent)
├── par                        (nt:unstructured) ← parsys
│   ├── hero                   (nt:unstructured) ← component instance
│   │   ├── sling:resourceType = "mysite/components/hero"
│   │   └── heroImage          = "/content/dam/..."
│   └── text_123456            (nt:unstructured)
│       ├── sling:resourceType = "core/wcm/components/text/v2/text"
│       └── text               = "<p>Hello</p>"
├── root                       (nt:unstructured) ← editable template root
│   └── responsivegrid         (nt:unstructured)
└── image                      (nt:unstructured) ← featured image node
    └── fileReference          = "/content/dam/mysite/image.jpg"

Quick Reference: Namespace Meanings

NamespaceOwnerMeaning
jcr:JCR specCore repository metadata
nt:JCR specNode types
sling:Sling frameworkRouting, scripting, resource resolution
cq:Adobe/AEMAEM-specific page/component metadata
dam:Adobe/AEMDAM asset metadata
oak:Apache OakOak-specific storage hints
rep:JackrabbitAccess control, security
mix:JCR specMixin types (versionable, referenceable)

Reading Properties in Java

ReadPageProperties.java
@Model(adaptables = SlingHttpServletRequest.class)
public class PageModel {

    @ScriptVariable
    private Page currentPage;

    public String getTitle() {
        // jcr:title fallback chain
        ValueMap props = currentPage.getProperties();
        return props.get("pageTitle", props.get("jcr:title", ""));
    }

    public boolean isPublished() {
        ValueMap props = currentPage.getProperties();
        return "Activate".equals(props.get("cq:lastReplicationAction", String.class));
    }

    public String[] getTags() {
        Tag[] tags = currentPage.getTags();
        return Arrays.stream(tags)
                     .map(Tag::getTitle)
                     .toArray(String[]::new);
    }
}

CRXDE Quick Check

Browse page properties in CRXDE:

http://localhost:4502/crx/de/index.jsp#/content/mysite/en/home/jcr:content

Or use the Groovy Console to dump all properties:

def page = pageManager.getPage('/content/mysite/en/home')
def props = page.properties
props.each { k, v -> println "$k = $v" }

Reflection

  • If you delete a template from the repository, will the pages created with it still render? Why or why not?
  • What is the difference between cq:lastModified and jcr:lastModified? When would they diverge?
  • How would you check whether a page has been published using the properties discussed here?

What's Next

Now that you understand JCR page properties, explore: