From openclaudia-openclaudia-skills
Pulls GA4 reports on traffic, users, engagement, conversions, and audience segments via Google Analytics Data API. Use for website analytics analysis.
npx claudepluginhub joshuarweaver/cascade-communication --plugin openclaudia-openclaudia-skillsThis skill uses the workspace's default tool permissions.
Pull reports and insights from GA4 using the Google Analytics Data API.
Creates isolated Git worktrees for feature branches with prioritized directory selection, gitignore safety checks, auto project setup for Node/Python/Rust/Go, and baseline verification.
Executes implementation plans in current session by dispatching fresh subagents per independent task, with two-stage reviews: spec compliance then code quality.
Dispatches parallel agents to independently tackle 2+ tasks like separate test failures or subsystems without shared state or dependencies.
Pull reports and insights from GA4 using the Google Analytics Data API.
Requires Google OAuth credentials:
GOOGLE_CLIENT_IDGOOGLE_CLIENT_SECRETSet credentials in .env, .env.local, or ~/.claude/.env.global.
# Step 1: Get authorization code (user must visit this URL in browser)
echo "https://accounts.google.com/o/oauth2/v2/auth?client_id=${GOOGLE_CLIENT_ID}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://www.googleapis.com/auth/analytics.readonly&response_type=code&access_type=offline"
# Step 2: Exchange code for tokens
curl -s -X POST "https://oauth2.googleapis.com/token" \
-d "code={AUTH_CODE}" \
-d "client_id=${GOOGLE_CLIENT_ID}" \
-d "client_secret=${GOOGLE_CLIENT_SECRET}" \
-d "redirect_uri=urn:ietf:wg:oauth:2.0:oob" \
-d "grant_type=authorization_code"
# Step 3: Refresh an expired token
curl -s -X POST "https://oauth2.googleapis.com/token" \
-d "refresh_token={REFRESH_TOKEN}" \
-d "client_id=${GOOGLE_CLIENT_ID}" \
-d "client_secret=${GOOGLE_CLIENT_SECRET}" \
-d "grant_type=refresh_token"
Store the refresh token securely. The access token expires after 1 hour.
curl -s -H "Authorization: Bearer ${GA_ACCESS_TOKEN}" \
"https://analyticsadmin.googleapis.com/v1beta/accountSummaries" \
| python3 -c "
import json, sys
data = json.load(sys.stdin)
for acct in data.get('accountSummaries', []):
for prop in acct.get('propertySummaries', []):
print(f\"{prop['property']} | {prop.get('displayName','')} | Account: {acct.get('displayName','')}\")
"
The property ID format is properties/XXXXXXXXX.
POST https://analyticsdata.googleapis.com/v1beta/{property_id}:runReport
All report requests use POST with a JSON body. Always include Authorization: Bearer {ACCESS_TOKEN}.
Get sessions, users, page views, and engagement rate over a date range.
curl -s -X POST \
"https://analyticsdata.googleapis.com/v1beta/properties/{PROPERTY_ID}:runReport" \
-H "Authorization: Bearer ${GA_ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"dateRanges": [{"startDate": "30daysAgo", "endDate": "today"}],
"metrics": [
{"name": "sessions"},
{"name": "totalUsers"},
{"name": "newUsers"},
{"name": "screenPageViews"},
{"name": "engagementRate"},
{"name": "averageSessionDuration"},
{"name": "bounceRate"}
]
}'
today, yesterday7daysAgo, 14daysAgo, 28daysAgo, 30daysAgo, 90daysAgo2024-01-01See where users come from (channels, sources, campaigns).
curl -s -X POST \
"https://analyticsdata.googleapis.com/v1beta/properties/{PROPERTY_ID}:runReport" \
-H "Authorization: Bearer ${GA_ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"dateRanges": [{"startDate": "30daysAgo", "endDate": "today"}],
"dimensions": [
{"name": "sessionDefaultChannelGroup"}
],
"metrics": [
{"name": "sessions"},
{"name": "totalUsers"},
{"name": "engagementRate"},
{"name": "conversions"}
],
"orderBys": [{"metric": {"metricName": "sessions"}, "desc": true}],
"limit": 20
}'
| Dimension | Description |
|---|---|
sessionDefaultChannelGroup | Channel grouping (Organic, Paid, Social, etc.) |
sessionSource | Traffic source (google, facebook, etc.) |
sessionMedium | Medium (organic, cpc, referral, etc.) |
sessionCampaignName | UTM campaign name |
firstUserSource | First-touch attribution source |
Find the highest-traffic pages on the site.
curl -s -X POST \
"https://analyticsdata.googleapis.com/v1beta/properties/{PROPERTY_ID}:runReport" \
-H "Authorization: Bearer ${GA_ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"dateRanges": [{"startDate": "30daysAgo", "endDate": "today"}],
"dimensions": [
{"name": "pagePath"}
],
"metrics": [
{"name": "screenPageViews"},
{"name": "totalUsers"},
{"name": "engagementRate"},
{"name": "averageSessionDuration"}
],
"orderBys": [{"metric": {"metricName": "screenPageViews"}, "desc": true}],
"limit": 25
}'
Understand how users interact with your content.
curl -s -X POST \
"https://analyticsdata.googleapis.com/v1beta/properties/{PROPERTY_ID}:runReport" \
-H "Authorization: Bearer ${GA_ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"dateRanges": [{"startDate": "30daysAgo", "endDate": "today"}],
"dimensions": [
{"name": "pagePath"}
],
"metrics": [
{"name": "engagedSessions"},
{"name": "engagementRate"},
{"name": "averageSessionDuration"},
{"name": "screenPageViewsPerSession"},
{"name": "eventCount"}
],
"orderBys": [{"metric": {"metricName": "engagedSessions"}, "desc": true}],
"limit": 20
}'
| Metric | What It Measures |
|---|---|
engagementRate | % of sessions that were engaged (>10s, 2+ pages, or conversion) |
averageSessionDuration | Mean session length in seconds |
screenPageViewsPerSession | Pages per session |
bounceRate | % of sessions with no engagement |
eventCount | Total events fired |
Report on conversion events (purchases, signups, etc.).
curl -s -X POST \
"https://analyticsdata.googleapis.com/v1beta/properties/{PROPERTY_ID}:runReport" \
-H "Authorization: Bearer ${GA_ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"dateRanges": [{"startDate": "30daysAgo", "endDate": "today"}],
"dimensions": [
{"name": "eventName"}
],
"metrics": [
{"name": "eventCount"},
{"name": "totalUsers"},
{"name": "eventValue"}
],
"dimensionFilter": {
"filter": {
"fieldName": "eventName",
"inListFilter": {
"values": ["purchase", "sign_up", "generate_lead", "begin_checkout"]
}
}
}
}'
curl -s -X POST \
"https://analyticsdata.googleapis.com/v1beta/properties/{PROPERTY_ID}:runReport" \
-H "Authorization: Bearer ${GA_ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"dateRanges": [{"startDate": "30daysAgo", "endDate": "today"}],
"dimensions": [
{"name": "sessionDefaultChannelGroup"}
],
"metrics": [
{"name": "sessions"},
{"name": "conversions"},
{"name": "totalRevenue"}
],
"orderBys": [{"metric": {"metricName": "conversions"}, "desc": true}]
}'
Break down traffic by device, geography, and demographics.
curl -s -X POST \
"https://analyticsdata.googleapis.com/v1beta/properties/{PROPERTY_ID}:runReport" \
-H "Authorization: Bearer ${GA_ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"dateRanges": [{"startDate": "30daysAgo", "endDate": "today"}],
"dimensions": [{"name": "deviceCategory"}],
"metrics": [
{"name": "sessions"},
{"name": "totalUsers"},
{"name": "engagementRate"},
{"name": "conversions"}
]
}'
Replace deviceCategory with country in the dimensions.
curl -s -X POST \
"https://analyticsdata.googleapis.com/v1beta/properties/{PROPERTY_ID}:runReport" \
-H "Authorization: Bearer ${GA_ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"dateRanges": [{"startDate": "30daysAgo", "endDate": "today"}],
"dimensions": [
{"name": "landingPage"},
{"name": "sessionSource"}
],
"metrics": [
{"name": "sessions"},
{"name": "engagementRate"},
{"name": "conversions"}
],
"orderBys": [{"metric": {"metricName": "sessions"}, "desc": true}],
"limit": 30
}'
Compare two time periods to identify trends.
curl -s -X POST \
"https://analyticsdata.googleapis.com/v1beta/properties/{PROPERTY_ID}:runReport" \
-H "Authorization: Bearer ${GA_ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"dateRanges": [
{"startDate": "30daysAgo", "endDate": "today", "name": "current"},
{"startDate": "60daysAgo", "endDate": "31daysAgo", "name": "previous"}
],
"metrics": [
{"name": "sessions"},
{"name": "totalUsers"},
{"name": "conversions"},
{"name": "engagementRate"}
]
}'
GA4 API returns JSON. Parse with python3 or jq:
# Parse report into a table
curl -s -X POST "..." | python3 -c "
import json, sys
data = json.load(sys.stdin)
headers = [h['name'] for h in data.get('dimensionHeaders',[])] + [m['name'] for m in data.get('metricHeaders',[])]
print(' | '.join(headers))
print('-' * (len(headers) * 20))
for row in data.get('rows', []):
dims = [d['value'] for d in row.get('dimensionValues',[])]
mets = [m['value'] for m in row.get('metricValues',[])]
print(' | '.join(dims + mets))
"
When asked for a monthly report:
Present as a structured report with tables, trends (up/down arrows), and recommendations:
## Monthly Analytics Report: {Property Name}
### Period: {date range} vs {previous period}
### Traffic Summary
| Metric | Current | Previous | Change |
|--------|---------|----------|--------|
| Sessions | X | Y | +Z% |
| ...
### Top Channels
...
### Top Pages
...
### Conversion Summary
...
### Recommendations
- [Based on data patterns]
properties/XXXXXXXXX)