Stitchflow
Google Analytics logo

Google Analytics User Management API Guide

API workflow

How to automate user lifecycle operations through APIs with caveats that matter in production.

UpdatedMar 11, 2026

Summary and recommendation

The Google Analytics Admin API (v1beta) manages GA4 user access through the `accessBindings` resource, replacing the deprecated v1alpha `userLinks` endpoints. Authentication requires OAuth 2.0; service accounts are supported for server-to-server flows but must themselves be granted a GA4 role (e.g., Administrator) at the target account or property before they can manage other users' bindings.

The minimum required scope for write operations is `https://www.googleapis.com/auth/analytics.manage.users`. Read-only audits can use `analytics.manage.users.readonly`. Account-level and property-level bindings are entirely separate resources - there is no unified endpoint that returns all bindings across both levels in a single call.

This API is a natural integration target for identity graph construction: by paginating `accessBindings` across all accounts and properties, you can build a complete map of which Google identities hold which roles at which GA4 resource level, then reconcile that against your IdP's source of truth.

API quick reference

Has user APIYes
Auth methodOAuth 2.0
Base URLOfficial docs
SCIM availableNo
SCIM plan requiredN/A - GA4 does not expose a SCIM endpoint. SCIM provisioning for Google accounts is handled at the Google Cloud Identity / Google Workspace level, not within GA4 directly.

Authentication

Auth method: OAuth 2.0

Setup steps

  1. Create a project in Google Cloud Console (console.cloud.google.com).
  2. Enable the 'Google Analytics Admin API' for the project.
  3. Create OAuth 2.0 credentials (Web, Desktop, or Service Account depending on use case).
  4. For service accounts: grant the service account a GA4 role (e.g., Editor or Admin) at the account or property level in GA4 UI or via API.
  5. Request the appropriate OAuth scopes during the authorization flow.
  6. Exchange authorization code for access token and refresh token (OAuth 2.0 Authorization Code flow) or use service account JWT for server-to-server.

Required scopes

Scope Description Required for
https://www.googleapis.com/auth/analytics.manage.users Read and write GA4 user access bindings (create, update, delete users). Creating, updating, and deleting accessBindings
https://www.googleapis.com/auth/analytics.manage.users.readonly Read-only access to GA4 user access bindings. Listing and getting accessBindings
https://www.googleapis.com/auth/analytics.readonly Read-only access to GA4 configuration data including account/property metadata. Reading account and property metadata
https://www.googleapis.com/auth/analytics.edit Read and write GA4 configuration data. Editing account and property settings

User object / data model

Field Type Description On create On update Notes
name string Resource name of the access binding, e.g. accounts/123/accessBindings/456 server-assigned immutable Used as identifier in GET/PATCH/DELETE
user string Email address of the user being granted access. required immutable Must be a valid Google Account email. Mutually exclusive with 'groupEmail'.
roles array List of GA4 predefined roles assigned to the user. required updatable Valid values: predefinedRoles/viewer, predefinedRoles/analyst, predefinedRoles/editor, predefinedRoles/marketer, predefinedRoles/admin

Core endpoints

List access bindings (users) on an account

  • Method: GET
  • URL: https://analyticsadmin.googleapis.com/v1beta/accounts/{account}/accessBindings
  • Watch out for: Returns only direct account-level bindings; property-level bindings must be queried separately per property.

Request example

GET /v1beta/accounts/123456/accessBindings?pageSize=200
Authorization: Bearer {token}

Response example

{
  "accessBindings": [
    {
      "name": "accounts/123456/accessBindings/789",
      "user": "user@example.com",
      "roles": ["predefinedRoles/viewer"]
    }
  ],
  "nextPageToken": "abc123"
}

Get a single access binding on an account

  • Method: GET
  • URL: https://analyticsadmin.googleapis.com/v1beta/accounts/{account}/accessBindings/{accessBinding}
  • Watch out for: Requires the exact resource name; no lookup by email directly.

Request example

GET /v1beta/accounts/123456/accessBindings/789
Authorization: Bearer {token}

Response example

{
  "name": "accounts/123456/accessBindings/789",
  "user": "user@example.com",
  "roles": ["predefinedRoles/editor"]
}

Create access binding (add user) on an account

  • Method: POST
  • URL: https://analyticsadmin.googleapis.com/v1beta/accounts/{account}/accessBindings
  • Watch out for: User must have a Google Account. Adding at account level does not automatically grant property-level access unless inherited.

Request example

POST /v1beta/accounts/123456/accessBindings
Authorization: Bearer {token}
{
  "user": "newuser@example.com",
  "roles": ["predefinedRoles/viewer"]
}

Response example

{
  "name": "accounts/123456/accessBindings/999",
  "user": "newuser@example.com",
  "roles": ["predefinedRoles/viewer"]
}

