Pulling Google Analytics 4 Data into Python


Hello, tech enthusiasts! ๐Ÿ‘‹

Every Monday, many office teams do the same thing. They open Google Analytics, click through a few reports, copy the visitor numbers, and paste them into a spreadsheet. It takes 20 minutes, and it is easy to copy the wrong cell.

What if Python could do this for you? Google Analytics 4 (GA4) has an API for this. An API is like a waiter in a restaurant: you ask for something, and it brings the data back to your table. The GA4 API is called the Google Analytics Data API.

Today we will set it up step by step and get the data into a pandas table.

What you need

  • A GA4 property where you are an Administrator (so you can add a new user)
  • A Google account that can create a Google Cloud project (https://console.cloud.google.com)
  • Python 3.9 or newer (https://www.python.org)
  • These packages: pip install google-analytics-data pandas openpyxl

Step 1: Create a Google Cloud project

A Google Cloud project is a folder that holds your API settings.

  1. Open the Google Cloud Console.
  2. At the top, click the project list, then New Project.
  3. Give it a name like “analytics-reports” and click Create.

Step 2: Turn on the Analytics Data API

Google keeps APIs switched off until you need them.

  1. In your new project, open APIs & Services โ†’ Library.
  2. Search for Google Analytics Data API.
  3. Click it, then click Enable.

Step 3: Create a service account and a key

A service account is a robot user. It is not a person, so your script can log in without your own password.

  1. Go to IAM & Admin โ†’ Service Accounts โ†’ Create service account.
  2. Name it “ga4-reader” and finish the steps. It does not need any Cloud roles for this task.
  3. Open the new service account, go to the Keys tab, and choose Add key โ†’ Create new key โ†’ JSON.
  4. A file downloads. Rename it to ga4-key.json and keep it in your project folder.

This JSON file is like a house key. Do not email it, do not put it in shared folders, and do not upload it to GitHub. If you use Git, add it to your .gitignore file.

Step 4: Give the robot access to GA4

The robot user has an email address. It looks like ga4-reader@your-project-id.iam.gserviceaccount.com. You can find it on the service account page, or inside the JSON file as client_email.

  1. Open Google Analytics and click Admin (the gear icon).
  2. Under your property, open Property access management.
  3. Click + โ†’ Add users, paste the robot’s email, and choose the Viewer role.
  4. Click Add.

Viewer is enough, because the script only reads data. Always give the smallest role that does the job.

While you are in Admin, open Property details and copy the Property ID. It is a number like 123456789.

Step 5: Ask for a report

Now the fun part. We ask GA4 for daily active users and sessions for the last 28 days, split by country.

Dimensions are the “by what” part, like date or country. Metrics are the numbers, like users or sessions.

from google.analytics.data_v1beta import BetaAnalyticsDataClient
from google.analytics.data_v1beta.types import (
    DateRange,
    Dimension,
    Metric,
    RunReportRequest,
)

PROPERTY_ID = "123456789"  # your GA4 property ID
KEY_FILE = "ga4-key.json"  # the service account key

# Log in with the robot user's key
client = BetaAnalyticsDataClient.from_service_account_file(KEY_FILE)

request = RunReportRequest(
    property=f"properties/{PROPERTY_ID}",
    date_ranges=[DateRange(start_date="28daysAgo", end_date="yesterday")],
    dimensions=[Dimension(name="date"), Dimension(name="country")],
    metrics=[Metric(name="activeUsers"), Metric(name="sessions")],
    limit=10000,
)

response = client.run_report(request)
print("Rows received:", response.row_count)

You can also use real dates like "2025-08-01". Words like "today", "yesterday" and "7daysAgo" work too.

Step 6: Turn the answer into a pandas table

The answer comes back as rows. Each row has dimension values and metric values, in the same order you asked for them. We put them into a DataFrame (a pandas table).

import pandas as pd

dim_names = [d.name for d in response.dimension_headers]
met_names = [m.name for m in response.metric_headers]

records = []
for row in response.rows:
    record = {}
    for name, value in zip(dim_names, row.dimension_values):
        record[name] = value.value
    for name, value in zip(met_names, row.metric_values):
        record[name] = value.value
    records.append(record)

df = pd.DataFrame(records)

# GA4 sends everything as text, so fix the types
df["date"] = pd.to_datetime(df["date"], format="%Y%m%d")
df[met_names] = df[met_names].astype(int)

df = df.sort_values(["date", "activeUsers"], ascending=[True, False])
print(df.head())

df.to_excel("ga4_report.xlsx", index=False)

GA4 sends dates as text like 20250830, so we convert them with a format. Now you have a clean table you can chart, filter, or send by email. ๐ŸŽ‰

Common problems

  • 403 User does not have sufficient permissions โ†’ The robot email was not added in GA4, or you added it to a different property. Check Step 4.
  • Google Analytics Data API has not been used in project โ†’ The API is not enabled in the same Cloud project as your key. Check Step 2.
  • Field xyz is not a valid dimension โ†’ Use the API names, not the names you see on screen. For example, activeUsers, not “Active users”. Google lists them on the “API Dimensions & Metrics” page.
  • Numbers are a little different from the website โ†’ GA4 may use sampling or thresholds, and today’s data is still being processed. Use yesterday as the end date for stable numbers.

Wrap-up

You created a robot user, gave it read-only access, and pulled real GA4 numbers into pandas. Your Monday copy-paste job is now one script.

Next idea: schedule the script to run every Monday morning with Windows Task Scheduler or cron, and save each report with the date in the file name.