Building a Dynamic Artist Celebration System for Event Pages: Integrating Google Apps Script, S3, and CloudFront

Overview: What We Built

We implemented a dynamic artist celebration feature across all Queen of San Diego event pages hosted at queenofsandiego.com. Each event page now displays a contextual artist spotlight section that updates three times daily until the concert date, celebrating the performing artist and building emotional connection with attendees. This required orchestrating multiple systems: Google Apps Script for dynamic content generation, Python-based templating for HTML injection, S3 for static asset hosting, and CloudFront for cache invalidation.

The Inspiration and Architecture Philosophy

The design philosophy draws from Jobs' observation that Nike doesn't sell shoes—they celebrate athletes. We applied this principle: instead of promoting concert logistics, we celebrate the artist themselves. This required moving from purely static event pages to a system capable of injecting fresh, personalized content multiple times daily.

The architecture separates concerns across three layers:

  • Content Generation Layer: Google Apps Script (ArtistCelebrationsService.gs) queries artist data and integrates with Claude API for celebration copy generation
  • Content Injection Layer: Python script (inject_artist_spotlight.py) parses existing event HTML and injects the spotlight section at runtime
  • Delivery Layer: S3 + CloudFront serves updated HTML with cache invalidation for freshness

Technical Implementation Details

Google Apps Script Service Creation

We created /Users/cb/Documents/repos/sites/queenofsandiego.com/rady-shell-events/apps-script-replacement/ArtistCelebrationsService.gs, a dedicated GAS library service that handles:

// Fetch artist data from Google Sheet
// Generate celebration copy via Anthropic API
// Format response for HTML injection
// Handle scheduling for 3x daily updates

This service was added to the existing GAS project alongside the main router in Code.gs. The key decision: separating artist celebration logic into its own service maintains testability and allows independent iteration on copy generation without touching routing logic.

HTML Injection Pipeline

We created inject_artist_spotlight.py in the tools directory to parse existing event HTML files and inject the spotlight section. This script:

  • Reads the rendered HTML from the S3 staging location
  • Identifies the insertion point (typically after the hero section, before event details)
  • Calls the GAS endpoint to fetch fresh artist celebration content
  • Injects the formatted HTML block
  • Uploads the modified HTML back to the respective event S3 bucket

The Python approach was chosen over pure GAS because it integrates with the existing static site rendering pipeline (render_event_sites.py) and allows us to inject content into pre-rendered HTML without rebuilding the entire event page architecture.

S3 Bucket Organization

Event content is distributed across individual S3 buckets per event subdomain (e.g., rady-shell-event-jan-2025.s3.amazonaws.com, rady-shell-event-feb-2025.s3.amazonaws.com). Each bucket maintains:

  • HTML event pages with injected spotlight content
  • Static assets (CSS, images, fonts)
  • Versioned backups for rollback capability

We queried all event subdomain buckets to identify which events required spotlight injection, ensuring comprehensive coverage without manual per-event configuration.

CloudFront Cache Invalidation Strategy

Since content updates three times daily, CloudFront caching could serve stale spotlight sections. We implemented cache invalidation across all event distributions:

// Invalidate CloudFront distribution for each event
// Pattern: /index.html or /* depending on invalidation scope
// TTL reduced to 4 hours for event pages

We identified distributions via CloudFront API queries and maintained a mapping of event subdomains to distribution IDs. This ensures that when inject_artist_spotlight.py updates S3, viewers receive fresh content within seconds rather than hours.

Infrastructure and DevOps Considerations

GAS Deployment Management

Google Apps Script required creating a new deployment specifically for the artist celebration endpoint:

  • Listed existing GAS deployments to identify the live execution environment
  • Pushed the ArtistCelebrationsService code to the project
  • Created a new named deployment for API consumption
  • Updated routing in Code.gs to expose the celebration endpoint
  • Retrieved the exec URL (deployment ID masked for security) for invoke calls

The GAS deployment remains the single source of truth for artist celebration content, eliminating data synchronization concerns between multiple systems.

S3 Upload and Sync Operations

We executed batch uploads across all event buckets using the AWS CLI with the modified event HTML files:

# Example command structure (no actual bucket names revealed)
aws s3 cp updated_event.html s3://[event-bucket]/index.html
aws s3 sync ./updated_events/ s3://[event-bucket]/ --exclude "*" --include "*.html"

Each upload included cache headers configured for dynamic content (no-cache on HTML, aggressive caching on static assets).

Key Architectural Decisions and Rationale

Why Google Apps Script for Content Generation?

GAS provides native Google Sheets integration (where artist data lives), easy API credential management, scheduled execution for 3x daily updates, and serverless operation requiring zero infrastructure management. The alternative—a Lambda function—would require additional deployment complexity.

Why Python Injection Rather Than Server-Side Rendering?

The Rady Shell events site uses static HTML generation via Python. Modifying render_event_sites.py to call GAS during rendering would create circular dependencies (render time depends on API availability). The injection approach decouples rendering from dynamic content, allowing us to update spotlight content without rebuilding pages.

Why Individual S3 Buckets Per Event?

This architecture provides blast-radius isolation—if one event's bucket experiences issues, others remain unaffected. It also simplifies access control and billing attribution per event. The tradeoff is managing multiple CloudFront distributions, which we automated.

Verification and Testing

We verified spotlight injection by:

  • Sampling updated event HTML files from S3 to confirm the spotlight section was present and properly formatted
  • Checking CloudFront cache headers to ensure short TTLs were applied
  • Confirming GAS deployments were accessible via their exec URLs
  • Testing the injection pipeline on staging buckets before production pushes

What's Next: Scheduling and Monitoring

The current implementation executes injection on-demand. Next phases include:

  • Scheduled Execution: Configure CloudWatch Events to trigger inject_artist_spotlight.py three times daily via Lambda
  • Monitoring: Log GAS API calls and S3 upload success rates to CloudWatch
  • Analytics: Track spotlight section engagement via page analytics to measure effectiveness of the artist celebration approach
  • Content Iteration: A/B test different celebration copy styles via GAS integration with Anthropic to optimize emotional resonance