plugins/aem/edge-delivery-services-content-ops/skills/content-diff/SKILL.md
Compare two versions of an AEM Edge Delivery Services page to identify what changed. Fetches preview vs live, or two different URLs, and produces a detailed content diff showing added, removed, and modified content, metadata, and blocks. Use when reviewing changes before publishing, auditing content modifications, or tracking content evolution.
npx skillsauth add adobe/skills content-diffInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Compare two versions of an AEM Edge Delivery Services page and produce a clear, author-friendly change report covering content, metadata, blocks, and media. Highlights changes that could impact SEO, performance, or accessibility.
This skill fetches external web pages for comparison. When fetching:
.plain.html).EDS has three environments for every page:
*.aem.page) — shows the latest content from the source document (Google Doc or Word). Updated when an author clicks "Preview" in Sidekick.*.aem.live) — shows the last-published version. Updated when an author clicks "Publish" in Sidekick.Comparing preview vs live shows what will change on the next publish. This is the most common comparison mode.
The .plain.html variant of any page strips header, footer, and navigation, returning only the authored page content. This gives the cleanest comparison.
.plain.html convention are EDS-specific).Before starting, create a checklist to track progress:
.plain.html)Ask the user or infer from the provided URLs which mode to use:
The most common mode. Given a page path like /about:
https://<branch>--<repo>--<owner>.aem.live/abouthttps://<branch>--<repo>--<owner>.aem.page/aboutIf the user provides a production URL (custom domain), ask for the owner, repo, and branch to construct the .aem.page and .aem.live URLs.
The user provides two explicit URLs. These could be:
/about and /about-us)Compare the same page across two branches:
https://<branch1>--<repo>--<owner>.aem.page/abouthttps://<branch2>--<repo>--<owner>.aem.page/aboutFor each version, fetch two representations:
<head> with metadata, plus the full <body> with header, navigation, content, and footer..plain.html to the page path (e.g., /about becomes /about.plain.html). For root paths (/), use /index.plain.html. This returns only the authored content: headings, paragraphs, sections, blocks, images, and links — no site chrome.So you will fetch up to four URLs total:
.plain.html.plain.htmlIf .plain.html returns a 404 for either version, fall back to comparing the full HTML and note this limitation.
Note: EDS loads header and footer content via JavaScript, so those elements appear empty in the initial HTML. If you need to diff navigation or footer content, fetch /nav.plain.html and /footer.plain.html separately for each version. Some tools convert fetched HTML to markdown, losing attributes like alt, loading, and class names. When diffing attributes, use curl or a tool that preserves raw HTML.
Compare the <meta> tags from the <head> of both full HTML versions.
Important: When comparing .aem.page vs .aem.live, EDS automatically swaps the domain in canonical, og:url, og:image, og:image:secure_url, and twitter:image tags to match each environment. These are not real content changes — filter them out. Only report metadata differences that reflect actual author edits (changed titles, descriptions, added/removed tags, etc.). Similarly, CSP nonces and other per-request headers will differ between fetches and should be ignored.
Check for changes in:
<title> — the page title<meta name="description"> — the page descriptionog:title, og:description, og:image — Open Graph tags<meta name="robots"> — indexing directives<link rel="canonical"> — canonical URLtwitter:card, twitter:title, twitter:description — Twitter card tagsPresent changes as:
| Property | Before | After | |----------|--------|-------| | Title | "Our Company - About" | "About Us - Our Company" | | Description | "Learn about our company" | "Meet the team behind Our Company" | | og:image | /media/old-hero.jpg | /media/new-hero.jpg | | Robots | (not set) | noindex |
If no metadata changed, state "No metadata changes detected."
Using the .plain.html versions, compare the page content section by section.
In EDS, sections are <div> wrappers separated by <hr> (horizontal rules) in the source document. Each section may contain default content (headings, paragraphs, lists, links, images) and blocks.
For each section, identify:
For modified sections, describe the changes in plain language:
Keep the diff author-friendly. Focus on the content meaning, not the HTML tags. Instead of saying "a <p> element was inserted after the third <p>," say "A new paragraph was added after 'We deliver excellence...': 'Our team has grown to 50 specialists...'"
Compare blocks between the two versions. Blocks in EDS are rendered from tables in the source document and appear as <div> elements with class names matching the block name.
Check for:
columns changed to columns (wide)). Variants appear as additional CSS classes.Present block changes:
| Block | Change Type | Details |
|-------|-------------|---------|
| Hero | Modified | Heading changed from "Welcome" to "Hello World" |
| Columns | Variant changed | columns changed to columns (wide) |
| Cards | Added | New cards block with 3 cards added in section 4 |
| Quote | Removed | Pull quote block removed from section 2 |
Compare images and videos between versions:
src URL.Present media changes:
| Media | Change | Location | Details | |-------|--------|----------|---------| | /media/hero.jpg | Replaced | Section 1 (Hero) | New hero image | | /media/team.jpg | Added | Section 3 | New team photo, alt: "Engineering team at offsite" | | /media/old-logo.png | Removed | Footer | Logo image removed | | /media/product.jpg | Alt text changed | Section 2 | "product" changed to "Cloud dashboard showing real-time analytics" |
Produce a clear, scannable report organized as follows:
State the overall scope in one line:
The table from Step 3, or "No metadata changes."
The section-by-section diff from Step 4, presented in order.
The table from Step 5, or "No block changes."
The table from Step 6, or "No media changes."
Flag anything that could impact SEO, performance, or accessibility:
| Risk | Category | Details |
|------|----------|---------|
| H1 changed | SEO | H1 changed from "About Us" to "Our Story" — may affect search ranking for "about us" queries |
| Description removed | SEO | Meta description was removed — search engines will auto-generate a snippet |
| LCP image changed | Performance | The first section's hero image was replaced — verify the new image is optimized and has fetchpriority="high" |
| Alt text removed | Accessibility | Image in section 3 lost its alt text — this is a WCAG violation |
| noindex added | SEO | robots: noindex was added — this page will be removed from search indexes |
| New block added | Performance | A new block in section 2 will load additional CSS/JS — verify it does not impact LCP |
If there are no risks, state "No SEO, performance, or accessibility risks identified."
| Problem | Cause | Solution |
|---------|-------|----------|
| .plain.html returns 404 | Page may not exist or may use a non-standard setup | Fall back to comparing the full HTML; note the limitation |
| Preview and live are identical | No changes have been made since last publish, or the page was just published | Confirm with the user; this means there is nothing new to publish |
| Cannot fetch one version | URL may be wrong, page may not exist on that branch, or there may be auth | Verify the URL; ask the user to check Sidekick |
| Large pages produce noisy diffs | Pages with many sections and blocks | Focus the report on the most significant changes; summarize minor edits |
| Media URLs differ but images look the same | EDS may regenerate media paths on re-upload | Note the path change but suggest verifying visually |
| Custom domain version differs from .aem.live | CDN cache may be stale | Compare .aem.live (live) and .aem.page (preview) instead of production |
<div> wrappers. Say "the second paragraph was reworded" not "a <p> element's innerHTML changed.".plain.html gives the cleanest comparison. It strips navigation, footer, and site chrome. Always prefer it for content diffing.tools
Use the run-workflow MCP to discover, compose, execute, publish, and save Adobe Firefly workflows. TRIGGER when: user asks what actions are available, what the MCP can do, how to process images/video/3D via workflow, wants to build/run/save/publish a workflow, OR pastes any workflow/batch/execution ID. BARE ID (UUID/workflowId/batchId) = INSPECT ONLY — call inspect_run, NEVER run_workflow_submit. ALWAYS call list_actions first for capability/discovery questions. DO NOT TRIGGER for direct Firefly API calls without MCP (use firefly-api-specs).
tools
Run predefined featured workflows via run-workflow MCP. TRIGGER when user names a featured workflow (retargeting, banners at scale, localization, packaging, banner advertising, etc.) or asks to run a known marketing/production workflow. Requires run-workflow MCP. ALWAYS call get_featured_workflow before compose_workflow. DO NOT TRIGGER for custom one-off workflows with no named template — use run-workflow skill.
tools
Migrate an Adobe Commerce App Builder project from the Integration Starter Kit or Checkout Starter Kit to the new App Management approach. Run from the root of the App Builder project to be migrated. Pass --auto to skip confirmation prompts (suitable for CI or batch use) — auto mode prints a summary of all Q&A questions answered with their defaults. Pass --doc-scan-only to scan README.md and env.dist for outdated content without modifying any files. Use when the user wants to migrate an App Builder project from the Integration Starter Kit or Checkout Starter Kit to the App Management approach, or mentions upgrading their Adobe Commerce extension architecture.
development
Add or modify webhook interceptors in an Adobe Commerce app. Use when the user wants to intercept Commerce operations to validate input, append data, or modify behavior — before or after execution. Requires a base app initialized with commerce-app-init.