Automating Weekly Analytics Reports to Slack With a GitHub Action

Google Analytics access is often restricted to a handful of people, which means useful data rarely makes it to the wider team. A GitHub Action can change that by pulling page-view data from Google Analytics, comparing it week over week, and posting the results to a Slack channel on a schedule. This turns analytics into something anyone on the team can see, use, and share.

The workflow described here queries Google Analytics for the top ten most-viewed pages in the last seven days, then compares those numbers against the previous seven days. Each entry in the resulting report is labeled by trend: increased, decreased, unchanged, or new to the list. The report includes icons for each status and posts to a designated Slack channel every Friday at 10 AM.

The formatted output is easy to screenshot or copy into a slide for weekly meetings, so the data can be shared beyond Slack as well. The full repository is available on GitHub.

What You’ll Need

Setting this up requires admin access to Google Analytics and Slack, plus administrator privileges on a GitHub repository so you can configure Actions and Secrets.

Adjusting the Report to Your Needs

The code in the repository is intentionally left readable so it can be modified. The key areas are the Action’s schedule and naming, the Google Analytics query, and the Slack message layout.

Action Schedule and Naming

The Action file weekly-analytics.report.yml can be renamed without breaking anything. The name and jobs: values appear in the GitHub UI and workflow logs, so you’ll likely want to customize those to fit your project.

The cron expression controls when the Action runs. Schedules follow POSIX cron syntax, so editing the numbers changes the trigger time. You can also rename the secret variables, as long as you update them in the repository’s Settings.

# .github/workflows/weekly-analytics-report.yml

name: Weekly Analytics Report

on:
  schedule:
    - cron: '0 10 * * 5' # Runs every Friday at 10 AM UTC
  workflow_dispatch: # Allows manual triggering

jobs:
  analytics-report:
    runs-on: ubuntu-latest

    env:
      SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
      GA4_PROPERTY_ID: ${{ secrets.GA4_PROPERTY_ID }}
      GOOGLE_APPLICATION_CREDENTIALS_BASE64: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS_BASE64 }}

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20.x'

      - name: Install dependencies
        run: npm install

      - name: Run the JavaScript script
        run: node src/services/weekly-analytics.js

Google Analytics Query

The API request pulls the fullPageUrl and pageTitle for the totalUsers metric. One request covers the current seven-day window; a second covers the previous seven days. The results are aggregated and the response is limited to ten entries.

If you want a different metric or date range, use Google’s GA4 Query Explorer to construct your own query and replace the requests in the service file.

// src/services/weekly-analytics.js#L75

const [thisWeek] = await analyticsDataClient.runReport({
  property: `properties/${process.env.GA4_PROPERTY_ID}`,
  dateRanges: [
    {
      startDate: '7daysAgo',
      endDate: 'today',
    },
  ],
  dimensions: [
    {
      name: 'fullPageUrl',
    },
    {
      name: 'pageTitle',
    },
  ],
  metrics: [
    {
      name: 'totalUsers',
    },
  ],
  limit: reportLimit,
  metricAggregations: ['MAXIMUM'],
});

How the Week-Over-Week Comparison Works

Three functions handle the comparison logic. The first uses a reduce operation to produce a list of URLs with their view counts. The second maps this week’s results against last week’s to pair them up. The final function assigns each pair a status: up, down, same, or new.

const lastWeekMap = lastWeekResults.reduce((items, item) => {
  const { url, count } = item;
  items[url] = count;
  return items;
}, {});
// Generate the report for this week
const report = thisWeekResults.map((item, index) => {
  const { url, title, count } = item;
  const lastWeekCount = lastWeekMap[url];
  const status = determineStatus(count, lastWeekCount);

  return {
    position: (index + 1).toString().padStart(2, '0'), // Format the position with leading zero if it's less than 10
    url,
    title,
    count: { thisWeek: count, lastWeek: lastWeekCount || '0' }, // Ensure lastWeekCount is displayed as '0' if not found
    status,
  };
});
// Function to determine the status
const determineStatus = (count, lastWeekCount) => {
  const thisCount = Number(count);
  const previousCount = Number(lastWeekCount);

  if (lastWeekCount === undefined || lastWeekCount === '0') {
    return NEW;
  }

  if (thisCount > previousCount) {
    return HIGHER;
  }

  if (thisCount < previousCount) {
    return LOWER;
  }

  return SAME;
};

