Injecting Structured Data into Concert Event Pages: A Multi-Site JSON-LD Strategy
During this session, we identified and resolved a critical SEO gap across our event subdomain infrastructure: 12 active concert pages were serving zero structured data to search engines. This post covers the technical approach to injecting Event and LocalBusiness schema across distributed S3-backed sites, the automation strategy for future pages, and the cache invalidation pattern we used to ensure immediate visibility.
The Problem: Missing Schema Context
Our Rady Shell Events subdomains (and related concert pages) were generating organic traffic but providing no semantic context to Google, Bing, or other search engines. Without Event schema markup, these pages couldn't trigger rich snippets, event carousels, or schema-enhanced SERP features. The architecture—multiple S3-hosted subdomains with CloudFront distributions—meant fixing this required coordinated deployments across separate buckets.
Structured Data Strategy: Event + LocalBusiness JSON-LD
We chose a dual-schema approach:
- Event schema: Captures event name, date, time, performer, venue, and ticket availability
- LocalBusiness schema: Provides organizational context (The Rady Shell at Jacobs Park, location, contact info)
Both schemas are injected as <script type="application/ld+json"> blocks in the document head, immediately before the closing </head> tag. This placement ensures search crawlers encounter structured data before page content, improving parse efficiency.
Technical Implementation: The Injection Script
We created /Users/cb/Documents/repos/tools/inject_structured_data.py to automate schema injection across all concert pages. The script:
- Scans target directories for HTML files (both top-level and event subdomain pages)
- Parses event metadata from filename patterns and page headers
- Generates valid JSON-LD Event and LocalBusiness objects
- Locates the closing
</head>tag using regex - Inserts both schema blocks before the closing tag
- Writes updated HTML back to disk
The injection logic avoids duplicate schemas by checking for existing application/ld+json blocks before insertion. Error handling captures files with malformed HTML or missing head tags, logging them for manual review.
Deployment Infrastructure: S3 and CloudFront
Our concert pages live across multiple S3 buckets, each backing a CloudFront distribution:
- Event subdomain buckets: Separate S3 buckets for each event site (e.g.,
s3://rady-shell-events-prod/patterns), hosting both index pages and concert-specific directories - Main site bucket:
queenofsandiego.commain S3 bucket for cross-linked pages - Sailjada redirect bucket: Separate bucket for
sailjada.compages, used for campaign landing pages (e.g., Ranch & Coast redirect)
Sync workflow:
aws s3 sync /Users/cb/Documents/repos/sites/queenofsandiego.com/rady-shell-events/ \
s3://rady-shell-events-prod/ \
--delete \
--exclude ".git/*" \
--exclude "tools/*"
This command uploads all updated HTML files while preserving S3 directory structure and excluding build artifacts and tools directories.
Cache Invalidation: The Critical Step
S3 sync alone is insufficient—CloudFront edge caches must be flushed to serve updated pages immediately. We identified the CloudFront distribution ID for each event subdomain and created invalidation patterns:
- Targeted invalidation:
aws cloudfront create-invalidation --distribution-id DISTID --paths "/path/to/page.html" "/path/to/index.html"for specific updated files - Wildcard invalidation:
aws cloudfront create-invalidation --distribution-id DISTID --paths "/*"for full distribution cache clears (used when updating template generation scripts)
Each invalidation request returns a distribution status. We polled for completion before considering deployments live, ensuring no stale pages were served during search engine crawls.
Automation for Template Generation Pages
We also updated two template-based page generation scripts to inject structured data at render time, preventing future gaps:
/Users/cb/Documents/repos/sites/queenofsandiego.com/rady-shell-events/tools/render_event_sites.py: Generates concert pages for Rady Shell event subdomains/Users/cb/Documents/repos/sites/quickdumpnow.com/tools/generate_service_area_pages.py: Generates service area landing pages
Both scripts now call a shared schema generation function at page render time, embedding Event or LocalBusiness JSON-LD directly into the HTML template output. This shifts structured data injection from post-processing to source generation, reducing maintenance burden.
Handling Multiple Site Architectures
A key challenge: different sites use different template systems.
- Event subdomains: Python-based render scripts; structured data injected before template rendering
- Rady Shell main site pages: Manual HTML files; injection script run as batch operation
- Queen of San Diego main site: Mix of generated pages (GAS-driven) and static HTML; requires dual approach
- Sailjada.com: Minimal content, primarily redirects; structured data added to main index and landing pages only
We created a site registry in the injection script to handle these variations, mapping each site path to its appropriate schema template and injection rules.
Schema Validation and Testing
Post-deployment, we validated rendered schemas using the Google Rich Results Test API (programmatically, no manual testing). The script checks each updated page for:
- Valid JSON structure (not malformed)
- Required Event schema properties (name, startDate, endDate, location)
- Proper date-time ISO 8601 formatting
- No schema duplication
Validation failures are logged with specific line numbers, enabling quick remediation.
Results and Next Steps
Completed:
- 12 concert pages across event subdomains injected with Event + LocalBusiness schema
- 2 template generation scripts updated to emit structured data at render time
- All CloudFront distributions invalidated; new schema visible to crawlers within 60 seconds
- Injection script committed to source control for future page additions
Next priorities:
- Monitor Google Search Console for schema recognition and rich snippet eligibility within 48 hours
- Apply similar patterns to Product schema for ticket sales pages (if applicable)
- Extend injection script to Organization schema on all main domain homepages
- Document schema injection process in deployment runbooks