Skip to Content
Embed System

Embed System

The /embed route is the core of the project β€” it renders interactive GPX maps inside iframes on the WordPress blog.

Query parameters

ParameterRequiredDescription
gpxYesURL to the GPX file (must be on bttpirineus.org)
chartNoElevation chart behavior: auto (default), show, hide
pageNoWordPress page URL (used for sharing and analytics)
anchorNoAnchor ID for deep-linking (e.g. map-bassegoda)
titleNoCustom display title (defaults to GPX filename)

Example:

/embed?gpx=http://www.bttpirineus.org/wp-content/uploads/Falda%20Bassegoda.gpx&chart=auto

Data flow

  1. page.tsx extracts query params and passes them to EmbedClient
  2. EmbedClient fetches the GPX via /api/gpx?url=... (server-side proxy)
  3. Parses XML with parseGpx() (DOMParser-based, handles missing elevation/time)
  4. Enriches with enrichGpxData(): haversine distances, cumulative elevation, smoothed speeds, gradients, waypoint snapping
  5. Renders the UI components

UI layout

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ LeafletMap β”‚ β”‚ (track in red, hover marker) β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚πŸ‘ 42 β”‚ │⬇ 12 β”‚ β”‚β†— 3 β”‚ β”‚ ← Analytics HUD (bottom-left) β”‚ β””β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚β–² Veure perfilβ”‚ β”‚ ← Chart toggle (when collapsed) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ ElevationChart (SVG) β”‚ ← Collapsible β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Title β”‚πŸ“ Inici │⬇ Descarregarβ”‚β†— Compartir β”‚ ← Bottom bar β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Chart auto-collapse

When chart=auto (the default), the chart behavior depends on the device:

  • Mobile devices (touch, small screen, or mobile UA): chart starts collapsed
  • Very short embeds (innerHeight < 360px): chart starts collapsed
  • Desktop: chart starts expanded

Users can toggle the chart at any time. The chart=show and chart=hide params override auto-detection.

Mobile detection

Uses multiple signals: CSS media queries (hover: none, max-width: 767px), navigator.maxTouchPoints, user agent string, and userAgentData.mobile.

Map features

  • Track rendering: Red polyline (#e74c3c) with start (green) and end (red) circle markers
  • Waypoints: Blue circles with emoji icons based on semantic categories (font, coll, ermita, etc.)
  • Hover sync: Hovering the elevation chart moves a marker along the track on the map
  • Cyclist icon: Animated emoji that flips direction based on track heading
  • Base layers: Hybrid (Esri satellite), Topo (OpenTopoMap), IGN Raster β€” preference persisted in localStorage
  • Responsive: Full viewport height layout, adapts to compact viewports

Bottom bar

  • Title: Derived from GPX filename or explicit title param
  • Inici de ruta: Opens Google Maps directions to the track start point
  • Descarregar el track: Downloads GPX via /api/gpx?url=...&dl=1
  • Compartir: ShareDropdown with Facebook, X, WhatsApp, email, Garmin Connect, QR code, copy link

Analytics

On mount, the embed:

  1. Fetches current view/download/share counts from Supabase (displayed in HUD)
  2. Fires a track_viewed event (deduplicated per session via sessionStorage)
  3. Subsequent actions (download, share, route start) are tracked via dual-write to Supabase + PostHog

Cross-origin iframe considerations

When embedded on bttpirineus.org, the iframe is cross-origin. This means:

  • localStorage may be blocked β€” the layer preference hook fails gracefully
  • PostHog uses persistence: "memory" in iframe contexts (loses cross-page identity, which is acceptable)
  • sessionStorage is used for view deduplication β€” works within the iframe session