Update access binding (change roles) on an account

  • Method: PATCH
  • URL: https://analyticsadmin.googleapis.com/v1beta/accounts/{account}/accessBindings/{accessBinding}
  • Watch out for: Full roles array must be provided; partial updates replace the entire roles list.

Request example

PATCH /v1beta/accounts/123456/accessBindings/999
Authorization: Bearer {token}
{
  "name": "accounts/123456/accessBindings/999",
  "roles": ["predefinedRoles/editor"]
}

Response example

{
  "name": "accounts/123456/accessBindings/999",
  "user": "newuser@example.com",
  "roles": ["predefinedRoles/editor"]
}

Delete access binding (remove user) from an account

  • Method: DELETE
  • URL: https://analyticsadmin.googleapis.com/v1beta/accounts/{account}/accessBindings/{accessBinding}
  • Watch out for: Returns empty body on success (HTTP 200). Does not remove property-level bindings for the same user.

Request example

DELETE /v1beta/accounts/123456/accessBindings/999
Authorization: Bearer {token}

Response example

{}

Batch create access bindings on an account

  • Method: POST
  • URL: https://analyticsadmin.googleapis.com/v1beta/accounts/{account}/accessBindings:batchCreate
  • Watch out for: Max 1000 bindings per batch call. All requests in a batch must reference the same parent account.

Request example

POST /v1beta/accounts/123456/accessBindings:batchCreate
{
  "requests": [
    {"accessBinding": {"user": "a@example.com", "roles": ["predefinedRoles/viewer"]}},
    {"accessBinding": {"user": "b@example.com", "roles": ["predefinedRoles/analyst"]}}
  ]
}

Response example

{
  "accessBindings": [
    {"name": "accounts/123456/accessBindings/1001", "user": "a@example.com", "roles": ["predefinedRoles/viewer"]},
    {"name": "accounts/123456/accessBindings/1002", "user": "b@example.com", "roles": ["predefinedRoles/analyst"]}
  ]
}

List access bindings (users) on a property

  • Method: GET
  • URL: https://analyticsadmin.googleapis.com/v1beta/properties/{property}/accessBindings
  • Watch out for: Property-level bindings are independent of account-level bindings. A user can have different roles at each level.

Request example

GET /v1beta/properties/987654/accessBindings?pageSize=200
Authorization: Bearer {token}

Response example

{
  "accessBindings": [
    {
      "name": "properties/987654/accessBindings/111",
      "user": "user@example.com",
      "roles": ["predefinedRoles/analyst"]
    }
  ]
}

Batch delete access bindings on an account

  • Method: POST
  • URL: https://analyticsadmin.googleapis.com/v1beta/accounts/{account}/accessBindings:batchDelete
  • Watch out for: Returns empty body on success. All names must belong to the same parent account.

Request example

POST /v1beta/accounts/123456/accessBindings:batchDelete
{
  "names": [
    "accounts/123456/accessBindings/1001",
    "accounts/123456/accessBindings/1002"
  ]
}

Response example

{}

Rate limits, pagination, and events

  • Rate limits: Google Analytics Admin API enforces per-project and per-user quotas. Default quota is 10 queries per second (QPS) per project for most Admin API methods. Batch operations count as multiple requests.
  • Rate-limit headers: Yes
  • Retry-After header: No
  • Rate-limit notes: HTTP 429 returned on quota exhaustion. Use exponential backoff. Batch endpoints (batchCreate, batchUpdate, batchDelete) accept up to 1000 bindings per call but each binding counts toward quota. Quota increases requested via Google Cloud Console.
  • Pagination method: token
  • Default page size: 200
  • Max page size: 200
  • Pagination pointer: pageToken
Plan Limit Concurrent
GA4 Standard (Free) 10 QPS per project; 50,000 requests/day default 0
GA4 360 Higher quota available on request via Google Cloud Console quota increase 0
  • Webhooks available: No
  • Webhook notes: Google Analytics Admin API does not provide webhook or push notification support for user management events.
  • Alternative event strategy: Poll the accessBindings.list endpoint periodically to detect changes. Google Cloud Audit Logs (via Cloud Logging) can capture Admin API write operations if the GA4 account is linked to a Google Cloud project.

SCIM API status

  • SCIM available: No
  • SCIM version: Not documented
  • Plan required: N/A - GA4 does not expose a SCIM endpoint. SCIM provisioning for Google accounts is handled at the Google Cloud Identity / Google Workspace level, not within GA4 directly.
  • Endpoint: Not documented

Limitations:

  • GA4 has no native SCIM endpoint.
  • User provisioning to Google accounts can be done via Google Workspace SCIM (supported by Okta, Entra ID, etc.), but this only creates/manages the Google account, not GA4 property/account access.
  • GA4 role assignments must be managed separately via the Admin API or GA4 UI.
  • No automated sync between IdP group membership and GA4 roles.

Common scenarios

Bulk onboarding to a property uses POST /v1beta/properties/{property}/accessBindings:batchCreate with up to 1000 user objects per request. Each binding in the batch counts individually toward the 10 QPS / 50,000 requests-per-day default quota.

