🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
287 lines
7.5 KiB
Markdown
287 lines
7.5 KiB
Markdown
# Visualization Tools Setup
|
|
|
|
## Overview
|
|
|
|
For lightweight dashboards displaying GA4/BigQuery insights, we recommend:
|
|
|
|
| Tool | Best For | Complexity |
|
|
|------|----------|------------|
|
|
| **Streamlit** | Quick Python dashboards | Low |
|
|
| **Plotly Dash** | Interactive charts | Medium |
|
|
| **HTML + Chart.js** | Portable, no server | Low |
|
|
|
|
## Option 1: Streamlit Dashboard (Recommended)
|
|
|
|
### Install Dependencies
|
|
|
|
```bash
|
|
cd /path/to/ga-agent-project/visualization
|
|
|
|
# Create virtual environment
|
|
python -m venv venv
|
|
source venv/bin/activate
|
|
|
|
# Install packages
|
|
pip install streamlit pandas plotly google-cloud-bigquery google-analytics-data
|
|
```
|
|
|
|
### Basic Dashboard Template
|
|
|
|
Create `visualization/streamlit_dashboard.py`:
|
|
|
|
```python
|
|
import streamlit as st
|
|
import pandas as pd
|
|
import plotly.express as px
|
|
from google.cloud import bigquery
|
|
from google.analytics.data_v1beta import BetaAnalyticsDataClient
|
|
from google.analytics.data_v1beta.types import RunReportRequest
|
|
|
|
# Page config
|
|
st.set_page_config(
|
|
page_title="GA4 Analytics Dashboard",
|
|
page_icon="📊",
|
|
layout="wide"
|
|
)
|
|
|
|
st.title("📊 GA4 Analytics Dashboard")
|
|
|
|
# Sidebar for configuration
|
|
with st.sidebar:
|
|
st.header("Settings")
|
|
property_id = st.text_input("GA4 Property ID", "YOUR_PROPERTY_ID")
|
|
date_range = st.selectbox(
|
|
"Date Range",
|
|
["Last 7 days", "Last 30 days", "Last 90 days"]
|
|
)
|
|
|
|
# Date mapping
|
|
date_map = {
|
|
"Last 7 days": "7daysAgo",
|
|
"Last 30 days": "30daysAgo",
|
|
"Last 90 days": "90daysAgo"
|
|
}
|
|
|
|
@st.cache_data(ttl=3600)
|
|
def fetch_ga4_data(property_id: str, start_date: str):
|
|
"""Fetch data from GA4 API"""
|
|
client = BetaAnalyticsDataClient()
|
|
|
|
request = RunReportRequest(
|
|
property=f"properties/{property_id}",
|
|
dimensions=[{"name": "date"}],
|
|
metrics=[
|
|
{"name": "activeUsers"},
|
|
{"name": "sessions"},
|
|
{"name": "screenPageViews"}
|
|
],
|
|
date_ranges=[{"start_date": start_date, "end_date": "today"}]
|
|
)
|
|
|
|
response = client.run_report(request)
|
|
|
|
data = []
|
|
for row in response.rows:
|
|
data.append({
|
|
"date": row.dimension_values[0].value,
|
|
"users": int(row.metric_values[0].value),
|
|
"sessions": int(row.metric_values[1].value),
|
|
"pageviews": int(row.metric_values[2].value)
|
|
})
|
|
|
|
return pd.DataFrame(data)
|
|
|
|
# Fetch and display data
|
|
try:
|
|
df = fetch_ga4_data(property_id, date_map[date_range])
|
|
|
|
# Metrics row
|
|
col1, col2, col3 = st.columns(3)
|
|
with col1:
|
|
st.metric("Total Users", f"{df['users'].sum():,}")
|
|
with col2:
|
|
st.metric("Total Sessions", f"{df['sessions'].sum():,}")
|
|
with col3:
|
|
st.metric("Total Pageviews", f"{df['pageviews'].sum():,}")
|
|
|
|
# Charts
|
|
st.subheader("Traffic Over Time")
|
|
fig = px.line(df, x="date", y=["users", "sessions"],
|
|
title="Users & Sessions")
|
|
st.plotly_chart(fig, use_container_width=True)
|
|
|
|
# Raw data
|
|
with st.expander("View Raw Data"):
|
|
st.dataframe(df)
|
|
|
|
except Exception as e:
|
|
st.error(f"Error fetching data: {e}")
|
|
st.info("Ensure GOOGLE_APPLICATION_CREDENTIALS is set")
|
|
```
|
|
|
|
### Run Dashboard
|
|
|
|
```bash
|
|
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/credentials.json"
|
|
streamlit run visualization/streamlit_dashboard.py
|
|
```
|
|
|
|
---
|
|
|
|
## Option 2: Static HTML Dashboard
|
|
|
|
For portable reports without a server:
|
|
|
|
Create `visualization/templates/report.html`:
|
|
|
|
```html
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>GA4 Report</title>
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
<style>
|
|
body { font-family: -apple-system, sans-serif; margin: 40px; }
|
|
.metrics { display: flex; gap: 20px; margin-bottom: 40px; }
|
|
.metric-card {
|
|
background: #f5f5f5;
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
flex: 1;
|
|
}
|
|
.metric-value { font-size: 32px; font-weight: bold; }
|
|
.metric-label { color: #666; }
|
|
.chart-container { max-width: 800px; margin: 40px 0; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>📊 GA4 Analytics Report</h1>
|
|
<p>Generated: <span id="date"></span></p>
|
|
|
|
<div class="metrics">
|
|
<div class="metric-card">
|
|
<div class="metric-value" id="users">--</div>
|
|
<div class="metric-label">Active Users</div>
|
|
</div>
|
|
<div class="metric-card">
|
|
<div class="metric-value" id="sessions">--</div>
|
|
<div class="metric-label">Sessions</div>
|
|
</div>
|
|
<div class="metric-card">
|
|
<div class="metric-value" id="pageviews">--</div>
|
|
<div class="metric-label">Page Views</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="chart-container">
|
|
<canvas id="trafficChart"></canvas>
|
|
</div>
|
|
|
|
<script>
|
|
// Data will be injected by Python script
|
|
const reportData = {{ DATA_JSON }};
|
|
|
|
document.getElementById('date').textContent = new Date().toLocaleDateString();
|
|
document.getElementById('users').textContent = reportData.totals.users.toLocaleString();
|
|
document.getElementById('sessions').textContent = reportData.totals.sessions.toLocaleString();
|
|
document.getElementById('pageviews').textContent = reportData.totals.pageviews.toLocaleString();
|
|
|
|
new Chart(document.getElementById('trafficChart'), {
|
|
type: 'line',
|
|
data: {
|
|
labels: reportData.dates,
|
|
datasets: [{
|
|
label: 'Users',
|
|
data: reportData.users,
|
|
borderColor: '#4285f4',
|
|
tension: 0.1
|
|
}, {
|
|
label: 'Sessions',
|
|
data: reportData.sessions,
|
|
borderColor: '#34a853',
|
|
tension: 0.1
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
plugins: {
|
|
title: { display: true, text: 'Traffic Over Time' }
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|
|
```
|
|
|
|
---
|
|
|
|
## Option 3: Python Chart Generation
|
|
|
|
For generating standalone chart images:
|
|
|
|
```python
|
|
# visualization/scripts/generate_charts.py
|
|
import pandas as pd
|
|
import plotly.express as px
|
|
import plotly.io as pio
|
|
|
|
def generate_traffic_chart(df: pd.DataFrame, output_path: str):
|
|
"""Generate traffic chart as HTML or PNG"""
|
|
fig = px.line(
|
|
df,
|
|
x="date",
|
|
y=["users", "sessions"],
|
|
title="Traffic Overview",
|
|
template="plotly_white"
|
|
)
|
|
|
|
fig.update_layout(
|
|
xaxis_title="Date",
|
|
yaxis_title="Count",
|
|
legend_title="Metric"
|
|
)
|
|
|
|
# Save as interactive HTML
|
|
fig.write_html(f"{output_path}/traffic_chart.html")
|
|
|
|
# Save as static image (requires kaleido)
|
|
# pip install kaleido
|
|
fig.write_image(f"{output_path}/traffic_chart.png", scale=2)
|
|
|
|
return fig
|
|
```
|
|
|
|
---
|
|
|
|
## Integration with Claude Skill
|
|
|
|
The Claude Skill will use these visualization tools via Python scripts:
|
|
|
|
```
|
|
15-ourdigital-ga-agent/
|
|
├── SKILL.md
|
|
├── scripts/
|
|
│ ├── fetch_ga4_data.py # Get data from GA4/BigQuery
|
|
│ ├── generate_report.py # Create visualizations
|
|
│ └── streamlit_app.py # Launch dashboard
|
|
├── templates/
|
|
│ └── report.html # Static report template
|
|
└── assets/
|
|
└── styles.css # Dashboard styling
|
|
```
|
|
|
|
## Requirements File
|
|
|
|
Create `visualization/requirements.txt`:
|
|
|
|
```
|
|
streamlit>=1.28.0
|
|
pandas>=2.0.0
|
|
plotly>=5.18.0
|
|
google-cloud-bigquery>=3.12.0
|
|
google-analytics-data>=0.18.0
|
|
kaleido>=0.2.1
|
|
```
|