Back to Projects
Project Overview
Curious about my lifetime skiing stats, I reverse-engineered the Vail Resorts Epic Pass mobile app API
by intercepting HTTPS traffic with Proxyman. This uncovered an undocumented stats endpoint that returns
day-by-day ski history including vertical feet, lift rides, and GPS data. I extracted 256 day records
spanning December 2010 through January 2025 across four Colorado resorts: Vail, Breckenridge, Keystone,
and Beaver Creek. A Python script processes the raw JSON into a clean CSV, and the interactive charts
below are powered by Chart.js loading the data directly from the source.
Objectives
- Extract and preserve personal ski history from the Epic Pass platform via API reverse engineering.
- Build a reusable Python data pipeline to process and enrich the raw API data.
- Create interactive visualizations revealing skiing patterns across 15 seasons.
- Demonstrate API reverse-engineering and browser-based data visualization skills.
Key Results
- Successfully reverse-engineered an undocumented API by intercepting mobile app traffic with Proxyman.
- Extracted 256 day records spanning 15 ski seasons (Dec 2010 – Jan 2025) across 4 Colorado resorts.
- Python script processes raw JSON into enriched CSV with season labels, resort names, and derived fields.
- 8 interactive Chart.js visualizations reveal patterns in resort preference, seasonal trends, and activity levels.
Lifetime Stats
Best Skiing Day
Days by Resort
Days at Each Resort
Resort Distribution
Vertical Feet Over Time
Total Vertical Feet by Season
Days Skied by Season
Average Vertical per Day by Season
Lift Rides & Activity
Total Lift Rides by Season
Day of Week Distribution
Monthly Patterns
Days Skied by Month (All Seasons)
Methodology
- API Discovery: Used Proxyman to intercept HTTPS traffic from the Epic Pass mobile app, identifying the Vail Resorts stats API endpoint and authentication pattern (Bearer token + client credentials).
- Data Extraction: Single authenticated GET request with date range parameters to retrieve all historical day records as JSON (256 records, ~93KB).
- Data Processing: Python script (standard library only — no pip dependencies) parses JSON, maps resort IDs to names, derives ski season labels, and exports an enriched CSV.
- Visualization: Chart.js renders 8 interactive charts directly from the JSON data in the browser with no build tools or frameworks required.
Skills Demonstrated
- API Reverse Engineering: Intercepting and analyzing mobile app network traffic to discover undocumented endpoints and authentication schemes.
- Data Pipeline: Building a Python ETL script to transform raw API responses into analysis-ready datasets with derived fields.
- Data Visualization: Creating interactive browser-based charts with Chart.js and vanilla JavaScript for pattern discovery.
- Web Development: Building a responsive, data-driven project page following modern HTML/CSS patterns.
Technologies Used
Python
JavaScript
Chart.js
API
Data Viz
Updating the Data
The Epic Pass API uses short-lived Bearer tokens (~1.5 hours), so automated refresh isn't practical. To update the dataset:
- Open the Epic Pass mobile app while Proxyman (or a similar HTTPS proxy) is intercepting traffic.
- Navigate to your stats/history in the app to trigger the API call.
- Copy the
Authorization: Bearer <token> header from the intercepted request.
- Make a GET request to the stats endpoint with the fresh token:
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.vailresorts.com/digital/stats/statsapi/v3/Stats/ResortDayStat/YOUR_USER_ID?Limit=1000&MinDate=2010-01-01T00:00:00Z" \
-o ski_day_data.json
- Replace
data/ski_day_data.json with the new response.
- Re-run
python process_ski_data.py to regenerate the CSV.
GitHub Repository
View on GitHub