Batch operations are not transactional - partial failures return per-item errors while successful items are committed; callers must inspect each response item and handle retries independently.

Full access audits require two separate pagination loops: one against accounts/{account}/accessBindings and one against properties/{property}/accessBindings for each property under the account. A user can hold different roles at both levels simultaneously; account-level roles do not override property-level roles. Merging both result sets client-side is required to produce an accurate access report.

Offboarding has no single 'remove from all resources' endpoint. Each account-level and property-level binding must be located by filtering the user field client-side and deleted individually via DELETE. Full offboarding also requires revoking the underlying Google account at the Google Workspace or Cloud Identity level - the GA4 API only removes GA4 role bindings, not the Google account itself.

Bulk onboard a team to a GA4 property

  1. Authenticate with OAuth 2.0 using scope https://www.googleapis.com/auth/analytics.manage.users.
  2. Prepare a list of user emails and desired roles (e.g., predefinedRoles/analyst).
  3. POST to /v1beta/properties/{property}/accessBindings:batchCreate with up to 1000 user objects per request.
  4. Parse the response to confirm each binding was created; log any errors for retry.
  5. Optionally repeat for account-level bindings if account access is also required.

Watch out for: batchCreate is atomic per request but not transactional across requests; partial failures return errors for individual items while others succeed. Check each item in the response.

Audit all users with access to a GA4 account and its properties

  1. Authenticate with scope https://www.googleapis.com/auth/analytics.manage.users.readonly.
  2. GET /v1beta/accounts/{account}/accessBindings with pageSize=200; paginate using nextPageToken until exhausted.
  3. List all properties under the account: GET /v1beta/properties?filter=parent:accounts/{account}.
  4. For each property, GET /v1beta/properties/{property}/accessBindings and paginate.
  5. Merge account-level and property-level bindings to produce a full access report.

Watch out for: A user may appear at both account and property level with different roles. Account-level roles do not override property-level roles; both apply independently.

Remove a departed employee's access from all GA4 resources

  1. Authenticate with scope https://www.googleapis.com/auth/analytics.manage.users.
  2. List account-level bindings: GET /v1beta/accounts/{account}/accessBindings; filter results client-side for the target email.
  3. If found, DELETE /v1beta/accounts/{account}/accessBindings/{bindingName}.
  4. List all properties and for each, GET /v1beta/properties/{property}/accessBindings; filter for the target email.
  5. DELETE each matching property-level binding.
  6. Verify removal by re-listing bindings for the user's email.

Watch out for: There is no single 'remove user from all resources' endpoint. Each account and property binding must be deleted individually. Also revoke the user's Google account access at the Google Workspace/Cloud Identity level if full offboarding is required.

Why building this yourself is a trap

The roles array in a PATCH (update) request replaces the entire roles list - there is no partial update or append operation. Sending an incomplete roles array silently removes any roles not included in the payload.

The user field (email address) is immutable after a binding is created. Changing a user's email requires deleting the existing binding and creating a new one; there is no update path for the email field itself.

Quota exhaustion returns HTTP 429 with no Retry-After header. Exponential backoff must be implemented manually. Quota increase requests are handled through Google Cloud Console, not the Analytics Admin API.

Webhooks are not available. There is no push notification mechanism for access change events. The only options for change detection are periodic polling of accessBindings.list or routing Google Cloud Audit Logs through Cloud Logging if the GA4 account is linked to a Google Cloud project.

GA4 Standard has no native audit log for user removal events within the GA4 UI itself.

Automate Google Analytics workflows without one-off scripts

Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.

Every app coverage, including apps without APIs
60+ app integrations plus browser automation for apps without APIs
IT graph reconciliation across apps and your IdP
Less than a week to launch, maintained as APIs and admin consoles change
SOC 2 Type II. ~2 hours of your team's time

UpdatedMar 11, 2026

* Details sourced from official product documentation and admin references.

Keep exploring

Related apps

Abnormal Security logo

Abnormal Security

API Only
AutomationAPI only
Last updatedMar 2026

Abnormal Security is an enterprise email security platform focused on detecting and investigating threats such as phishing, account takeover (ATO), and vendor email compromise. It does not support SCIM provisioning, which means every app in your stack

ActiveCampaign logo

ActiveCampaign

API Only
AutomationAPI only
Last updatedFeb 2026

ActiveCampaign uses a group-based permission model: every user belongs to exactly one group, and all feature-area access (Contacts, Campaigns, Automations, Deals, Reports, Templates) is configured at the group level, not per individual. The default Adm

ADP logo

ADP

API Only
AutomationAPI only
Last updatedFeb 2026

ADP Workforce Now is a mid-market to enterprise HCM platform that serves as the HR source of record for employee data — payroll, benefits, time, and talent. User access is governed by a hybrid permission model: predefined security roles (Security Maste