From openclaudia-openclaudia-skills
Pulls GA4 reports, traffic data, and insights from the Google Analytics Data API. Handles OAuth authentication and provides example queries for traffic overview, user behavior, and acquisition channels.
How this skill is triggered — by the user, by Claude, or both
Slash command
/openclaudia-openclaudia-skills:google-analyticsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Pull reports and insights from GA4 using the Google Analytics Data API.
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)npx claudepluginhub joshuarweaver/cascade-communication --plugin openclaudia-openclaudia-skillsAnalyzes Google Analytics 4 data to review website performance, traffic patterns, bounce rates, and conversions. Generates actionable reports including SEO daily reports with organic KPIs, anomaly detection, and prioritized recommendations.
Queries Google Analytics 4 reports and properties using the Data and Admin APIs. Useful for traffic, sessions, users, conversions, and realtime data.
Queries Google Analytics 4 data via the Analytics Data API for metrics like page views, sessions, users, conversions, and traffic sources with custom date ranges and filtering.