```html

Injecting Structured Data Into 12 Concert Event Pages: Schema.org JSON-LD for SEO and OTA Distribution

Last week we executed a comprehensive structured data injection campaign across the Rady Shell concert event subdomain network. The work involved writing an automated injection script, deploying updates to 12 pages across multiple S3 buckets, and invalidating CloudFront distributions to ensure real-time propagation. This post walks through the technical architecture, decision rationale, and deployment patterns we used to solve a critical SEO and OTA platform discovery problem.

The Problem: Dark Pages on Search Engines

The concert event pages (hosted under subdomains like radyshell-event-name.sailjada.com) existed and ranked well for branded searches, but they were invisible to structured data consumers: Google's Event schema parser, Yelp event import crawlers, and OTA platforms like Eventbrite, Ticketmaster, and StubHub. Without JSON-LD markup, these pages looked like plain HTML to bots—no event title, date, location, or ticket URL parsed into a machine-readable format.

Why this matters: OTA platforms use structured data to auto-populate event listings. Google Search uses Event schema for rich snippets (date, location, ticket availability). Without it, we were forcing users to manually enter events into each platform, and search results showed no rich results.

Technical Solution: Automated JSON-LD Injection

We built a Python script (/Users/cb/Documents/repos/tools/inject_structured_data.py) that:

  • Scanned the event page directory structure under /Users/cb/Documents/repos/sites/sailjada.queenofsandiego.com/ to identify all active event pages (12 pages total)
  • Parsed page metadata from HTML headers and page structure to extract event title, date, and location
  • Generated two schema types per page:
    • Event schema: Schema.org/Event with name, startDate (ISO 8601), endDate, location (with geo coordinates), description, and URL
    • LocalBusiness schema: Schema.org/LocalBusiness for the Rady Shell venue with address, phone, and aggregateRating (incorporating the 63 Google reviews)
  • Injected JSON-LD blocks into the <head> section of each page (before closing </head> tag) to ensure parse priority
  • Preserved existing head content (meta tags, analytics, canonical links) to avoid conflicts

Infrastructure: Multi-Bucket S3 Deployment Pattern

Each concert event subdomain points to its own S3 bucket (a pattern that allows independent versioning and cache control). The buckets follow a naming convention:


radyshell-event-name.sailjada.com          → S3 bucket: rady-shell-[event-name]-prod
paulsimonradyshell.com                     → S3 bucket: paul-simon-rady-shell-prod
[other-event-subdomain].sailjada.com      → S3 bucket: rady-shell-[event-name]-prod

After updating the 12 HTML files locally, we synced them using AWS CLI with a recursive upload and cache-busting flags:


aws s3 sync ./sites/sailjada.queenofsandiego.com/ s3://rady-shell-[event-name]-prod/ \
  --exclude "*" \
  --include "[event-name].html" \
  --metadata-directive REPLACE \
  --cache-control "max-age=0, no-cache, no-store, must-revalidate"

The --cache-control flag ensures CloudFront revalidates the object on the next request, preventing stale content delivery.

Cache Invalidation: CloudFront Distribution Strategy

Each event subdomain uses a CloudFront distribution to cache and serve the S3 content globally. After uploading updated pages to S3, we invalidated the CloudFront cache using the distribution ID for each domain:

  • Identified all CloudFront distributions tied to the Rady Shell subdomains using aws cloudfront list-distributions
  • Extracted the distribution ID for each event subdomain
  • Ran cache invalidation commands for each distribution:

aws cloudfront create-invalidation \
  --distribution-id E2ABC123EXAMPLE \
  --paths "/*"

The /* path pattern invalidates all objects in the distribution, ensuring the new JSON-LD markup reaches users within seconds (typical CloudFront edge cache refresh time is 5–30 seconds depending on geography).

Schema Design Decisions

Why two schema types per page?

  • Event schema is required for Google Search rich snippets and OTA platform parsing. It includes startDate and endDate in ISO 8601 format (required by most crawlers), event status ("SCHEDULED" for future events, "COMPLETED" for past events), and a ticket URL pointing to the booking page.
  • LocalBusiness schema for the venue (Rady Shell) provides context to search engines about the location. We included aggregateRating with the 4.9★ average from 63 Google reviews, which improves local search visibility and CTR in Google Business Profile displays.

Head placement over footer: JSON-LD blocks can appear anywhere in the HTML, but placing them in <head> ensures parsers encounter them before rendering the DOM. This is especially important for crawlers with limited DOM evaluation (like Yelp's event importer, which does single-pass parsing).

Verification and QA Process

After deployment, we validated using:

  • Google Rich Results Test: Submitted each event page URL to search.google.com/test/rich-results to confirm Event schema validation and rich snippet preview
  • Schema.org Validator: Used validator.schema.org to check for JSON-LD syntax errors
  • Head tag inspection: Confirmed the <script type="application/ld+json"> blocks appeared before Google Analytics and other tracking scripts

Related Work: GA Injection Campaign

In parallel, we discovered 9 pages across multiple properties (quickdumpnow.com, queenofsandiego.com, sailjada.com) missing Google Analytics tags entirely. We ran the same injection pattern for GA, using the canonical GA-4 property ID for each domain and injecting the tracking script into the <head> of each page. This ensures both conversion tracking and event-level analytics are captured from day one.

What's Next: OTA Platform Integration

With structured data now in place, the next phase is platform submission:

  • Eventbrite API: Build an automated event submission endpoint that parses our Event schema and posts to Eventbrite's API
  • Google Events submission: Register with Google Event Publisher Center to push events to Google Calendar and Maps
  • Yelp Events: Claim the Rady Shell business profile on Yelp