1 Site Architecture
E-commerce site architecture determines how effectively search engines crawl, index, and rank your pages. A well-structured site concentrates topical authority, distributes link equity, and keeps every product reachable within three clicks of the homepage.
Flat vs. Deep Hierarchy
Aim for a 3-level maximum depth. Flat architectures allow crawlers to discover all pages quickly and keep users from getting lost in navigation. The ideal structure is:
URL Structure
URLs should mirror the hierarchy and remain readable by both humans and crawlers:
/category/subcategory/product-name
Examples:
/chassis/modular-chassis/patriot-pro-series-frame
/suspension/air-shocks/adjustable-air-ride-kit
/accessories/lighting/led-underbody-light-bar
Hub-and-Spoke Internal Linking
Each category page acts as a hub that links outward to its products (spokes) and each product links back to its parent category. This model concentrates topical authority on hub pages while ensuring every product inherits relevance.
Silo Structure for Topical Authority
Group related pages into content silos: chassis pages link to other chassis pages, suspension pages link within the suspension silo. Cross-silo links should be used sparingly and intentionally. This signals to search engines that each section is a deep, authoritative resource on its topic.
2 Performance & Core Web Vitals
Google's Core Web Vitals are the primary performance metrics that directly influence search rankings and user experience. Meeting all three thresholds is non-negotiable for competitive e-commerce.
The Three Core Web Vitals
| Metric | Good | Needs Improvement | Poor |
|---|---|---|---|
| LCP (Largest Contentful Paint) | 0 – 2.5s | 2.5 – 4.0s | > 4.0s |
| INP (Interaction to Next Paint) | 0 – 200ms | 200 – 500ms | > 500ms |
| CLS (Cumulative Layout Shift) | 0 – 0.1 | 0.1 – 0.25 | > 0.25 |
Industry Benchmarks & Impact
- LCP > 3s: 23% more traffic loss compared to sites meeting the threshold
- Poor INP (> 300ms): 31% traffic drop from sluggish interactivity
Swappie invested in Core Web Vitals optimization and achieved a 55% improvement in LCP and 91% improvement in CLS. The direct business result: a 42% increase in mobile revenue. This demonstrates the tangible ROI of performance engineering for e-commerce.
3 Schema Markup
Structured data (JSON-LD format) tells search engines exactly what your content represents. For e-commerce, schema markup enables rich results: star ratings, prices, availability badges, and FAQ expansions directly in search results.
Product Schema
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Patriot Pro Series Modular Chassis",
"image": "https://patriotchassis.com/images/pro-series-chassis.jpg",
"description": "Full modular chassis for classic 4x4 trucks. Bolt-on design, laser-cut steel, adjustable wheelbase.",
"sku": "PC-PRO-001",
"brand": {
"@type": "Brand",
"name": "Patriot Chassis"
},
"offers": {
"@type": "Offer",
"price": "8995.00",
"priceCurrency": "USD",
"availability": "https://schema.org/InStock",
"url": "https://patriotchassis.com/chassis/modular/pro-series"
}
}
</script>
BreadcrumbList Schema
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://patriotchassis.com/"
},
{
"@type": "ListItem",
"position": 2,
"name": "Chassis",
"item": "https://patriotchassis.com/chassis/"
},
{
"@type": "ListItem",
"position": 3,
"name": "Pro Series Modular Chassis",
"item": "https://patriotchassis.com/chassis/modular/pro-series"
}
]
}
</script>
Organization & LocalBusiness Schema
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"name": "Patriot Chassis",
"url": "https://patriotchassis.com",
"logo": "https://patriotchassis.com/images/logo.png",
"contactPoint": {
"@type": "ContactPoint",
"telephone": "+1-208-555-0199",
"contactType": "sales"
},
"address": {
"@type": "PostalAddress",
"streetAddress": "123 Mountain Workshop Rd",
"addressLocality": "Sandpoint",
"addressRegion": "ID",
"postalCode": "83864",
"addressCountry": "US"
},
"telephone": "+1-208-555-0199",
"openingHoursSpecification": [
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
"opens": "08:00",
"closes": "17:00"
}
]
}
</script>
FAQPage Schema
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "What trucks does the Patriot chassis fit?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Our modular chassis fits 1967-1972 Chevrolet C/K, 1965-1979 Ford F-Series, and 1972-1993 Dodge D/W trucks."
}
},
{
"@type": "Question",
"name": "How long does installation take?",
"acceptedAnswer": {
"@type": "Answer",
"text": "A typical chassis swap takes 40-60 hours for an experienced builder. Our bolt-on design eliminates welding for most installations."
}
}
]
}
</script>
Review & AggregateRating Schema
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Adjustable Air Ride Shock Kit",
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.8",
"reviewCount": "127",
"bestRating": "5",
"worstRating": "1"
},
"review": {
"@type": "Review",
"author": { "@type": "Person", "name": "Mike R." },
"reviewRating": {
"@type": "Rating",
"ratingValue": "5"
},
"reviewBody": "Night and day difference in ride quality. Installation was straightforward with the included instructions."
}
}
</script>
Star ratings and review counts displayed directly in search results significantly increase click-through rates. Ensure all review data is genuine and sourced from verified purchasers.
4 Image Optimization
Images typically account for 50-70% of total page weight on e-commerce sites. Proper optimization directly impacts LCP scores, bandwidth costs, and conversion rates.
Format Strategy
| Format | Compression vs. JPEG | Browser Support | Role |
|---|---|---|---|
| AVIF | 50%+ smaller | Chrome, Firefox, Safari 16.4+ | Primary format |
| WebP | 25-34% smaller | All modern browsers | Fallback format |
| JPEG | Baseline | Universal | Legacy fallback |
The <picture> Element for Format Negotiation
<picture>
<!-- AVIF: best compression, served to supporting browsers -->
<source
type="image/avif"
srcset="chassis-400w.avif 400w,
chassis-800w.avif 800w,
chassis-1200w.avif 1200w"
sizes="(max-width: 600px) 100vw,
(max-width: 1024px) 50vw,
33vw">
<!-- WebP: good compression, wide support -->
<source
type="image/webp"
srcset="chassis-400w.webp 400w,
chassis-800w.webp 800w,
chassis-1200w.webp 1200w"
sizes="(max-width: 600px) 100vw,
(max-width: 1024px) 50vw,
33vw">
<!-- JPEG: universal fallback -->
<img
src="chassis-800w.jpg"
srcset="chassis-400w.jpg 400w,
chassis-800w.jpg 800w,
chassis-1200w.jpg 1200w"
sizes="(max-width: 600px) 100vw,
(max-width: 1024px) 50vw,
33vw"
alt="Patriot Pro Series chassis, isometric view"
width="1200"
height="800"
loading="lazy"
decoding="async">
</picture>
Size Budgets
loading="lazy" on images below the fold. Never lazy-load the LCP element (hero image, primary product image). The LCP image should load eagerly and be preloaded in the <head>.
<head>
<link rel="preload" as="image" type="image/avif"
href="hero-chassis-1200w.avif"
imagesrcset="hero-chassis-800w.avif 800w,
hero-chassis-1200w.avif 1200w"
imagesizes="100vw">
</head>
An e-commerce site reduced total image payload from 2.8MB to 0.95MB (a 66% reduction) through format conversion (AVIF/WebP), responsive sizing, and proper compression. The result: an 8% increase in conversion rate from faster page loads and improved user experience on mobile connections.
5 Caching Strategy
A proper caching strategy ensures returning visitors and repeat navigations are near-instant while guaranteeing fresh content is always delivered when it changes.
Cache-Control Headers by Asset Type
| Asset Type | Cache-Control Header | Rationale |
|---|---|---|
| Static assets (CSS, JS, images, fonts) | public, max-age=31536000, immutable |
Cache for 1 year; content-hashed filenames handle updates |
| HTML pages | no-cache, max-age=0, must-revalidate |
Always revalidate; use ETag for conditional requests |
| API responses | private, no-store |
User-specific data must never be cached in shared caches |
Cache-Busting with Version Hashes
<!-- Before: cache problems on deploy -->
<link rel="stylesheet" href="/css/styles.css">
<script src="/js/app.js"></script>
<!-- After: content hash in filename, cache forever -->
<link rel="stylesheet" href="/css/styles.a3f8c2e1.css">
<script src="/js/app.7b4d9e0f.js"></script>
Build tools (Vite, Webpack) automatically generate content hashes. When the file content changes, the hash changes, forcing browsers to fetch the new version. When it hasn't changed, the cached copy is used for a full year.
Service Workers for Progressive Caching
// Register service worker for offline/progressive caching
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(reg => console.log('SW registered:', reg.scope))
.catch(err => console.error('SW registration failed:', err));
}
// sw.js — Cache-first strategy for static assets
self.addEventListener('fetch', event => {
if (event.request.destination === 'image' ||
event.request.destination === 'style' ||
event.request.destination === 'script') {
event.respondWith(
caches.match(event.request).then(cached =>
cached || fetch(event.request).then(response => {
const clone = response.clone();
caches.open('static-v1').then(cache =>
cache.put(event.request, clone)
);
return response;
})
)
);
}
});
If-None-Match with the stored ETag. If the content hasn't changed, the server responds with 304 Not Modified (no body), saving bandwidth and rendering time.
6 CSS / JS Optimization
Render-blocking resources are the primary cause of slow LCP and poor INP scores. Optimizing how CSS and JavaScript are delivered can cut seconds from initial page load.
Inline Critical CSS
<head>
<!-- Critical CSS inlined: renders above-fold content immediately -->
<style>
/* Only styles needed for above-the-fold content */
body { font-family: system-ui, sans-serif; margin: 0; }
.hero { position: relative; height: 80vh; background: #0f172a; }
.hero h1 { color: #fff; font-size: 2.5rem; }
.nav { display: flex; align-items: center; padding: 1rem 2rem; }
</style>
<!-- Full stylesheet loaded asynchronously -->
<link rel="preload" href="/css/styles.a3f8c2e1.css" as="style"
onload="this.onload=null;this.rel='stylesheet'">
<noscript>
<link rel="stylesheet" href="/css/styles.a3f8c2e1.css">
</noscript>
</head>
Defer Non-Critical JavaScript
<!-- Critical: loads and executes immediately (use sparingly) -->
<script src="/js/critical.js"></script>
<!-- Defer: downloads in parallel, executes after HTML parsing -->
<script src="/js/app.js" defer></script>
<!-- Async: downloads in parallel, executes as soon as ready -->
<script src="/js/analytics.js" async></script>
<!-- Module: deferred by default, supports import/export -->
<script type="module" src="/js/components.js"></script>
DOM Size & Preloading
<head>
<!-- Preload critical font -->
<link rel="preload" href="/fonts/inter-var.woff2" as="font"
type="font/woff2" crossorigin>
<!-- Preload hero image -->
<link rel="preload" href="/images/hero-chassis.avif" as="image"
type="image/avif">
<!-- Preconnect to third-party origins -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
</head>
Code Splitting
For large applications, split JavaScript into route-based chunks so users only download the code needed for the current page:
// Instead of importing everything upfront:
// import { ProductGallery } from './components/ProductGallery';
// Dynamically import when needed:
const loadGallery = async () => {
const { ProductGallery } = await import('./components/ProductGallery.js');
ProductGallery.init(document.getElementById('gallery'));
};
// Load gallery only when user scrolls to it
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
loadGallery();
observer.disconnect();
}
});
});
observer.observe(document.getElementById('gallery'));
7 Security
E-commerce sites handle sensitive customer data and financial transactions. Security is not optional; it is a fundamental architectural requirement.
HTTPS Everywhere
All traffic must be served over HTTPS. HTTP requests should redirect with a 301 Moved Permanently to the HTTPS equivalent. HSTS headers prevent downgrade attacks:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Content Security Policy (CSP)
Content-Security-Policy:
default-src 'self';
script-src 'self' https://js.stripe.com https://www.googletagmanager.com;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
img-src 'self' data: https://res.cloudinary.com;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.stripe.com https://www.google-analytics.com;
frame-src https://js.stripe.com;
object-src 'none';
base-uri 'self';
form-action 'self';
Secure Cookies
Set-Cookie: session_id=abc123;
HttpOnly; /* Not accessible via JavaScript */
Secure; /* Only sent over HTTPS */
SameSite=Lax; /* Prevents CSRF in most scenarios */
Path=/;
Max-Age=86400
Input Validation & PCI DSS
Input Validation at System Boundaries
- Validate and sanitize all user input on the server side, regardless of client-side validation
- Use parameterized queries (prepared statements) for all database operations
- Encode output to prevent XSS (cross-site scripting)
- Implement rate limiting on authentication and checkout endpoints
PCI DSS Compliance for Payment Handling
- Never store raw credit card numbers, CVVs, or full magnetic stripe data
- Use tokenized payment methods (Stripe Elements, PayPal SDK) that keep card data off your servers entirely
- Maintain PCI SAQ-A or SAQ-A-EP compliance when using hosted payment fields
- Log and monitor all access to payment-related systems
8 API Design
A well-designed REST API powers the e-commerce backend: product catalog, cart management, checkout flow, and order tracking. Consistency and documentation are critical.
RESTful Resource Design
Use resource-based URIs with nouns, not verbs. HTTP methods express the action:
| Method | Endpoint | Action |
|---|---|---|
| GET | /api/v1/products |
List all products (paginated) |
| GET | /api/v1/products/:id |
Get single product details |
| POST | /api/v1/cart/items |
Add item to cart |
| PUT | /api/v1/cart/items/:id |
Update cart item quantity |
| DELETE | /api/v1/cart/items/:id |
Remove item from cart |
| POST | /api/v1/checkout |
Initiate checkout / create order |
| GET | /api/v1/orders |
List user's orders |
| GET | /api/v1/orders/:id |
Get order details + tracking |
OpenAPI Specification
openapi: "3.0.3"
info:
title: Patriot Chassis E-Commerce API
version: "1.0.0"
description: Product catalog, cart, checkout, and order management.
paths:
/api/v1/products:
get:
summary: List products
parameters:
- name: category
in: query
schema: { type: string }
- name: page
in: query
schema: { type: integer, default: 1 }
- name: limit
in: query
schema: { type: integer, default: 20, maximum: 100 }
responses:
'200':
description: Paginated product list
content:
application/json:
schema:
type: object
properties:
data:
type: array
items: { $ref: '#/components/schemas/Product' }
meta:
$ref: '#/components/schemas/Pagination'
Authentication & Authorization
Stateless Requests with RBAC
- Stateless: Each request carries its own authentication (JWT bearer token or session cookie). The server stores no session state.
- Role-Based Access Control (RBAC): Define roles (customer, staff, admin) with specific permissions. Customers can view products and manage their own orders. Staff can manage inventory. Admins have full access.
- All endpoints validate both authentication (who are you?) and authorization (are you allowed to do this?).
9 Analytics & Monitoring
Data-driven decision making requires comprehensive tracking across the customer journey. Every optimization in this document should be measured against real user data.
GA4 Enhanced E-Commerce Tracking
// Product viewed
gtag('event', 'view_item', {
currency: 'USD',
value: 8995.00,
items: [{
item_id: 'PC-PRO-001',
item_name: 'Patriot Pro Series Chassis',
item_category: 'Chassis',
price: 8995.00,
quantity: 1
}]
});
// Added to cart
gtag('event', 'add_to_cart', {
currency: 'USD',
value: 8995.00,
items: [{ item_id: 'PC-PRO-001', item_name: 'Patriot Pro Series Chassis',
price: 8995.00, quantity: 1 }]
});
// Checkout started
gtag('event', 'begin_checkout', {
currency: 'USD',
value: 9245.00,
items: [/* cart items */]
});
// Purchase completed
gtag('event', 'purchase', {
transaction_id: 'ORD-20260217-001',
currency: 'USD',
value: 9245.00,
tax: 0,
shipping: 250.00,
items: [{ item_id: 'PC-PRO-001', item_name: 'Patriot Pro Series Chassis',
price: 8995.00, quantity: 1 }]
});
Heat Mapping & Session Recording
| Tool | Capability | Use Case |
|---|---|---|
| Hotjar | Heatmaps, recordings, surveys, funnels | Identify where users click, scroll, and drop off |
| CrazyEgg | Click maps, scroll maps, confetti reports | Granular click analysis by source/segment |
| Session Recording | Replay individual user sessions | Diagnose UX friction, form abandonment, rage clicks |
Real User Monitoring (RUM)
Why RUM Over Synthetic Testing
Synthetic tests (Lighthouse, PageSpeed Insights) measure performance in controlled lab conditions. RUM measures actual performance experienced by real users across diverse devices, networks, and geographies. Use both, but prioritize RUM data for business decisions.
- Track CWV (LCP, INP, CLS) from real visitors using the
web-vitalslibrary - Segment by device type, connection speed, and geography
- Set alerts for performance regressions (e.g., p75 LCP exceeds 2.5s)
import { onLCP, onINP, onCLS } from 'web-vitals';
function sendToAnalytics(metric) {
const body = JSON.stringify({
name: metric.name,
value: metric.value,
rating: metric.rating, // 'good', 'needs-improvement', 'poor'
delta: metric.delta,
id: metric.id,
url: window.location.href,
userAgent: navigator.userAgent
});
// Use sendBeacon for reliability (fires even on page unload)
navigator.sendBeacon('/api/v1/analytics/vitals', body);
}
onLCP(sendToAnalytics);
onINP(sendToAnalytics);
onCLS(sendToAnalytics);
10 Error Handling
Errors are inevitable. How your site handles them determines whether a frustrated user bounces or recovers their journey and completes a purchase.
404 Page Optimization
An optimized 404 page must include:
Elements of an Effective 404 Page
- Search bar: Prominently placed so users can find what they were looking for
- Popular products: Display 4-8 best-selling or featured items
- Category navigation: Link to all major product categories
- Incentive coupon: Offer a small discount to recover the session (e.g., "Sorry about that — here's 10% off")
- Correct HTTP status: Must return an actual
404HTTP status code, not a 200 with "not found" text
server {
# ...
error_page 404 /404.html;
location = /404.html {
root /home/patriot/domains/patriotchassis.com/public_html;
internal; # Only served on actual 404 errors, not direct requests
}
}
Graceful Degradation for JavaScript Failures
Progressive Enhancement Strategy
- Core content (product info, prices, images) must be visible without JavaScript
- Interactive features (add-to-cart, filtering, live search) enhance the experience when JS is available
- Wrap JS-dependent features in try/catch blocks with meaningful fallbacks
- Use
<noscript>to provide alternative content or redirect to a basic version
// Wrap non-critical features in error boundaries
async function initProductGallery() {
try {
const gallery = await import('./components/gallery.js');
gallery.init();
} catch (error) {
console.error('Gallery failed to load:', error);
// Fallback: show static images that are already in the HTML
document.getElementById('gallery-fallback').style.display = 'block';
}
}
// Global error handler for uncaught exceptions
window.addEventListener('error', event => {
// Log to monitoring service, but don't break the page
fetch('/api/v1/errors', {
method: 'POST',
body: JSON.stringify({
message: event.message,
source: event.filename,
line: event.lineno,
url: window.location.href
}),
keepalive: true
});
});
11 Third-Party Integrations
E-commerce requires specialized services for payments, shipping, and tax calculation. Choose integrations that provide reliability, developer experience, and PCI compliance.
Payment Processing
| Provider | Strengths | Integration Pattern |
|---|---|---|
| Stripe | Developer-first API, Stripe Elements (hosted fields), 135+ currencies | Client-side Stripe.js + server-side PaymentIntents API |
| PayPal | Consumer trust, buyer protection, PayPal/Venmo wallet | PayPal JS SDK with server-side Orders API |
| Apple Pay / Google Pay | One-tap checkout, biometric auth, highest mobile conversion | Payment Request API or Stripe Payment Element |
// Initialize Stripe
const stripe = Stripe('pk_live_...');
const elements = stripe.elements({
clientSecret: '{{CLIENT_SECRET_FROM_SERVER}}',
appearance: { theme: 'stripe' }
});
// Mount the Payment Element (handles cards, wallets, BNPL)
const paymentElement = elements.create('payment');
paymentElement.mount('#payment-element');
// Handle form submission
document.getElementById('checkout-form').addEventListener('submit', async (e) => {
e.preventDefault();
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: 'https://patriotchassis.com/order-confirmation'
}
});
if (error) {
document.getElementById('error-message').textContent = error.message;
}
});
Shipping & Fulfillment
| Provider | Features |
|---|---|
| EasyPost | Multi-carrier rate comparison, label generation, tracking webhooks, address verification |
| ShipStation | Real-time shipping rates, batch label printing, branded tracking pages, returns management |
Tax Calculation
| Provider | Features |
|---|---|
| TaxJar | Real-time sales tax calculation, nexus tracking, automated filing for all US jurisdictions |
| Avalara | Global tax compliance (VAT, GST, sales tax), 1,200+ tax rule integrations, exemption management |
12 A/B Testing
A/B testing removes guesswork from optimization. Instead of debating whether a red or blue CTA button performs better, you measure it against real user behavior.
Platform Comparison
| Platform | Type | Strengths | Best For |
|---|---|---|---|
| GrowthBook | Open-source | Code-driven experiments, feature flags, self-hosted, free | Engineering-led teams |
| Split.io | SaaS | Feature flags + experimentation, real-time targeting, SDKs for all platforms | Enterprise, multi-platform |
| VWO | SaaS | Visual editor, heatmaps, surveys, full-stack testing | Marketing-led teams, e-commerce |
| Convert | SaaS | Privacy-first (no personal data), flicker-free, advanced targeting | GDPR-conscious e-commerce |
Feature Flags for Gradual Rollout
import { GrowthBook } from '@growthbook/growthbook';
const gb = new GrowthBook({
apiHost: 'https://cdn.growthbook.io',
clientKey: 'sdk-abc123',
enableDevMode: process.env.NODE_ENV === 'development',
trackingCallback: (experiment, result) => {
// Send experiment exposure to GA4
gtag('event', 'experiment_viewed', {
experiment_id: experiment.key,
variation_id: result.key
});
}
});
await gb.init();
// Feature flag: show new checkout flow to 20% of users
if (gb.isOn('new-checkout-flow')) {
renderNewCheckout();
} else {
renderClassicCheckout();
}
// Multivariate test: which CTA color converts best?
const ctaColor = gb.getFeatureValue('cta-button-color', 'blue');
document.querySelector('.cta-btn').style.backgroundColor = ctaColor;
A/B Testing Best Practices for E-Commerce
- Test one variable at a time: Changing the CTA color AND the headline simultaneously makes it impossible to attribute the result
- Run tests for full business cycles: At minimum 1-2 weeks to account for weekday/weekend variation
- Prioritize high-impact pages: Product pages, cart, and checkout have the most direct revenue impact
- Document everything: Record hypotheses, results, and learnings for institutional knowledge
- Avoid the peeking problem: Do not stop tests early when results look promising; wait for statistical significance