{"id":7527,"date":"2026-06-01T12:13:47","date_gmt":"2026-06-01T12:13:47","guid":{"rendered":"https:\/\/onwardpath.com\/intelligence\/?p=7527"},"modified":"2026-06-02T14:31:18","modified_gmt":"2026-06-02T14:31:18","slug":"getting-started-with-aem-universal-editor-and-ai-assisted-authoring","status":"publish","type":"post","link":"https:\/\/onwardpath.com\/intelligence\/getting-started-with-aem-universal-editor-and-ai-assisted-authoring\/","title":{"rendered":"Getting Started with AEM Universal Editor and AI-Assisted Authoring"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><strong>Overview<\/strong> : The Universal Editor is Adobe&#8217;s next-generation visual editing interface for AEM as a Cloud Service. Framework-agnostic and decoupled by design, it works with Edge Delivery Services pages, headless React and Next.js apps backed by Content Fragments, and any front end instrumented with UE metadata attributes. This blog shows how to extend it with AI.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>What Is the Universal Editor?<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The Universal Editor (UE) is Adobe&#8217;s next-generation visual editing interface for AEM as a Cloud Service. Unlike the classic Sites editor it is tightly coupled to AEM&#8217;s page model and the Universal Editor is framework-agnostic and decoupled by design.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It works with:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"\"><strong>AEM Edge Delivery Services<\/strong> pages<\/li>\n\n\n\n<li class=\"\"><strong>Headless React \/ Next.js \/ Vue apps<\/strong> backed by AEM Content Fragments<\/li>\n\n\n\n<li class=\"\"><strong>Any front end<\/strong> instrumented with UE metadata attributes<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The editor opens your live page in an iframe, lets authors click any component and edit it in-context, and writes changes back to either the AEM repository or a connected Google Doc depending on your delivery model.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Why It Matters for AI Integration<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The Universal Editor exposes a REST-based Connections API and a plugin extension model built on Adobe&#8217;s App Builder UI framework. This means you can inject AI capabilities directly into the authoring surface not as a separate tool, but as a panel or action button inside the editor itself.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The three most impactful AI integrations for Universal Editor are:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"\"><strong>In-context content generation<\/strong> : It authors click a component and generate or rewrite copy without leaving the editor<\/li>\n\n\n\n<li class=\"\"><strong>AI image variant generation<\/strong> : It triggers Adobe Firefly to produce on-brand image alternatives for a selected asset slot<\/li>\n\n\n\n<li class=\"\"><strong>Automated accessibility checking<\/strong> : It runs an AI pass on page content for WCAG 2.1 AA compliance before publish<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Use Case 1 : In-Context AI Copywriting Panel<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>The Setup<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Universal Editor extensions are built as App Builder UI extensions using the @adobe\/uix-sdk. You define a panel that appears in the editor&#8217;s right rail and receives the currently selected component&#8217;s content as context.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ src\/aem-cf-editor-1\/web-src\/src\/components\/AICopyPanel.jsx\nimport { useEffect, useState } from 'react';\nimport { attach } from '@adobe\/uix-guest';\n \nexport default function AICopyPanel() {\n  const &#91;selection, setSelection] = useState(null);\n  const &#91;draft, setDraft]         = useState('');\n  const &#91;loading, setLoading]     = useState(false);\n \n  useEffect(() =&gt; {\n    attach({ id: 'ai-copy-panel' }).then(guest =&gt; {\n      guest.host.editorState.getSelection().then(setSelection);\n    });\n  }, &#91;]);\n \n  async function generateCopy() {\n    setLoading(true);\n    const res = await fetch('\/api\/generate-copy', {\n      method: 'POST',\n      headers: { 'Content-Type': 'application\/json' },\n      body: JSON.stringify({\n        currentText: selection?.content ?? '',\n        tone: 'professional',\n        maxWords: 80,\n      }),\n    });\n    const { copy } = await res.json();\n    setDraft(copy);\n    setLoading(false);\n  }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The App Builder action called by this panel:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ actions\/generate-copy\/index.js\nconst Anthropic = require('@anthropic-ai\/sdk');\n \nasync function main(params) {\n  const client = new Anthropic({ apiKey: params.ANTHROPIC_API_KEY });\n  const message = await client.messages.create({\n    model: 'claude-sonnet-4-6',\n    max_tokens: 300,\n    messages: &#91;{\n      role: 'user',\n      content: `Rewrite in ${params.tone} tone, max ${params.maxWords} words.\nReturn only the rewritten text.\n \nOriginal: ${params.currentText}`,\n    }],\n  });\n  return { copy: message.content&#91;0].text };\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Use Case 2 : Adobe Firefly Image Variants<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When an author selects an image component in Universal Editor, your extension surfaces a &#8220;Generate Variant&#8221; button that calls the Firefly API with the current image&#8217;s alt text as the prompt producing on-brand alternatives without leaving the editor.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ actions\/firefly-variant\/index.js\nconst fetch = require('node-fetch');\n \nasync function main(params) {\n  const token = await getFireflyToken(params); \/\/ OAuth via Adobe IMS\n \n  const res = await fetch('https:\/\/firefly-api.adobe.io\/v3\/images\/generate', {\n    method: 'POST',\n    headers: {\n      'Authorization': `Bearer ${token}`,\n      'x-api-key': params.FIREFLY_CLIENT_ID,\n      'Content-Type': 'application\/json',\n    },\n    body: JSON.stringify({\n      prompt: params.altText,\n      numVariations: 3,\n      size: { width: 1200, height: 630 },\n      contentClass: 'photo',\n    }),\n  });\n  const { outputs } = await res.json();\n  return { variants: outputs.map(o =&gt; o.image.presignedUrl) };\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Important<\/strong> : Firefly images are commercially safe by default \u2014 trained only on licensed Adobe Stock content. This makes them suitable for brand and product use without IP risk.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Use Case 3 : AI Accessibility Pre-Check<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Before an author publishes, a toolbar button triggers an accessibility scan checking for missing alt text, poor colour contrast, improper heading hierarchy, and ARIA gaps. Issues are surfaced inline as highlights on the canvas.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ actions\/accessibility-check\/index.js\nconst Anthropic = require('@anthropic-ai\/sdk');\n \nasync function main(params) {\n  const client = new Anthropic({ apiKey: params.ANTHROPIC_API_KEY });\n  const message = await client.messages.create({\n    model: 'claude-sonnet-4-6',\n    max_tokens: 1024,\n    system: `You are a WCAG 2.1 AA accessibility auditor.\nAnalyse the provided HTML and return a JSON array of issues.\nEach issue: { element, issue, severity: \"error\"|\"warning\", suggestion }`,\n    messages: &#91;{ role: 'user', content: `Page HTML:\\n\\n${params.pageHtml}` }],\n  });\n  return { issues: JSON.parse(message.content&#91;0].text) };\n}\n<\/code><\/pre>\n\n\n\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;6a2f6a9073b19&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"6a2f6a9073b19\" class=\"wp-block-image size-full wp-lightbox-container\"><img decoding=\"async\" width=\"760\" height=\"577\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" loading=\"lazy\" src=\"https:\/\/i0.wp.com\/onwardpath.com\/intelligence\/wp-content\/uploads\/2026\/06\/image.png?fit=760%2C577&amp;ssl=1\" alt=\"\" class=\"wp-image-7529\" srcset=\"https:\/\/i0.wp.com\/onwardpath.com\/intelligence\/wp-content\/uploads\/2026\/06\/image.png?w=760&amp;ssl=1 760w, https:\/\/i0.wp.com\/onwardpath.com\/intelligence\/wp-content\/uploads\/2026\/06\/image.png?resize=300%2C228&amp;ssl=1 300w\" sizes=\"auto, (max-width: 760px) 100vw, 760px\" \/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\tdata-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.thisImage.buttonRight\"\n\t\t\tdata-wp-style--top=\"state.thisImage.buttonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Setting Up a Universal Editor Extension<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Step 1 &#8211; Scaffold with the AIO CLI<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aio app init my-ue-extension --template @adobe\/aem-cf-editor-ui-ext-tpl<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Step 2 &#8211; Register the extension<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In <em>app.config.yaml<\/em>, declare your extension point:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>extensions:\n  aem\/universal-editor\/1:\n    $include: src\/universal-editor\/ext.config.yaml\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Step 3 &#8211;  Configure the right rail panel<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ src\/universal-editor\/web-src\/src\/index.js\nimport { register } from '@adobe\/uix-guest';\n \nregister({\n  id: 'ai-copy-panel',\n  methods: {\n    rightPanel: {\n      addPanels() {\n        return &#91;{ id: 'ai-copy', title: 'AI Copy', url: '\/ai-copy-panel' }];\n      },\n    },\n  },\n});\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Step 4 &#8211; Deploy<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aio app deploy<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The extension appears automatically in Universal Editor for all authors in your AEM organisation no browser plugin installation required.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Key Differences from EDS Block AI Integration<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td>&nbsp;<\/td><td><strong>EDS Block AI<\/strong><\/td><td><strong>Universal Editor AI<\/strong><\/td><\/tr><tr><td>Extension point<\/td><td>Vanilla JS decorate()<\/td><td>App Builder UI extension<\/td><\/tr><tr><td>Author interface<\/td><td>Sidekick event API<\/td><td>Right rail panel \/ toolbar<\/td><\/tr><tr><td>Content model<\/td><td>Google Docs tables<\/td><td>Content Fragments \/ page model<\/td><\/tr><tr><td>AI triggered by<\/td><td>Block render \/ lazy load<\/td><td>Author action in editor<\/td><\/tr><tr><td>Output goes to<\/td><td>DOM (sanitised)<\/td><td>Content Fragment \/ page properties<\/td><\/tr><tr><td>Framework<\/td><td>Vanilla JS<\/td><td>React + @adobe\/uix-sdk<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Project Setup Checklist<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"\">Create App Builder project in Adobe Developer Console<\/li>\n\n\n\n<li class=\"\">Scaffold extension with aio app init and the UE template<\/li>\n\n\n\n<li class=\"\">Add <em>ANTHROPIC_API_KEY<\/em> and <em>FIREFLY_CLIENT_ID<\/em> to App Builder environment params<\/li>\n\n\n\n<li class=\"\">Instrument your front end with data-aue-resource and data-aue-type attributes<\/li>\n\n\n\n<li class=\"\">Register extension in app.config.yaml under <em>aem\/universal-editor\/1<\/em><\/li>\n\n\n\n<li class=\"\">Test AI panel in UE staging environment before deploying to production<\/li>\n\n\n\n<li class=\"\">Set Content-Security-Policy on your front end to allow https:\/\/experience.adobe.com<\/li>\n\n\n\n<li class=\"\">Validate AI-generated content updates persist correctly to the AEM content repo<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Final Thoughts<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The Universal Editor represents Adobe&#8217;s bet on a single, extensible authoring surface for every delivery model EDS, headless, traditional. For development teams, it means AI extensions built once with App Builder work across all project types without re-implementation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The pattern is consistent: authors stay in context, AI does the repetitive cognitive work, and humans approve before anything publishes. The tooling has matured to the point where this is now a realistic production setup not a proof of concept.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Most AEM teams still treat AI as a separate tool authors have to leave the editor to use. The Universal Editor changes that. With App Builder UI extensions and the @adobe\/uix-sdk, you can inject AI copywriting, Firefly image variants, and WCAG accessibility scanning directly into the authoring surface as right rail panels and toolbar buttons. This guide covers the full setup: scaffolding with the AIO CLI, registering extensions under aem\/universal-editor\/1, and wiring server-side Claude API actions so API keys never reach the browser.<\/p>\n","protected":false},"author":7,"featured_media":7538,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"nf_dc_page":"","site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[138,37],"tags":[137,189,188,192,184,139,197,194,195,190,187,196,200,199,198,193,191],"class_list":["post-7527","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-adobe-experience-manager","category-technology-blog","tag-adobe-experience-manager","tag-adobe-uix-sdk","tag-adobe-firefly","tag-adobe-ims","tag-adobe-sensei","tag-aem","tag-aem-developer","tag-aem-universal-editor","tag-ai-assisted-authoring","tag-aio-cli","tag-app-builder-claude-api","tag-developer-guide","tag-digital-experience","tag-enterprise-cms","tag-front-end-development","tag-universal-editor","tag-wcag-accessibility"],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/onwardpath.com\/intelligence\/wp-content\/uploads\/2026\/06\/AEM-Universal-Editor-1.png?fit=2048%2C1075&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/onwardpath.com\/intelligence\/wp-json\/wp\/v2\/posts\/7527","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/onwardpath.com\/intelligence\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/onwardpath.com\/intelligence\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/onwardpath.com\/intelligence\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/onwardpath.com\/intelligence\/wp-json\/wp\/v2\/comments?post=7527"}],"version-history":[{"count":4,"href":"https:\/\/onwardpath.com\/intelligence\/wp-json\/wp\/v2\/posts\/7527\/revisions"}],"predecessor-version":[{"id":7539,"href":"https:\/\/onwardpath.com\/intelligence\/wp-json\/wp\/v2\/posts\/7527\/revisions\/7539"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/onwardpath.com\/intelligence\/wp-json\/wp\/v2\/media\/7538"}],"wp:attachment":[{"href":"https:\/\/onwardpath.com\/intelligence\/wp-json\/wp\/v2\/media?parent=7527"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/onwardpath.com\/intelligence\/wp-json\/wp\/v2\/categories?post=7527"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/onwardpath.com\/intelligence\/wp-json\/wp\/v2\/tags?post=7527"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}