The code is deliberately verbose so you can drop in console.log statements and inspect what each function returns as it processes the data.

Designing the Slack Message

The Slack message configuration builds a header with an emoji, a divider, and a short description of the report content. A context object is used to iterate over the comparisons and output each item with an icon, the view count, the page name, and a link.

The Block Kit Builder is the best place to prototype a different message format if you want a different look or additional fields.

// src/services/weekly-analytics.js#151 

    const slackList = report.map((item, index) => {
      const {
        position,
        url,
        title,
        count: { thisWeek, lastWeek },
        status,
      } = item;

      return {
        type: 'context',
        elements: [
          {
            type: 'image',
            image_url: `${reportConfig.url}/images/${status}`,
            alt_text: 'icon',
          },
          {
            type: 'mrkdwn',
            text: `${position}.  <${url}|${title}> | *\`${`x${thisWeek}`}\`* / x${lastWeek}`,
          },
        ],
      };
    });

Setting Up the Google Cloud Side

Before the Action can run, you need to complete setup in Google Cloud, Google Analytics, Slack, and GitHub. Start with a new Google Cloud project.

In the Google Cloud console, open the project dropdown at the top and choose Select a project. In the modal, click NEW PROJECT and give it a name; the example uses smashing-weekly-analytics. Click CREATE.

Google Cloud console with the highlighted dropdown menu Select a project and a New Project button
(Large preview)
Google Cloud console with the highlighted project name
(Large preview)

Next, enable the Google Analytics Data API. From the sidebar, go to APIs & Services > Enable APIs & services, then click + ENABLE APIS & SERVICES. Search for “Google analytics data API,” select it, and click ENABLE.

Google Cloud console with the highlighted APIs & Services
(Large preview)
Google Cloud console with the highlighted Google analytics data API
(Large preview)

Creating Service Account Credentials

With the API enabled, create credentials by clicking CREATE CREDENTIALS and choosing a Service account. This lets an application authenticate with the Google Analytics Data API using the credentials you’ll generate.

Google Cloud console with the highlighted CREATE CREDENTIALS button
(Large preview)

On the credential type screen, select Google Analytics Data API from the dropdown and choose Application data, then click NEXT.

Google Cloud console with the highlighted Service Account Credentials Type
(Large preview)

Give the service account a name, ID, and optional description. The example uses smashing-weekly-analytics for both name and ID. Click CREATE AND CONTINUE.

Google Cloud console with the highlighted Service Account Details
(Large preview)

On the next screen, set the Role to Owner and click CONTINUE. The final step can be left blank; click DONE.

Google Cloud console with the highlighted Service Accounts
(Large preview)
Google Cloud console with the highlighted button Done in Service Accounts
(Large preview)

Downloading the Key File

Navigate to Service Accounts from the left-hand menu, open the “more dots” menu for your account, and select Manage keys. Go to the KEYS tab, click ADD KEY, and choose Create new key. Select JSON as the key type and click CREATE to download the credentials file.

Google Cloud console with the highlighted Service Accounts in the navigation
(Large preview)
Google Cloud console with the highlighted KEYS tab
(Large preview)
Google Cloud console with the highlighted JSON as the key type
(Large preview)

The downloaded .json file contains the credentials the app will use to authenticate.

A screenshot of .json file in a code editor
(Large preview)

Converting Credentials for Environment Variables

These credentials can’t be assigned directly as an object in an .env file. The entire JSON file needs to be converted to a base64 string first. Run the following command from the terminal, replacing name-of-creds-file.json with your actual file name:

