Injecting Structured Data into Concert Event Pages: A Multi-Subdomain JSON-LD Strategy
What Was Done
Over the course of this development session, we identified a critical SEO gap across 12 concert event pages hosted on multiple Rady Shell event subdomains. None of these pages contained JSON-LD structured data, meaning search engines couldn't understand the event details, venue information, or organizer context. We built an automated injection script, deployed it across all active event properties, and invalidated CloudFront caches to ensure search engines crawled the updated content immediately.
The Problem: Invisible Events to Search Engines
The Rady Shell Events ecosystem consists of multiple event-specific subdomains (e.g., paulsimonradyshell.com, sailjada.queenofsandiego.com) with individual concert landing pages. While the HTML, styling, and booking integrations were production-ready, the pages were completely opaque to search engine crawlers. Without Event schema markup, Google couldn't extract:
- Event name, date, time, and duration
- Venue location (LocalBusiness schema)
- Ticket availability and pricing
- Organizer details (Queen of San Diego)
- Event description and image
This meant zero rich snippets in search results, no event panels in Google Search, and no appearance in Google's Event schema carousel—essentially leaving organic discoverability on the table.
Technical Solution: Automated Structured Data Injection
Discovery Phase: Audit Script
We first inventoried all event pages to understand scope:
find /Users/cb/Documents/repos/sites/queenofsandiego.com/rady-shell-events \
-name "*.html" -type f | wc -l
Then checked which pages already contained JSON-LD:
grep -r "application/ld+json" \
/Users/cb/Documents/repos/sites/queenofsandiego.com/rady-shell-events/ | wc -l
Result: 0 matches. Zero pages had structured data.
Build Phase: Python Injection Script
Created /Users/cb/Documents/repos/tools/inject_structured_data.py with the following capabilities:
- Event Schema Template: Generates
Eventschema with name, description, startDate, endDate, image, and eventStatus - LocalBusiness Nested Schema: Embeds venue information (address, telephone, GBP ID) within the event object
- Head Tag Injection: Locates the closing
</head>tag and injects<script type="application/ld+json">immediately before it - Metadata Extraction: Parses page title, meta description, and Open Graph image to populate schema fields
- Datetime Handling: Converts human-readable dates from page content to ISO 8601 format required by schema.org
The script iterates over all HTML files in the event directories, validates the presence of required fields, and logs failures for manual review.
Infrastructure: Multi-Subdomain Deployment Pipeline
S3 Bucket Targets
Each event subdomain has a dedicated S3 bucket for static assets:
paulsimonradyshell.com→s3://paulsimonradyshell-com-staticsailjada.queenofsandiego.com→s3://sailjada-queenofsandiego-static- Additional event subdomains follow the same naming pattern
Updated pages were synced using:
aws s3 sync /Users/cb/Documents/repos/sites/queenofsandiego.com/rady-shell-events/ \
s3://paulsimonradyshell-com-static/ \
--exclude "*.py" --exclude ".git*" \
--cache-control "max-age=3600"
CloudFront Cache Invalidation
Each event subdomain is fronted by a CloudFront distribution. We identified distribution IDs:
paulsimonradyshell.com→EXXXXXXXXXXXXXsailjada.queenofsandiego.com→EXXXXXXXXXXXXX
After S3 sync, we invalidated all HTML paths to ensure CloudFront served the updated pages immediately:
aws cloudfront create-invalidation \
--distribution-id EXXXXXXXXXXXXX \
--paths "/*.html"
This bypasses the default 24-hour cache TTL for HTML objects, allowing search engine crawlers to fetch updated content within minutes rather than hours.
Key Architectural Decisions
Why JSON-LD Over Microdata or RDFa?
We selected JSON-LD for three reasons:
- Zero markup pollution: Structured data lives in a separate
<script>tag, not interleaved with HTML attributes. This keeps templates clean and maintainable. - Google's preferred format: Google explicitly recommends JSON-LD in their structured data guidelines. RDFa and Microdata receive equal parsing, but JSON-LD has first-class tooling.
- Automation-friendly: A simple script can inject or update JSON blocks without regex-parsing HTML attributes across multiple files.
Why Injection Over Template Generation?
Event pages already existed as static HTML. Rather than refactor all pages to use a templating system (Jinja2, EJS, etc.), we injected structured data as a post-processing step. This approach:
- Requires zero changes to existing page logic or CMS workflow
- Can be run as a CI/CD pre-deployment step or manual batch process
- Allows independent versioning of schema updates from page content
Why Embed LocalBusiness in Event Schema?
Rather than creating a separate LocalBusiness JSON-LD block, we nested the venue as the location property of the Event schema. This follows schema.org best practices for event-venue relationships and prevents duplicate venue data in search engine indices. A single Event object now contains all context about where the concert happens.
Validation & Monitoring
After deployment, we validated using:
- Google Rich Results Test: Submitted each event page URL to verify Event schema was detected and parsed correctly
- Schema.org Validator: Confirmed all required Event properties were present and valid
- CloudFront Cache Stats: Monitored origin request rates to