🎁 Get the FREE AI Skills Starter Guide β€” Subscribe β†’
BytesAgainBytesAgain
πŸ¦€ ClawHub

Google Analytics CLI

by @bin-huang

Google Analytics 4 data analysis and reporting via google-analytics-cli. Use when the user wants to check GA4 traffic, run reports with dimensions and metric...

Versionv1.0.0
Downloads693
TERMINAL
clawhub install google-analytics-cli

πŸ“– About This Skill


name: google-analytics-cli description: > Google Analytics 4 data analysis and reporting via google-analytics-cli. Use when the user wants to check GA4 traffic, run reports with dimensions and metrics, monitor realtime users, explore account structure, or analyze user behavior. Triggers: "Google Analytics", "GA4", "analytics report", "active users", "page views", "traffic source", "sessions", "engagement", "realtime", "bounce rate".

Google Analytics CLI Skill

You have access to google-analytics-cli, a read-only CLI for the GA4 API. Use it to run reports, monitor realtime activity, and explore account/property structure.

Quick start

# Check if the CLI is available
google-analytics-cli --help

List accounts and properties

google-analytics-cli accounts

If the CLI is not installed, install it:

npm install -g google-analytics-cli

Authentication

The CLI uses Google service account credentials. Credentials are resolved in this order:

1. --credentials flag (per-command) 2. GOOGLE_APPLICATION_CREDENTIALS env var 3. ~/.config/google-analytics-cli/credentials.json (auto-detected) 4. gcloud Application Default Credentials

Before running any command, verify credentials by running google-analytics-cli accounts. If it fails, ask the user to set up a service account and grant it Viewer access in Google Analytics.

Property ID

