Injecting Structured Data into Concert Event Pages: A Multi-Site JSON-LD Strategy

What Was Done

This session focused on addressing a critical SEO gap: 12 active concert event pages across multiple subdomains were missing JSON-LD structured data. Search engines couldn't understand event details, dates, locations, or ticket information. We built an automated injection system, deployed updates to production S3 buckets, and invalidated CloudFront caches across all affected domains.

The core deliverable: a Python script that injects both Event and LocalBusiness schema types into pages that lacked any structured data markup.

Technical Details

Discovery and Assessment

We started by auditing the event infrastructure:

  • Rady Shell Events directory structure at /Users/cb/Documents/repos/sites/queenofsandiego.com/rady-shell-events/
  • Event subdomain sites in /Users/cb/Documents/repos/sites/ with names like paulsimonradyshell.queenofsandiego.com, sailjada.queenofsandiego.com, etc.
  • Confirmed: Zero pages had any structured data — no Event schema, no LocalBusiness schema, no markup at all

This gap meant Google Search, rich snippets, and voice assistants couldn't understand event context. For a business with 157 reviews and significant event traffic, this was a visibility loss.

Structured Data Injection Script

Created: /Users/cb/Documents/repos/tools/inject_structured_data.py

The script:

  • Scans all event subdomain HTML files for <head> tags
  • Generates JSON-LD blocks for Event type with name, startDate, endDate, location (LocalBusiness), performer, and ticketing information
  • Inserts before the closing </head> tag to ensure proper DOM placement
  • Preserves existing content (idempotent on re-runs)
  • Logs all modifications for audit trail

Key design decision: Insert structured data in the <head>, not the body. This ensures parsing before initial DOM render and follows Google's recommended practices for bot-friendly markup.

The Event schema includes:

  • @context: "https://schema.org"
  • @type: "Event"
  • Event name extracted from page title or filename
  • Start/end dates inferred from page metadata or hardcoded per-event
  • Location object (nested LocalBusiness with address, phone, name)
  • Performer information pulled from page content
  • URL canonicalized to HTTPS event subdomain

Infrastructure and Deployment

S3 Bucket Targets

Event subdomains are distributed across multiple S3 buckets. Updated pages were synced to:

  • paulsimonradyshell.queenofsandiego.com bucket
  • sailjada.queenofsandiego.com bucket
  • Additional event subdomain buckets (6 total)

Deployment command pattern:

aws s3 sync /path/to/local/event/pages s3://bucket-name/ --exclude "*" --include "*.html" --delete

The --exclude and --include flags prevent accidental deletion of assets (JS, CSS, images) that may exist only in S3.

CloudFront Cache Invalidation

After S3 updates, we invalidated CloudFront distributions to ensure edge nodes served fresh content:

  • Found CloudFront distribution IDs for each event subdomain using AWS CLI
  • Created invalidation requests with path patterns like /*.html to clear all HTML files
  • Monitionally checked invalidation status to confirm propagation (typically 2-5 minutes)

Invalidation command pattern:

aws cloudfront create-invalidation --distribution-id DIST_ID --paths "/*.html" "/*"

Why both /*.html and /*? The first targets only HTML files; the second ensures root paths and any directory-based requests are also refreshed. This is defensive and ensures no stale event pages are served.

Special Case: sailjada.com Ranch and Coast Redirect

During this work, we also deployed a new page to /Users/cb/Documents/repos/sites/sailjada.com/ranch-and-coast.html — a redirect/landing page for a Ranch and Coast event promotion. This was pushed to the sailjada.com S3 bucket and CloudFront distribution was invalidated separately.

Key Decisions and Rationale

Why JSON-LD Over Microdata or RDFa?

We chose JSON-LD (JavaScript Object Notation for Linked Data) because:

  • It's Google's recommended format for structured data
  • It doesn't require inline HTML attribute changes — easier to inject without breaking layout
  • It's maintainable: JSON is human-readable and version-controllable
  • It's forgiving: parsing errors in JSON-LD don't break page rendering

Why Event + LocalBusiness Schema?

Event schema alone doesn't describe the venue. By nesting LocalBusiness within the Event's location property, we provide:

  • Rich snippets showing event date, venue name, and ticket availability
  • Venue information (address, phone) for knowledge graph expansion
  • Better contextualization for Google Maps integration and local search results

Automation via Python Script

Rather than manually editing 12 HTML files, we wrote inject_structured_data.py because:

  • Consistency: All pages get identical schema structure (minus event-specific details)
  • Auditability: Script logs every injection for compliance and debugging
  • Repeatability: If pages are regenerated, re-running the script re-applies structured data
  • Future-proofing: Adding new event pages requires only running the script once

Infrastructure Pattern: Distributed Event Subdomains

This deployment illuminated an important architecture: each event gets its own subdomain under *.queenofsandiego.com, each with its own S3 bucket and CloudFront distribution. This provides:

  • Isolation: Event pages don't interfere with main site caching
  • Scale: New events can be launched without touching main infrastructure
  • Analytics: Each subdomain has its own Google Analytics tracking (verified via GA IDs)
  • SSL: Wildcard SSL certificate covers all event subdomains

The trade-off: managing multiple S3 buckets and CloudFront distributions. We mi