Content operations skills for AEM Edge Delivery Services: page auditing, SEO optimization, AI search (GEO), WCAG accessibility, bulk metadata, structured data, sitemap validation, and content diffing. Complements the EDS development skills with operational tooling for content teams.
90%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
This document covers the performance constraints and patterns specific to Adobe Edge Delivery Services. Use it as a reference when auditing EDS pages for performance.
| Metric | Target | Notes |
|---|---|---|
| Lighthouse Performance | 100 | All four categories should score 100 |
| Lighthouse Accessibility | 100 | |
| Lighthouse Best Practices | 100 | |
| Lighthouse SEO | 100 | |
| LCP (mobile) | < 1560ms | Largest Contentful Paint on a throttled 4G connection |
| CLS | < 0.05 | Cumulative Layout Shift |
| INP | < 200ms | Interaction to Next Paint |
EDS is engineered to hit Lighthouse 100/100/100/100 out of the box. If a page drops below these scores, something in the content or customization is the cause.
The most critical performance constraint in EDS is the LCP budget: everything that loads before the Largest Contentful Paint element must stay under approximately 100KB aggregate.
aem.css (the boilerplate stylesheet)aem.js (the boilerplate script)loading="eager" on images in the first section. If you see loading="lazy" on the LCP candidate, it is a bug or an override.fetchpriority="high". This hints the browser to prioritize the LCP image download.EDS uses a three-phase loading strategy: Eager, Lazy, Delayed. Every resource on the page belongs to exactly one phase.
Loads immediately with the initial page render.
Belongs here:
aem.js — the EDS boilerplate scriptaem.css — the EDS boilerplate stylesheetstyles.css — site-level styles (custom properties, typography, layout)scripts.js — site-level scripts (header/footer loading, section decoration)Does NOT belong here:
Loads after the first section renders and the LCP event fires.
Belongs here:
loading="lazy")How it works: The EDS boilerplate walks the DOM section by section. After the first section renders, it loads block CSS/JS for subsequent sections on demand.
Loads well after the page is interactive. Managed by delayed.js.
Belongs here:
How it works: delayed.js is loaded 3 seconds after the page load event. It then loads any third-party scripts. This ensures third-party code never competes with core page rendering.
| Violation | Impact | Fix |
|---|---|---|
Analytics script in head.html | Blocks LCP, adds 50-200ms | Move to delayed.js |
| Chat widget loaded eagerly | Adds 100-500KB before LCP | Move to delayed.js |
| Block CSS loaded for off-screen block | Unnecessary render-blocking CSS | Ensure block is not in the first section |
loading="lazy" on LCP image | LCP delayed by 200-500ms | Remove the attribute or set to eager |
EDS uses a specific font loading approach that differs from most web performance advice.
@font-face declarations with font-display: swap.size-adjust. Every custom font must have a system font fallback with size-adjust, ascent-override, descent-override, and line-gap-override values tuned to match the custom font metrics. This prevents CLS when the custom font loads.@font-face {
font-family: 'Brand Sans Fallback';
src: local('Arial');
size-adjust: 95.2%;
ascent-override: 103%;
descent-override: 28%;
line-gap-override: 0%;
}The fallback font is used immediately on first paint. When the real font loads, font-display: swap switches it in with minimal CLS because size-adjust ensures the metrics match closely.
EDS automatically optimizes images through its media pipeline, but authors and developers must follow certain rules.
./media_* paths are automatically optimized, resized, and served in WebP/AVIF formats with responsive srcset.loading="eager" to below-fold images.EDS generates responsive <picture> elements with multiple sources:
<picture>
<source type="image/webp"
srcset="./media_hash.jpeg?width=750&format=webply&optimize=medium 750w,
./media_hash.jpeg?width=2000&format=webply&optimize=medium 2000w"
sizes="100vw">
<img src="./media_hash.jpeg?width=750&format=jpeg&optimize=medium"
loading="lazy" alt="Description">
</picture>The head.html file is injected into every page's <head>. It must be minimal.
<script> and <link> tags (aem.js, aem.css)<meta> tags for viewport, charset, theme-color<style> for CLS prevention (hiding the page until styles load)delayed.js)styles.css)EDS sites should use CSS custom properties (variables) for all theme values. This enables:
:root {
--color-brand-primary: #0045ff;
--color-text: #2c2c2c;
--color-background: #ffffff;
--font-family-heading: 'Brand Sans', 'Brand Sans Fallback', sans-serif;
--font-family-body: 'Brand Serif', 'Brand Serif Fallback', serif;
--spacing-m: 16px;
--spacing-l: 32px;
}Hardcoded hex colors, pixel values, or font names directly in block CSS (instead of referencing custom properties) are a code smell and a P2 audit finding.
.tessl-plugin
skills
accessibility-fix
bulk-metadata
content-audit
content-diff
cwv-optimizer
geo-rewrite
heading-optimizer
image-seo
internal-linking
link-rot-scanner
optel-interpreter
performance-budget
product-page-seo
query-index-optimizer
sitemap-audit
structured-data