Most commands require a GA4 property ID. It can be provided as:

  • A positional argument: google-analytics-cli report 123456789 ...
  • The --property flag: google-analytics-cli report --property 123456789 ...
  • The GA_PROPERTY_ID env var: export GA_PROPERTY_ID=123456789
  • Both raw numbers (123456789) and prefixed format (properties/123456789) are accepted.

    Output format

    All commands output pretty-printed JSON by default. Use --format compact for single-line JSON.

    Admin commands

    # List all accounts and their properties
    google-analytics-cli accounts

    Get details about a specific property

    google-analytics-cli property 123456789

    List properties for an account

    google-analytics-cli properties 987654321 google-analytics-cli properties 987654321 --show-deleted

    List data streams for a property

    google-analytics-cli data-streams 123456789

    List key events (conversions) for a property

    google-analytics-cli key-events 123456789

    List custom dimensions for a property (Admin API)

    google-analytics-cli admin-custom-dimensions 123456789

    List custom metrics for a property (Admin API)

    google-analytics-cli admin-custom-metrics 123456789

    Get data retention settings for a property

    google-analytics-cli data-retention 123456789

    List Google Ads links for a property

    google-analytics-cli ads-links 123456789

    List annotations for a property (alpha API)

    google-analytics-cli annotations 123456789

    Get custom dimensions and metrics for a property (Data API, filters by customDefinition)

    google-analytics-cli custom-dims 123456789

    Change history

    Search change history events for an account:

    google-analytics-cli change-history 987654321
    google-analytics-cli change-history 987654321 --filter-property 123456789
    google-analytics-cli change-history 987654321 --earliest-change-time 2026-01-01T00:00:00Z
    google-analytics-cli change-history 987654321 --earliest-change-time 2026-01-01T00:00:00Z --latest-change-time 2026-03-01T00:00:00Z
    google-analytics-cli change-history 987654321 --actor-email user@example.com
    google-analytics-cli change-history 987654321 --resource-type '["PROPERTY","DATA_STREAM"]'
    google-analytics-cli change-history 987654321 --action '["CREATED","UPDATED"]'
    

    Access report

    Run an access report to see who accessed the property:

    google-analytics-cli access-report 123456789 \
      --dimensions "accessorEmail,accessMechanism" \
      --metrics "accessCount" \
      --date-ranges '[{"startDate": "30daysAgo", "endDate": "yesterday"}]'
    

    Options: --dimension-filter, --metric-filter, --order-by, --limit, --offset, --time-zone, --return-entity-quota, --include-all-users, --expand-groups.

    Note: Access report uses dimensionName/metricName (not name) internally and entity (not property).

    Running reports

    The report command runs a GA4 Data API report.

    google-analytics-cli report  \
      --dimensions "" \
      --metrics "" \
      --date-ranges '' \
      [--dimension-filter ''] \
      [--metric-filter ''] \
      [--order-by ''] \
      [--limit ] \
      [--offset ] \
      [--currency-code ] \
      [--keep-empty-rows] \
      [--return-property-quota]
    

    Required options: --dimensions, --metrics, --date-ranges.

    Date ranges

    The --date-ranges option takes a JSON array of date range objects:

    # Relative dates
    --date-ranges '[{"startDate": "30daysAgo", "endDate": "yesterday"}]'

    Absolute dates

    --date-ranges '[{"startDate": "2026-01-01", "endDate": "2026-01-31"}]'

    Compare two periods

    --date-ranges '[{"startDate": "30daysAgo", "endDate": "yesterday", "name": "current"}, {"startDate": "60daysAgo", "endDate": "31daysAgo", "name": "previous"}]'

    Valid date values:

  • Absolute: YYYY-MM-DD (e.g. 2026-01-01)
  • Relative: NdaysAgo (e.g. 30daysAgo, 7daysAgo)
  • Special: yesterday, today
  • Up to 4 date ranges per request
  • Dimension filters

    The --dimension-filter option takes a JSON FilterExpression:

    # Exact match
    --dimension-filter '{"filter": {"fieldName": "country", "stringFilter": {"matchType": "EXACT", "value": "United States"}}}'

    Contains

    --dimension-filter '{"filter": {"fieldName": "pagePath", "stringFilter": {"matchType": "CONTAINS", "value": "/blog"}}}'

    Regex

    --dimension-filter '{"filter": {"fieldName": "pagePath", "stringFilter": {"matchType": "PARTIAL_REGEXP", "value": "^/products/[0-9]+"}}}'

    In list

    --dimension-filter '{"filter": {"fieldName": "eventName", "inListFilter": {"values": ["page_view", "scroll", "click"]}}}'

    AND group

    --dimension-filter '{"andGroup": {"expressions": [{"filter": {"fieldName": "country", "stringFilter": {"matchType": "EXACT", "value": "United States"}}}, {"filter": {"fieldName": "deviceCategory", "stringFilter": {"matchType": "EXACT", "value": "mobile"}}}]}}'

    OR group

    --dimension-filter '{"orGroup": {"expressions": [{"filter": {"fieldName": "country", "stringFilter": {"matchType": "EXACT", "value": "United States"}}}, {"filter": {"fieldName": "country", "stringFilter": {"matchType": "EXACT", "value": "Canada"}}}]}}'

    NOT

    --dimension-filter '{"notExpression": {"filter": {"fieldName": "pagePath", "stringFilter": {"matchType": "EXACT", "value": "/"}}}}'

    StringFilter matchType values: EXACT, BEGINS_WITH, ENDS_WITH, CONTAINS, FULL_REGEXP, PARTIAL_REGEXP.

    Metric filters

    The --metric-filter option takes the same FilterExpression structure but with numeric filters:

    # Greater than
    --metric-filter '{"filter": {"fieldName": "sessions", "numericFilter": {"operation": "GREATER_THAN", "value": {"int64Value": "100"}}}}'

    Between

    --metric-filter '{"filter": {"fieldName": "bounceRate", "betweenFilter": {"fromValue": {"doubleValue": 0.5}, "toValue": {"doubleValue": 0.9}}}}'

    NumericFilter operations: EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL.

    NumericValue: use {"int64Value": "string"} for integers or {"doubleValue": number} for decimals.

    Ordering

    The --order-by option takes a JSON array:

    # By metric descending
    --order-by '[{"metric": {"metricName": "sessions"}, "desc": true}]'

    By dimension alphabetically

    --order-by '[{"dimension": {"dimensionName": "date", "orderType": "ALPHANUMERIC"}}]'

    Multiple sort keys

    --order-by '[{"metric": {"metricName": "sessions"}, "desc": true}, {"dimension": {"dimensionName": "country"}}]'

    DimensionOrderBy orderType values: ALPHANUMERIC, CASE_INSENSITIVE_ALPHANUMERIC, NUMERIC.

    Pivot reports

    Run a pivot report for cross-tabulation analysis:

    google-analytics-cli pivot-report 123456789 \
      --dimensions "country,browser" \
      --metrics "sessions,activeUsers" \
      --date-ranges '[{"startDate": "30daysAgo", "endDate": "yesterday"}]' \
      --pivots '[{"fieldNames": ["browser"], "limit": 5, "orderBys": [{"metric": {"metricName": "sessions"}, "desc": true}]}]'
    

    Options: --dimension-filter, --metric-filter, --currency-code, --keep-empty-rows, --return-property-quota.

    Batch reports

    Run up to 5 reports in a single request:

    google-analytics-cli batch-report 123456789 \
      --requests '[{"dimensions": [{"name": "date"}], "metrics": [{"name": "activeUsers"}], "dateRanges": [{"startDate": "7daysAgo", "endDate": "yesterday"}]}, {"dimensions": [{"name": "country"}], "metrics": [{"name": "sessions"}], "dateRanges": [{"startDate": "7daysAgo", "endDate": "yesterday"}]}]'
    

    Metadata and compatibility

    # Get full metadata (all available dimensions and metrics)
    google-analytics-cli metadata 123456789

    Check if dimensions and metrics are compatible

    google-analytics-cli check-compatibility 123456789 \ --dimensions "date,country" \ --metrics "sessions,activeUsers"

    Options: --dimension-filter, --metric-filter (same FilterExpression format as report).

    Audience exports

    # Create an audience export
    google-analytics-cli audience-export-create 123456789 \
      --audience "properties/123456789/audiences/456" \
      --dimensions "deviceId,userId"

    Get status of an audience export

    google-analytics-cli audience-export 123456789 properties/123456789/audienceExports/789

    List all audience exports

    google-analytics-cli audience-exports 123456789

    Query rows from a completed audience export

    google-analytics-cli audience-export-query 123456789 properties/123456789/audienceExports/789 \ --limit 1000 --offset 0

    Realtime reports

    The realtime command monitors current activity. No date ranges or currency code.

    google-analytics-cli realtime  \
      --dimensions "" \
      --metrics "" \
      [--dimension-filter ''] \
      [--metric-filter ''] \
      [--order-by ''] \
      [--limit ] \
      [--return-property-quota]
    

    Realtime reports cover the last 30 minutes of activity.

    Realtime dimensions (limited set)

    appVersion, audienceId, audienceName, audienceResourceName, city, cityId, country, countryId, deviceCategory, eventName, minutesAgo, platform, streamId, streamName, unifiedScreenName

    Note: minutesAgo is "00" for the current minute, "01" for the previous, up to "29".

    Realtime metrics (4 only)

    activeUsers, eventCount, keyEvents, screenPageViews

    Common dimensions reference

    Traffic source (session-scoped): sessionSource, sessionMedium, sessionSourceMedium, sessionDefaultChannelGroup, sessionCampaignName, sessionCampaignId

    Traffic source (first-user acquisition): firstUserSource, firstUserMedium, firstUserSourceMedium, firstUserDefaultChannelGroup, firstUserCampaignName

    Page/Screen: pagePath, pageTitle, pagePathPlusQueryString, landingPage, landingPagePlusQueryString, hostName, fullPageUrl, contentGroup

    Event: eventName, isKeyEvent

    User: newVsReturning, userAgeBracket, userGender, firstSessionDate

    Geography: country, countryId, city, cityId, region, continent, language

    Device: deviceCategory, browser, operatingSystem, operatingSystemVersion, screenResolution, mobileDeviceBranding, platform

    Time: date, dateHour, day, dayOfWeek, dayOfWeekName, hour, month, week, year, yearMonth, nthDay

    Ecommerce: transactionId, itemName, itemId, itemCategory, itemBrand, itemVariant, orderCoupon

    Google Ads: sessionGoogleAdsCampaignName, sessionGoogleAdsAdGroupName, sessionGoogleAdsKeyword, sessionGoogleAdsAdNetworkType, googleAdsAccountName

    Audience: audienceId, audienceName

    Custom dimensions: customEvent:parameter_name (event-scoped), customUser:parameter_name (user-scoped), customItem:parameter_name (item-scoped)

    Common metrics reference

    User: activeUsers, newUsers, totalUsers

    Session: sessions, sessionsPerUser, averageSessionDuration, bounceRate

    Engagement: engagedSessions, engagementRate, screenPageViews, screenPageViewsPerSession, screenPageViewsPerUser, userEngagementDuration

    Event: eventCount, eventCountPerUser, eventValue, eventsPerSession

    Key events (conversions): keyEvents, sessionKeyEventRate, userKeyEventRate

    Ecommerce/Revenue: ecommercePurchases, purchaseRevenue, totalRevenue, transactions, averagePurchaseRevenue, averageRevenuePerUser, itemRevenue, addToCarts, checkouts, cartToViewRate

    Advertising: advertiserAdClicks, advertiserAdCost, advertiserAdCostPerClick, advertiserAdImpressions, returnOnAdSpend

    Custom metrics: customEvent:parameter_name (sum), averageCustomEvent:parameter_name (average), countCustomEvent:parameter_name (count)

    Report examples

    Traffic overview (last 30 days):

    google-analytics-cli report 123456789 \
      --dimensions "sessionDefaultChannelGroup" \
      --metrics "sessions,activeUsers,engagementRate,keyEvents,totalRevenue" \
      --date-ranges '[{"startDate": "30daysAgo", "endDate": "yesterday"}]' \
      --order-by '[{"metric": {"metricName": "sessions"}, "desc": true}]'
    

    Top pages by views:

    google-analytics-cli report 123456789 \
      --dimensions "pagePath" \
      --metrics "screenPageViews,activeUsers,averageSessionDuration,bounceRate" \
      --date-ranges '[{"startDate": "30daysAgo", "endDate": "yesterday"}]' \
      --order-by '[{"metric": {"metricName": "screenPageViews"}, "desc": true}]' \
      --limit 20
    

    Daily trend:

    google-analytics-cli report 123456789 \
      --dimensions "date" \
      --metrics "activeUsers,sessions,screenPageViews,keyEvents" \
      --date-ranges '[{"startDate": "30daysAgo", "endDate": "yesterday"}]' \
      --order-by '[{"dimension": {"dimensionName": "date"}}]'
    

    Traffic source breakdown:

    google-analytics-cli report 123456789 \
      --dimensions "sessionSource,sessionMedium" \
      --metrics "sessions,activeUsers,engagementRate,bounceRate,keyEvents" \
      --date-ranges '[{"startDate": "7daysAgo", "endDate": "yesterday"}]' \
      --order-by '[{"metric": {"metricName": "sessions"}, "desc": true}]' \
      --limit 20
    

    Landing page performance:

    google-analytics-cli report 123456789 \
      --dimensions "landingPage" \
      --metrics "sessions,activeUsers,bounceRate,keyEvents,averageSessionDuration" \
      --date-ranges '[{"startDate": "30daysAgo", "endDate": "yesterday"}]' \
      --order-by '[{"metric": {"metricName": "sessions"}, "desc": true}]' \
      --limit 20
    

    Device breakdown:

    google-analytics-cli report 123456789 \
      --dimensions "deviceCategory" \
      --metrics "activeUsers,sessions,engagementRate,bounceRate,screenPageViews" \
      --date-ranges '[{"startDate": "30daysAgo", "endDate": "yesterday"}]'
    

    Geography:

    google-analytics-cli report 123456789 \
      --dimensions "country" \
      --metrics "activeUsers,sessions,engagementRate,keyEvents" \
      --date-ranges '[{"startDate": "30daysAgo", "endDate": "yesterday"}]' \
      --order-by '[{"metric": {"metricName": "activeUsers"}, "desc": true}]' \
      --limit 20
    

    Event analysis:

    google-analytics-cli report 123456789 \
      --dimensions "eventName" \
      --metrics "eventCount,eventCountPerUser,eventValue" \
      --date-ranges '[{"startDate": "7daysAgo", "endDate": "yesterday"}]' \
      --order-by '[{"metric": {"metricName": "eventCount"}, "desc": true}]' \
      --limit 20
    

    Period comparison:

    google-analytics-cli report 123456789 \
      --dimensions "sessionDefaultChannelGroup" \
      --metrics "sessions,activeUsers,keyEvents" \
      --date-ranges '[{"startDate": "30daysAgo", "endDate": "yesterday", "name": "current"}, {"startDate": "60daysAgo", "endDate": "31daysAgo", "name": "previous"}]' \
      --order-by '[{"metric": {"metricName": "sessions"}, "desc": true}]'
    

    Ecommerce performance:

    google-analytics-cli report 123456789 \
      --dimensions "itemName" \
      --metrics "itemRevenue,itemsPurchased,addToCarts,cartToViewRate" \
      --date-ranges '[{"startDate": "30daysAgo", "endDate": "yesterday"}]' \
      --order-by '[{"metric": {"metricName": "itemRevenue"}, "desc": true}]' \
      --limit 20
    

    New vs returning users:

    google-analytics-cli report 123456789 \
      --dimensions "newVsReturning" \
      --metrics "activeUsers,sessions,engagementRate,screenPageViews,keyEvents" \
      --date-ranges '[{"startDate": "30daysAgo", "endDate": "yesterday"}]'
    

    User acquisition (first-touch):

    google-analytics-cli report 123456789 \
      --dimensions "firstUserDefaultChannelGroup" \
      --metrics "newUsers,activeUsers,sessions,keyEvents,totalRevenue" \
      --date-ranges '[{"startDate": "30daysAgo", "endDate": "yesterday"}]' \
      --order-by '[{"metric": {"metricName": "newUsers"}, "desc": true}]'
    

    Campaign (UTM) performance:

    google-analytics-cli report 123456789 \
      --dimensions "sessionCampaignName,sessionSourceMedium" \
      --metrics "sessions,activeUsers,engagementRate,keyEvents,totalRevenue" \
      --date-ranges '[{"startDate": "30daysAgo", "endDate": "yesterday"}]' \
      --order-by '[{"metric": {"metricName": "sessions"}, "desc": true}]' \
      --limit 20
    

    Google Ads campaign performance:

    google-analytics-cli report 123456789 \
      --dimensions "sessionGoogleAdsCampaignName" \
      --metrics "sessions,keyEvents,advertiserAdCost,advertiserAdClicks,returnOnAdSpend" \
      --date-ranges '[{"startDate": "30daysAgo", "endDate": "yesterday"}]' \
      --order-by '[{"metric": {"metricName": "advertiserAdCost"}, "desc": true}]'
    

    Filtered report (blog pages only, US mobile users):

    google-analytics-cli report 123456789 \
      --dimensions "pagePath" \
      --metrics "screenPageViews,activeUsers,engagementRate" \
      --date-ranges '[{"startDate": "30daysAgo", "endDate": "yesterday"}]' \
      --dimension-filter '{"andGroup": {"expressions": [{"filter": {"fieldName": "pagePath", "stringFilter": {"matchType": "BEGINS_WITH", "value": "/blog"}}}, {"filter": {"fieldName": "country", "stringFilter": {"matchType": "EXACT", "value": "United States"}}}, {"filter": {"fieldName": "deviceCategory", "stringFilter": {"matchType": "EXACT", "value": "mobile"}}}]}}' \
      --order-by '[{"metric": {"metricName": "screenPageViews"}, "desc": true}]' \
      --limit 20
    

    Realtime -- active users by country:

    google-analytics-cli realtime 123456789 \
      --dimensions "country" \
      --metrics "activeUsers" \
      --order-by '[{"metric": {"metricName": "activeUsers"}, "desc": true}]'
    

    Realtime -- active pages:

    google-analytics-cli realtime 123456789 \
      --dimensions "unifiedScreenName" \
      --metrics "activeUsers,screenPageViews" \
      --order-by '[{"metric": {"metricName": "activeUsers"}, "desc": true}]' \
      --limit 10
    

    Important rules

    1. Dimension/metric compatibility. Not all dimensions and metrics can be used together. If you get a compatibility error, reduce the number of dimensions or try different combinations. Use the check-compatibility command to test before running a report, or use metadata to see all available dimensions and metrics.

    2. Max 9 dimensions per report request.

    3. Max 4 date ranges per report request.

    4. Max 250,000 rows per response. Use --offset and --limit for pagination.

    5. Realtime is limited. Only 15 dimensions and 4 metrics. No date ranges, no currency code, no offset. Covers the last 30 minutes.

    6. Thresholded dimensions. userAgeBracket, userGender, and audienceId/audienceName may return thresholded (sampled) data for privacy when row counts are too low.

    7. Quota. Use --return-property-quota to check current quota status. Standard properties get 200,000 tokens/day.

    8. Filter scope. --dimension-filter only accepts dimension field names. --metric-filter only accepts metric field names. They are applied independently by the API.

    9. Batch reports. Max 5 report objects per batch request.

    10. Audience exports. Creating an export returns a long-running operation. Poll with audience-export until state is ACTIVE, then query rows with audience-export-query.

    Workflow guidance

    Quick overview

    1. Run google-analytics-cli accounts to find properties 2. Run a traffic overview report with sessionDefaultChannelGroup and key metrics 3. Present trends with daily date dimension

    Deep analysis

    1. Start broad: traffic channels and top-level metrics 2. Drill down: specific pages, events, or sources that underperform 3. Compare periods to identify trends 4. Check device and geography breakdowns for segment-specific issues 5. Use --dimension-filter to isolate specific segments

    Property exploration

    1. Run google-analytics-cli properties to see all properties 2. Run google-analytics-cli data-streams to see data streams 3. Run google-analytics-cli key-events to see configured conversions 4. Run google-analytics-cli metadata for all available dimensions and metrics 5. Run google-analytics-cli check-compatibility before complex reports

    Error handling

  • Permission denied -- the service account needs Viewer access in Google Analytics
  • Incompatible dimensions/metrics -- use check-compatibility to test, reduce dimensions or try different combinations
  • Empty results -- check property ID, date range, and whether data exists for those dimensions
  • Quota exceeded -- use --return-property-quota to check usage; reduce request frequency or complexity
  • API documentation references

  • google-analytics-cli documentation
  • GA4 Data API overview
  • Dimensions and metrics reference
  • Realtime API schema
  • FilterExpression reference
  • OrderBy reference
  • Quotas and limits
  • GA4 Admin API
  • πŸ’‘ Examples

    # Check if the CLI is available
    google-analytics-cli --help

    List accounts and properties

    google-analytics-cli accounts

    If the CLI is not installed, install it:

    npm install -g google-analytics-cli