cat name-of-creds-file.json | base64

If you’ve cloned the repository and followed the README’s getting-started steps, add the base64 output to the GOOGLE_APPLICATION_CREDENTIALS_BASE64 variable in your .env file. Wrap the string in double quotation marks.

GOOGLE_APPLICATION_CREDENTIALS_BASE64="abc123"

That finishes the Google Cloud configuration. The next steps involve adding the service account email to your Google Analytics property and locating your Property ID.

Wiring Up Your Google Analytics Property

Before your service account can query data, it needs permission inside Google Analytics itself. Start by locating your Property ID: open your Google Analytics account, confirm you're on the correct property, click the admin cog in the bottom left, and select Property details.

A screenshot of the Google Analytics account with the highlighted Property details
(Large preview)

The PROPERTY ID appears in the top right corner. If you've cloned the repo and followed the README's getting-started steps, drop this value into the GA4_PROPERTY_ID variable in your .env file.

A screenshot of the Google Analytics account with the highlighted PROPERTY ID
(Large preview)

Granting Access to the Service Account

Next, open the Google application credential .json file you downloaded earlier and copy the client_email address. It will look something like smashing-weekly-analytics@smashing-weekly-analytics.iam.gserviceaccount.com.

In Google Analytics, go to Property access management, click the + in the top right, and choose Add users. Paste the client_email into the Email addresses field, untick Notify new users by email, assign the Viewer role under Direct roles and data restrictions, and click Add.

A screenshot of the Google Analytics account with the highlighted Property access management
(Large preview)
A screenshot of the Google Analytics account on how to add users
(Large preview)

That's all the Google Analytics setup required. Your application now has API access via the service account credentials.

Creating the Slack Destination

You'll post the report to a dedicated Slack channel through an incoming webhook. First, create a new channel in your workspace — this example uses #weekly-analytics-report.

Building the Slack App

Go to the Slack API dashboard and click Create an App.

A screenshot of the slack api dashboard
(Large preview)

Choose From an app manifest, then select your workspace and click Next.

A screenshot of the slack api dashboard
(Large preview)
A screenshot of the slack api dashboard with the selected Slack workspace
(Large preview)

Give the app a name (e.g., Weekly Analytics Report) and click Next. On the confirmation screen, just click Done.

A screenshot of the slack api dashboard with the highlighted name of the app
(Large preview)

Setting Up the Webhook

From the left-hand navigation, open Incoming Webhooks, toggle the switch to On, and click Add New Webhook to Workspace.

A screenshot with the highlighted Incoming Webhooks
(Large preview)

Pick the workspace and the channel where messages should appear, then click Allow. You'll now see the webhook with a copy button — copy the Webhook URL and, if you've already cloned the repo, paste it into the SLACK_WEBHOOK_URL variable in your .env file.

A screenshot with the selected Slack workspace and a channel
(Large preview)
(Large preview)

Polishing the App

Under Basic Information, you can add an icon and description for the app. Click Save Changes when finished. You should now see the app listed in your Slack workspace.

Slack app configuration with the basic information tab
(Large preview)
A screenshot from Slack with the highlighted Weekly Analytics report
(Large preview)

Storing Secrets in GitHub

Open your repository's Settings tab, select Secrets and variables, then Actions. Add the three variables from your .env file as Repository secrets. One note on the base64 string: don't include the surrounding double quotes when you paste it.

A screenshot of a GitHub repository
(Large preview)

Testing the Workflow

Head to the Actions tab, pick the Weekly Analytics Report job, and click Run workflow.

A screenshot of a GitHub repository with a Weekly Analytics Report
(Large preview)

If everything is configured correctly, Slack will show a neatly formatted list of your top ten page views.

A weekly analytics report with top ten page views
(Large preview)

Done

That's it: a fully automated Google Analytics digest delivered straight to Slack. In teams where analytics access is restricted, this kind of routine sharing gives everyone — not just a few stakeholders — visibility into site performance without extra manual effort.

Smashing Editorial