Part 1: Google Workspace Data Ingestion
Set up a Google Cloud service account with domain-wide delegation so ConfigView can pull your Google Workspace data into the dashboard. ConfigView reads Workspace through the Admin SDK and a few related Admin APIs. A single service account, authorized once in your Workspace Admin Console, impersonates an admin and reads users, groups, org units, roles, devices, audit logs, and mailbox settings — all read-only. You’ll end up with two things in ConfigView: a secretGOOGLE_ADMIN_EMAIL (the admin to impersonate) and the service-account key file, uploaded as google_admin.json. The key is not a Secret Manager secret — like Google Cloud, it’s uploaded as a JSON file and referenced directly by the scripts.
Running more than one Google Workspace? Each instance gets its own JSON file and admin-email secret, suffixed by number: the first instance usesgoogle_admin.json+GOOGLE_ADMIN_EMAIL, the second usesgoogle_admin_2.json+GOOGLE_ADMIN_EMAIL_2, and so on. The steps below cover the first instance; for a second instance, just append_2to the filename and the secret name.
Step 1: Create a Google Cloud project
The service account lives in a Google Cloud project. Any project works; API calls are quoted against it.- Go to the Google Cloud Console.
- Click the project dropdown (top-left) → New Project.
- Name it
configview-integration, choose your Organization, and click Create. - Make sure the new project is selected in the dropdown before continuing.
Step 2: Enable the required APIs
On that project, enable the APIs ConfigView calls. On a fresh project these are off by default. Click each link (with your project selected) and press Enable, or run the one-liner below.Note. The Admin SDK exposes both the Directory (directory_v1) and Reports (reports_v1) APIs under the singleadmin.googleapis.comservice — enabling Admin SDK API covers both. You only need the others for the specific endpoints listed above; skip an API and just leave its scripts disabled.
Propagation. Right after enabling, you may see intermittent SERVICE_DISABLED 403s for ~10–15 minutes while the change rolls out. Wait it out before assuming a misconfiguration.
Step 3: Create the service account
- Open IAM & Admin → Service Accounts with your
configview-integrationproject selected. - Click Create Service Account.
- Name:
configview(the email auto-fills, e.g.configview@configview-integration.iam.gserviceaccount.com). - Click Create and Continue.
- Skip the optional “Grant this service account access to project” and “Grant users access” steps — this integration needs no project IAM roles; all access comes from domain-wide delegation in Step 5.
- Click Done.
Step 4: Create and download the JSON key
- From the service account list, click your
configviewservice account. - Open the Keys tab → Add Key → Create new key → JSON → Create.
- The JSON key file downloads automatically. Keep it handy — you’ll upload it to ConfigView in Step 6.
- While you’re here, open the Details tab and copy the Unique ID (the numeric Client ID) — you’ll need it for delegation in Step 5.
Step 5: Authorize domain-wide delegation
This is what lets the service account read your Workspace data. You authorize its Client ID against a fixed list of read-only scopes in the Admin Console.- Sign in to the Google Workspace Admin Console as a super admin.
- Go to Security → Access and data control → API controls → Manage Domain Wide Delegation.
- Click Add new and paste:
- Client ID: the numeric Unique ID from Step 4.4
- OAuth scopes: the comma-separated list below
- Click Authorize.
Seat utilization usesapps.licensing+admin.reports.usage.readonly.apps.licensinganswers “how many seats are assigned” (one row per user per SKU). The purchased count comes from the Reports API customer usage report underadmin.reports.usage.readonly, which exposesaccounts:<edition>_total_licensesalongside_used_licenses.apps.orderdoes not work for this and you can skip it. The Reseller API has the same numbers, but it authenticates the reseller — a customer super admin gets a flat403 Forbiddenon every method even with the scope granted, and buying through a reseller does not change that. It is listed above only because the scope name suggests otherwise. Noteadmin.reports.usage.readonlyis a separate scope fromadmin.reports.audit.readonly— granting the audit one does not grant this one, and vice versa.
Adding scopes later. If you enable a new script that needs a scope you didn’t authorize, re-open Manage Domain Wide Delegation, click your client row, and add the missing scope. Delegation changes take a minute or two to propagate.
Trim if you like. You only need the scopes for the scripts you’ll actually run. The list above is the full set; dropping a scope just disables its endpoints (and its health check).
Step 6: Add the secret and upload the JSON key
6a. Add the admin-email secret.- Go to your ConfigView dashboard:
https://{companyname}.configview.com/admin/secret/ - Click Add Secret and create:
GOOGLE_ADMIN_EMAIL: a super-admin email address for the service account to impersonate (e.g.admin@yourdomain.com)
- Click Save.
- Go to the JSON upload board:
https://{companyname}.configview.com/admin/external/ - Rename the key file you downloaded in Step 4 to
google_admin.jsonbefore uploading — the scripts resolve it by that exact name. - Upload it. It’s saved to
<project_root>/json/google_admin.jsonon the satellite (the same directory that already holdssecret-manager.json). It is not a Secret Manager secret — the key is referenced directly by all Google Workspace scripts.
Second instance. For a second Google Workspace, name the secretGOOGLE_ADMIN_EMAIL_2and upload the key asgoogle_admin_2.json(instance 3 →_3, and so on).
Step 7: Enable the Google Workspace app in ConfigView
- Go to:
https://{companyname}.configview.com/admin/cron/ - You should see Google Workspace in the list of available apps.
- Select the scripts you want to run.
- Click Save.
Step 8: Verify
- Go to:
https://{companyname}.configview.com/admin/status/ - Run the Google Workspace health check.
- All checks should pass.
unauthorized_client/Client is unauthorized to retrieve access tokens— the Client ID isn’t authorized, or a required scope is missing. Re-do Step 5 and confirm the Unique ID matches. Note this failure happens when the token is issued, before any API call, so a script hitting it produces no 403 and no error rows — its table simply stays empty. Scopes are authorized individually: the rest of the integration can be working perfectly while one un-granted scope leaves its own endpoints silently at zero. If one table is empty and the others are fine, suspect its scope first.access_denied/403on a specific endpoint — the matching scope wasn’t authorized, orGOOGLE_ADMIN_EMAILisn’t a super admin.SERVICE_DISABLED— the API for that endpoint isn’t enabled on the project. Re-check Step 2.FileNotFoundError/google_admin.json— the key file wasn’t uploaded, or was uploaded under the wrong name. Re-do Step 6b and confirm it’s named exactlygoogle_admin.json(orgoogle_admin_2.jsonfor a second instance).- Otherwise verify your
GOOGLE_ADMIN_EMAILsecret and the uploaded JSON key are both in place.
Data Tables
Once the scripts run, the corresponding Google Workspace tables will be created in your database. All tables include arun_at column for historical tracking.
The License Assignments script (google_get_licenses → google_licenses) records one row per user per SKU across Google Workspace, Gemini, Vault, Voice and AppSheet, so you can see how many seats of each SKU are actually assigned. It stores product_id and sku_id verbatim — the friendly product_name / sku_name come from a static catalog and are NULL for any SKU Google has added since, so filter and join on the ids, never the names. This is the assigned side.
The License Totals script (google_get_license_totals → google_license_totals) supplies the purchased side, from the Reports API customer usage report: one row per edition per day with total_licenses and used_licenses. Together they answer “are we at our seat limit” — the curated query google.license_utilization renders it directly as purchased / used / available / percent.
Two things to know about it. The report is compiled daily and lags two to three days, so report_date is never today; asking for a newer date returns a 400 naming the newest one that exists, which the collector follows automatically. And its edition values are Google’s legacy gsuite_* names, which do not match the modern SKU names in google_licenses — compare the two tables’ numbers, don’t join them on the label.
The Admin Audit Log script (google_admin_audit) pulls the Google Admin Console activity feed from the Reports API — user, group, role, and security-setting changes over a rolling 180-day window. Curated queries built on it (recent admin actions, role & privilege changes, security-setting changes, and per-user investigation lookups) ship in the saved-query catalog under the Audit category.